27

I have two list, one reference and one input list

Ref = [3, 2, 1, 12, 11, 10, 9, 8, 7, 6, 5, 4]
Input = [9, 5, 2, 3, 10, 4, 11, 8]

I want to sort Input list, in the order as that of Ref. If some element is missing in Input list, it can skip and go for the other element.

Hence sorted Input list, based on Ref list will be like this

Sorted_Input = [3, 2, 11, 10, 9, 8, 5, 4]
double-beep
  • 5,031
  • 17
  • 33
  • 41
Hardik Gupta
  • 4,700
  • 9
  • 41
  • 83
  • 2
    why not loop over reference list and check if items are in input list? ```new = [val for val in Ref if val in Input]``` – Isdj Dec 25 '19 at 16:20
  • @Georgy - the above question only keeps the elements as present in the other list, however I was looking for sorting as well, this is why it's a different question – Hardik Gupta Dec 26 '19 at 11:19
  • 1
    There is no sorting here but just filtering. Please, see the accepted answer in the duplicate target. It is the same as the accepted answer here, and it will produce the same result as you want. – Georgy Dec 26 '19 at 11:22
  • @Georgy - now I agree with you. – Hardik Gupta Dec 26 '19 at 11:23

4 Answers4

25

I think this answers your question:

>>> [x for x in Ref if x in Input]
>>> [3, 2, 11, 10, 9, 8, 5, 4]

Hope it helps.

UPDATE: Making Input a set for faster access:

>>> Input_Set = set(Input)
>>> [x for x in Ref if x in Input_Set]
[3, 2, 11, 10, 9, 8, 5, 4]
dcg
  • 4,187
  • 1
  • 18
  • 32
  • 3
    This probably doesn't matter to the questioner since they accepted the answer, but beware this deduplicates `Input` as well as sorting it. For example, `[1, 1, 1, 3]` goes to `[3, 1]`. – Steve Jessop Dec 26 '19 at 02:00
  • @SteveJessop I know, at some point the OP said `Input`'s elements were all different. Now I'm confused, I thought this answer had several comments on that. – dcg Dec 26 '19 at 02:05
  • @SteveJessop - my input and ref will never have duplicates, so yes this solution will always be valid – Hardik Gupta Dec 29 '19 at 02:14
8

Another approach in addition to dcg's answer would be as follows:

Ref = [3, 2, 1, 12, 11, 10, 9, 8, 7, 6, 5, 4]
Input = [9, 5, 2, 3, 10, 4, 11, 8]

ref = set(Ref)
inp = set(Input)

sorted_list = sorted(ref.intersection(inp), key = Ref.index)

This outputs to:

[3, 2, 11, 10, 9, 8, 5, 4]

Here you convert the lists into sets, find their intersection, and sort them. The set is sorted based on the 'Ref' list's indexing.

A. Dhakal
  • 179
  • 6
8

You can use the sorted method:

# keep in a dict the index for each value from Ref
ref  = {val: i for i, val in enumerate(Ref)}
# sort by the index value from Ref for each number from Input 
sorted(Input, key=ref.get)

output:

[3, 2, 11, 10, 9, 8, 5, 4]
kederrac
  • 16,819
  • 6
  • 32
  • 55
6

Here's the naive approach:

sorted(Input, key=Ref.index)

Or in-place:

Input.sort(key=Ref.index)

Either way it's just one line.

Although I think it's slow -- O(n*m) where n and m are the lengths of Input and Ref. @rusu_ro1's solution uses a similar method but seems to be O(n+m).

wjandrea
  • 28,235
  • 9
  • 60
  • 81
  • 2
    Technically I guess any other solution is premature optimization unless we know the inputs will be large enough that the speed matters. – JollyJoker Dec 26 '19 at 13:19
  • 1
    @JollyJoker very true, thanks for mentioning – wjandrea Dec 26 '19 at 13:54
  • 2
    @JollyJoker And without knowing exactly what kind of elements are in the real list (duplicates/unique elements, hashable or not, etc). – Graipher Dec 26 '19 at 13:57