1

I want to sort a list in a way that the elements (sublists) which have a certain string (of my choosing) come first. I'd like to do this with the key parameter in Python's sort() method.

For example, if I have

Input

l1 = [["hello", 1, 65, 331],["goodbye", 653, 43, 9], ["example", 22, 123, 92]]

I'd like to use l1.sort() to sort the list in a way that, given "example" as the parameter, sorts the list like this:

Output

[["example", 22, 123, 92], ["hello", 1, 65, 331], ["goodbye", 653, 43, 9]].

Is this possible?

zeval
  • 147
  • 1
  • 10
  • Does this answer your question? [python: sort a list of lists by an item in the sublist](https://stackoverflow.com/questions/18142090/python-sort-a-list-of-lists-by-an-item-in-the-sublist) – Sayse Dec 11 '19 at 10:29
  • No, sorry, that's just lexicographic/alphanumeric ordering. – zeval Dec 11 '19 at 10:31
  • Can you give more explanations about the expected output? – Silveris Dec 11 '19 at 10:31
  • 1
    If the string is they key for sorting, why is `h` before `g`? – yatu Dec 11 '19 at 10:32
  • The order of the sublists that don't contain "example" in them is completely irrelevant, what matters is that the first element(s) contain the given string. – zeval Dec 11 '19 at 10:33
  • `a certain string (of my choosing)`, could you give an example?? – yatu Dec 11 '19 at 10:33
  • @Hasake - The accepted answer might be but the other answers show other ways, you should show what you've tried, aside from that, your `l1` isn't actually a valid list – Sayse Dec 11 '19 at 10:33
  • 2
    `l1.sort(key=lambda sub: (sub[0]!='example', sub))` – user2390182 Dec 11 '19 at 10:34
  • @schwobaseggl You are a life-saver. How can I ever repay you? That's exactly what I'm looking for!!! – zeval Dec 11 '19 at 10:37
  • @Sayse Thanks for the input. I checked it out, you were right, but I still didn't know exactly how to tune it to work in my case. Why do you say it isn't a valid list? – zeval Dec 11 '19 at 10:38
  • @Hasake *Why do you say it isn't a valid list?* - the code you've posted has a superfluous `[` at the start of the list containing "goodbye" – Jon Clements Dec 11 '19 at 11:13
  • @JonClements typo, my bad, thanks. – zeval Dec 11 '19 at 14:44

3 Answers3

3

Say you want goodbye to come first, you could do:

l1 = [["hello", 1, 65, 331],["goodbye", 653, 43, 9], ["example", 22, 123, 92]]

s = 'goodbye'
sorted(l1, key=lambda x: x[0]!=s)
# [['goodbye', 653, 43, 9], ['hello', 1, 65, 331], ['example', 22, 123, 92]]

For a detailed exaplanation on how the above works, check this other answer

yatu
  • 86,083
  • 12
  • 84
  • 139
  • or `s not in x` do don't rely on location inside the sublist – Tomerikoo Dec 11 '19 at 10:37
  • 1
    Well from the example it seems that the position where the string is is known. If that is the case this will be much more efficient @Tomerikoo – yatu Dec 11 '19 at 10:38
  • 2
    @yatu, this is was exactly what I wanted. Given that the string position is known this really is the best way. Thank you!! – zeval Dec 11 '19 at 10:41
  • 1
    `l1.sort(key=lambda x: not any([i in x for i in ["goodbye", "example"]]))` – mrtpk Dec 11 '19 at 10:44
  • 1
    @tpk thank you for the input. However, I was looking forward to using this technique in a list of lists with far more options than just these 3. Given that, it'd be far too much of a hassle to negate all of them, but at least I learned something new. :) – zeval Dec 11 '19 at 14:30
2

you can use a lambda expression to check if the keyword is in the sublist, this will return a boolean truth value for each expression in which False will be ordered before True, so we also apply reverse so that those that were True come first. it will maintain the order of the sub list after ordering by True and False. So those sublists with the same truth value will stay in the order they were in.

l1 = [["hello", 1, 65, 331],["goodbye", 653, 43, 9], ["example", 22, 123, 92]]
keyword = "example"
print(l1)
l1.sort(key=lambda sublist: keyword in sublist, reverse=True)
print(l1)

OUTPUT

[['hello', 1, 65, 331], ['goodbye', 653, 43, 9], ['example', 22, 123, 92]]
[['example', 22, 123, 92], ['hello', 1, 65, 331], ['goodbye', 653, 43, 9]]
Chris Doyle
  • 10,703
  • 2
  • 23
  • 42
  • Thank you! How did you get to this? This was my first approach, I tried for a long while to use boolean values inside lambda which was the more logical approach for me as well. However, I kept getting an error telling me something like "bool not allowed in lambda" or whatnot, so I discarded it. Turns out it works so thank you. – zeval Dec 11 '19 at 14:28
1

Here's the code. Excuse me for putting it this long but it serves the purpose :)

import operator
def sortfunction(parameter,list):
    tmplist1 = []
    tmplist2 = []
    for elem in list:
        if elem[0] == parameter:
            tmplist1 = elem
        else:
            tmplist2.append(elem)
    sorted_temp = sorted(tmplist2, key=operator.itemgetter(1),reverse=True)
    final_list = tmplist1 + sorted_temp
    return final_list

#Call the function:
sortfunction("example",l1)

Output:

['example', 22, 123, 92, ['goodbye', 653, 43, 9], ['hello', 1, 65, 331]]
Karthick Mohanraj
  • 1,565
  • 2
  • 13
  • 28
  • 1
    Thank you! No worries regarding length. Even though I was looking for a one-liner, this show's me how to actually use `operator.itemgetter()` properly, which is great! But at the core of the question, yes, I could definitely get around by using this! Again, thanks for the input. – zeval Dec 11 '19 at 14:26
  • @Hasake Cheers! – Karthick Mohanraj Dec 12 '19 at 06:12