Как отсортировать список подсписков по содержимому подсписков, где подсписки содержат строки и логические значения? - PullRequest
7 голосов
/ 17 января 2020

У меня есть список, содержащий тысячи подсписков. Каждый из этих подсписков содержит комбинацию смешанных строк и логических значений, например:

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

Я хочу отсортировать этот список в соответствии с содержимым подсписков, например:

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

Я пытался отсортировать это так:

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

Это не работает из-за комбинации логических значений со строками в некоторых полях, поэтому я получаю TypeError: '<' not supported between instances of 'bool' and 'str'.

Я также попробовал метод грубой силы, создавая каждую возможную комбинацию и затем проверяя их, чтобы увидеть, есть ли в первом списке:

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)

Этот способ работает достаточно хорошо, потому что я Я могу автоматически создавать отсортированные списки для каждого столбца, col 1, col 2 и col 3, но это занимает слишком много времени для запуска (более 3 дней).

Есть ли лучше решение для сортировки смешанных строковых / логических списков, как эти?

Ответы [ 4 ]

3 голосов
/ 17 января 2020

Они обрабатывают любую длину, не только длину 3. И выполняются операции в любых местах, а не только в последнем столбце. Для ввода ключей они превращают каждый элемент каждого подсписка в кортеж.


Решение 1:

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

Превращает строки в (False, False, thestring), поэтому они идут первыми.
Turns True в (False, True, True), поэтому он идет следующим образом.
Превращает False в (True, False, False), чтобы он пришел последним.

Хотя я думаю об этом обратным путем, как в «Первая деприоритизация * 1016» *, затем деприоритизировать True ". Общая форма: key=lambda x: (shall_come_last(x), x).


Решение 2:

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

Превращает строки в (0, thestring), поэтому они идут первыми.
Превращает True в (1, True) так оно и идет дальше.
Превращает False в (2, False), поэтому оно приходит последним.


Решение 3:

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

Превращает строки в (0, thestring) так они приходят первыми.
Превращает True в (1,), поэтому идет следующим образом.
Превращает False в (2,), поэтому он приходит последним.

1 голос
/ 17 января 2020

Если вы не возражаете, что логические значения предшествуют строкам в отсортированном списке, pandas предложит простой интерфейс для этой задачи:

import pandas as pd
df = pd.DataFrame(lst1)
# Sort by all columns, from left to right.
df.sort_values(by=list(df.columns), inplace=True)
lst2 = df.values.tolist()

Это приведет к следующему выводу.

[['a', 'a', False],
 ['a', 'a', 'a'],
 ['a', 'b', 'a'],
 ['k', 'a', True],
 ['k', 'b', False]]

Подход хорошо обобщает None-значения и числа без изменений.


Если вам действительно нужно, чтобы логические значения отображались в конце, вы можете временно переименовать значения. (Я пропускаю inplace=True для лучшей читаемости)

df = df.replace(False, "zFalse")
df = df.replace(True, "zTrue")
df = df.sort_values(by=list(df.columns))
df = df.replace("zFalse", False)
df = df.replace("zTrue", True)
lst2 = df.values.tolist()
[['a', 'a', 'a'],
 ['a', 'a', False],
 ['a', 'b', 'a'],
 ['k', 'a', True],
 ['k', 'b', False]]

Я согласен, что это менее привлекательно, но будет работать. К сожалению, sort_values() не поддерживает аргумент ключа сортировки для управления приоритетом сортировки.

1 голос
/ 17 января 2020

Вы можете создать обработчик ключа для sorted, который дополняет элемент, если он содержит логическое значение:

lst1 = [['k', 'b', False], ['k', 'a', True], ['a', 'a' , False], ['a', 'a', 'a'], ['a', 'b', 'a']]
result = sorted(lst1, key=lambda x:(x, False) if isinstance(x[-1], str) else (x[:-1]+[x[-2]], not x[-1]))

Вывод:

[['a', 'a', 'a'], ['a', 'a', False], ['a', 'b', 'a'], ['k', 'a', True], ['k', 'b', False]]
0 голосов
/ 17 января 2020
def sort(lst):
    pad = len(max(lst, key=lambda l: len(l)))
    def ssort(lst):
        newlst = list(map(lambda item: item if isinstance(item, str) else 'Ӿ' if item == True else "ӿ", lst))
        count = 0
        for l in newlst:
            if l == "ӿ" or l == "Ӿ":
                count += 1
        count = count + pad - len(newlst)
        while(count > 0):
            newlst.insert(0, 'ӿ')
            count -= 1
        return newlst
    lst.sort(key=lambda lst: ssort(lst))

st1 = [['k', 'b', False], ['k', 'a', True], ['a', 'a', 'a'], ['a', 'b', 'a'], ['a', 'a' , False], ['a', 'a', True]]
sort(st1)
print(st1)

Вывод

[['a', 'a', 'a'], ['a', 'b', 'a'], [' a ',' a ', True], [' a ',' a ', False], [' k ',' a ', True], [' k ',' b ', False]]

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...