Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to sort a list of sub-lists by the contents of sub-lists, where sub-lists contain strings and booleans?

I have a list containing thousands of sub-lists. Each of these sub-lists contain a combination of mixed strings and boolean values, for example:

lst1 = [['k', 'b', False], ['k', 'a', True], ['a', 'a', 'a'], ['a', 'b', 'a'], ['a', 'a' , False], ...]

I want to sort this list in accordance with the contents of the sub-lists, like:

lst2 = [['a', 'a', 'a'], ['a', 'a' , False], ['a', 'b', 'a'], ['k', 'a', True], ['k', 'b', False], ...]

I've tried sorting it like this:

lst2 = sorted([list(sorted(x)) for x in lst1])
print(lst2)

This doesn't work because of the combination of boolean values with strings in some fields, so I get TypeError: '<' not supported between instances of 'bool' and 'str'.

I've also tried a brute force method, creating every possible combination and then checking them to see if which are in the first list:

col1 = ['a', 'b', 'c', d, e, f, g, h, i, j, k, ..., True, False]
col2 = ['a', 'b', 'c', d, e, f, g, h, i, j, k, ..., True, False]
col3 = ['a', 'b', 'c', d, e, f, g, h, i, j, k, ..., True, False]
lst2 = list()
for t1 in col1:
    for t2 in col2:
        for t3 in col3:
            test_sublist = [t1, t2, t3]
            if test_sublist in lst1:
            lst2.append(test_sublist)

This way works well enough, because I'm able to automatically create sorted lists for each column, col 1, col 2, and col 3, but it takes way too long to run (more than 3 days).

Is there a better solution for sorting mixed string/boolean lists like these?

like image 702
AdeDoyle Avatar asked Jan 17 '20 15:01

AdeDoyle


1 Answers

These handle any lengths, not just length 3. And bools in any places, not just the last column. For keying, they turn each element of each sublist into a tuple.


Solution 1:

sorted(lst1, key=lambda s: [(e is False, e is True, e) for e in s])

Turns strings into (False, False, thestring) so they come first.
Turns True into (False, True, True) so it comes next.
Turns False into (True, False, False) so it comes last.

Though I think of it the reverse way, as in "First deprioritize False, then deprioritize True". The general form is key=lambda x: (shall_come_last(x), x).


Solution 2:

sorted(lst1, key=lambda s: [((e is True) + 2 * (e is False), e) for e in s])

Turns strings into (0, thestring) so they come first.
Turns True into (1, True) so it comes next.
Turns False into (2, False) so it comes last.


Solution 3:

sorted(lst1, key=lambda s: [(0, e) if isinstance(e, str) else (2 - e,) for e in s])

Turns strings into (0, thestring) so they come first.
Turns True into (1,) so it comes next.
Turns False into (2,) so it comes last.

like image 117
Kelly Bundy Avatar answered Oct 14 '22 00:10

Kelly Bundy