Aliaksei Laurynovich
Aliaksei Laurynovich

Reputation: 195

Sorting list based on order of substrings in another list

I have two lists of strings.

list_one = ["c11", "a78", "67b"]
list_two = ["a", "b", "c"]

What is the shortest way of sorting list_one using strings from list_two to get the following output?

["a78", "67b", "c11"]

Edit 1: There is a similar question Sorting list based on values from another list?, but in that question he already has the list of required indexes for resulting string, while here I have just the list of substrings.

Edit 2: Since the example of list above might be not fully representative, I add another case.

list_one is ["1.cde.png", "1.abc.png", "1.bcd.png"] list_two is ["abc", "bcd", "cde"]. The output is supposed to be [ "1.abc.png", "1.bcd.png", "1.cde.png"]

If, for example, list_one is shorter than list_two, it should still work:

list_one is ["1.cde.png", "1.abc.png"] list_two is ["abc", "bcd", "cde"] The output is supposed to be [ "1.abc.png", "1.cde.png"]

Upvotes: 4

Views: 892

Answers (4)

tobias_k
tobias_k

Reputation: 82899

Assuming that each item in list_one contains exactly one of the characters from list_two, and that you know the class of those characters, e.g. letters, you can extract those using a regex and build a dictionary mapping the characters to the element. Then, just look up the correct element for each character.

>>> list_one = ["c11", "a78", "67b"]
>>> list_two = ["a", "b", "c"]
>>> d = {re.search("[a-z]", s).group(): s for s in list_one}
>>> list(map(d.get, list_two))
['a78', '67b', 'c11']
>>> [d[c] for c in list_two]
['a78', '67b', 'c11']

Other than the other approaches posted so far, which all seem to be O(n²), this is only O(n).

Of course, the approach can be generalized to e.g. more than one character, or characters in specific positions of the first string, but it will always require some pattern and knowledge about that pattern. E.g., for your more recent example:

>>> list_one = ["1.cde.png", "1.abc.png", "1.bcd.png"]
>>> list_two = ["abc", "cde"]
>>> d = {re.search("\.(\w+)\.", s).group(1): s for s in list_one}
>>> d = {s.split(".")[1]: s for s in list_one}  # alternatively without re
>>> [d[c] for c in list_two if c in d]
['1.abc.png', '1.cde.png']

Upvotes: 1

blhsing
blhsing

Reputation: 106553

key = {next((s for s in list_one if v in s), None): i for i, v in enumerate(list_two)}
print(sorted(list_one, key=key.get))

This outputs:

['a78', '67b', 'c11']

Upvotes: 4

Sunitha
Sunitha

Reputation: 12015

>>> sorted(list_one, key=lambda x: [i for i,e in enumerate(list_two) if e in x][0])
['a78', '67b', 'c11']

Upvotes: -1

khelili miliana
khelili miliana

Reputation: 3822

Try this

list_one = ["c11", "a78", "67b"]
list_two = ["a", "b", "c"]

[x for y in list_two for x in list_one if y in x]

Output :

["a78", "67b", "c11"]

Upvotes: 3

Related Questions