Перегруппировать подсписки по первому элементу в python - PullRequest
0 голосов
/ 05 октября 2018

У меня есть вложенный список, который выглядит примерно так:

first_list = [[a, 1], [b, 3], [a, 6], [a, 2], [b, 4], [b, 5], ...]

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

new_list = [ [1, 6, 2, ...], [3, 4, 5, ...], ...]

, где все элементы, которые начинаются с перехода, входят в первый подсписок и так далее.Число различных значений a, b и т. Д. Не известно до времени выполнения, или я мог бы сделать что-то вроде:

a_list = []
b_list = []
for tag, x in first_list:
    if tag == a:
        a_list.append(x)
    elif tag == b:
        b_list.append(x)
new_list = [a_list, b_list]

Однако я пытаюсь приспособить это для произвольного числа тегов.

Возможно, я пропустил важную часть вопроса, но я должен сказать, что у меня уже есть список «тегов», то есть:

tags = [a, b, c, d, ...]

На самом деле они не являются символами, отсюда и отсутствиекавычки, но в любом случае они должны быть хэшируемыми.

Ответы [ 5 ]

0 голосов
/ 05 октября 2018

Хорошо, в python есть встроенные методы для этого, но абстрактным алгоритмическим способом мы можем сказать:

first_list = [["a", 1], ["b", 3], ["a", 6], ["a", 2], ["b", 4], ["b", 5],["c",5]]

indx_list = [x[0] for x in first_list]

new_list = [[] for x in range(len(first_list))]

for x in first_list:
    new_list[indx_list.index(x[0])] += [x[-1]]

print(new_list)
0 голосов
/ 05 октября 2018

Уменьшение будет работать для любого количества тегов.

first_list = [['a', 1], ['b', 3], ['a', 6], ['a', 2], ['b', 4], ['b', 5]]
def lambda_group(acc, val):
    tag, x = val
    if key not in acc:
        acc[key] = []
    acc[key].append(value)
    return acc
grouped_vals = reduce(lambda_group, first_list, {})
regrouped = list(grouped_vals.values())

Производит [[1, 6, 2], [3, 4, 5]]

0 голосов
/ 05 октября 2018

При использовании Python и программирования в целом вам следует избегать создания переменного числа переменных.

defaultdict

Вы можете использовать defaultdict из list объектов.Это естественным образом распространяется на произвольное количество групп без явного именования переменных.

first_list = [['a', 1], ['b', 3], ['a', 6], ['a', 2], ['b', 4], ['b', 5]]

from collections import defaultdict

dd = defaultdict(list)

for cat, num in first_list:
    dd[cat].append(num)

defaultdict(list, {'a': [1, 6, 2],
                   'b': [3, 4, 5]})

groupby

Решение defaultdict имеет сложность O ( n ),но возможно точное решение itertools.groupby, которое требует сортировки и сложности O ( n log n ):

from itertools import groupby
from operator import itemgetter

sorter = sorted(first_list, key=itemgetter(0))
grouper = groupby(sorter, key=itemgetter(0))
res = {i: list(map(itemgetter(1), j)) for i, j in grouper}

{'a': [1, 6, 2], 'b': [3, 4, 5]}

Список вывода списка

Это так же просто, как звонить list на dict.values:

res_list = list(res.values())
0 голосов
/ 05 октября 2018

Это прекрасная возможность использовать библиотеку itertools и понимание списка:

first_list = [['a', 1], ['b', 3], ['a', 6], ['a', 2], ['b', 4], ['b', 5], ...]
keyfunc = lambda x: x[0]
new_list = [[v1[1] for v1 in v] for k, v in itertools.groupby(sorted(first_list, key = keyfunc), key = keyfunc)]

Здесь я делаю группирование списка по первому значению в подсписке и вытягиваниевторое значение выключено.Обратите внимание, что список должен быть отсортирован заранее, поэтому он будет запущен в O(n log n) раз.

0 голосов
/ 05 октября 2018

Прежде всего, ваши a и b, вероятно, должны быть строками.

Вы можете сделать это, используя списочные выражения:

first_list = [["a", 1], ["b", 3], ["a", 6], ["a", 2], ["b", 4], ["b", 5]]
a_list = [x for x in first_list if x[0] == "a"]
b_list = [x for x in first_list if x[0] == "b"]
new_list = [a_list, b_list]
...