Предположим, что у меня есть набор пар данных, где индекс 0 - это значение, а индекс 1 - это тип:
input = [
('11013331', 'KAT'),
('9085267', 'NOT'),
('5238761', 'ETH'),
('5349618', 'ETH'),
('11788544', 'NOT'),
('962142', 'ETH'),
('7795297', 'ETH'),
('7341464', 'ETH'),
('9843236', 'KAT'),
('5594916', 'ETH'),
('1550003', 'ETH')
]
Я хочу сгруппировать их по типу (по 1-й индексированной строке) как таковые:
result = [
{
type:'KAT',
items: ['11013331', '9843236']
},
{
type:'NOT',
items: ['9085267', '11788544']
},
{
type:'ETH',
items: ['5238761', '962142', '7795297', '7341464', '5594916', '1550003']
}
]
Как я могу добиться этого эффективным способом?
[('11013331', 'red', 'KAT'), ('9085267', 'blue' 'KAT')]
где последний элемент кортежа является ключевым, а первые два - значением. Результат должен быть таким: result = [{type: 'KAT', items: [('11013331', red), ('9085267', blue)]}]from operator import itemgetter
d= {}; for k,v in input: d.setdefault(k, []).append(v)
Встроенный
itertools
модуль Python на самом деле имеетgroupby
функцию, но для этого элементы, которые нужно сгруппировать, должны быть сначала отсортированы таким образом, чтобы элементы, которые нужно сгруппировать, были смежными в списке:Теперь ввод выглядит так:
groupby
возвращает последовательность из двух кортежей формы(key, values_iterator)
. Мы хотим превратить это в список dicts, где 'type' является ключом, а 'items' - это список 0-х элементов кортежей, возвращаемых values_iterator. Как это:Теперь
result
содержит желаемый диктат, как указано в вашем вопросе.Однако вы можете подумать о том, чтобы просто сделать из этого один диктант с ключом по типу и каждым значением, содержащим список значений. В вашей текущей форме, чтобы найти значения для определенного типа, вам придется перебирать список, чтобы найти dict, содержащий соответствующий ключ type, а затем получить из него элемент items. Если вы используете одиночный dict вместо списка dict из 1 элемента, вы можете найти элементы для определенного типа с помощью поиска с одним ключом в главном dict. При использовании
groupby
это будет выглядеть так:result
теперь содержит этот dict (он похож на промежуточныйres
defaultdict в ответе @ KennyTM):(Если вы хотите сократить это до однострочника, вы можете:
или используя новомодную форму понимания слов:
источник
Еще мне понравилась простая группировка панд . это мощный, простой и наиболее подходящий для большого набора данных
result = pandas.DataFrame(input).groupby(1).groups
источник
Этот ответ аналогичен ответу @ PaulMcG, но не требует сортировки ввода.
Для тех, кто занимается функциональным программированием,
groupBy
может быть записано в одну строку (не включая импорт!), И, в отличие отitertools.groupby
этого, не требует сортировки ввода:(Причина
... or grp
вlambda
том , что для этогоreduce()
на работу, тоlambda
должен возвращать свой первый аргумент, потому чтоlist.append()
всегда возвращает всегда будет возвращать . Т.е. это хак , чтобы обойти ограничение питона , что лямбда может оценивать только одно выражение.)None
or
grp
Это возвращает dict, ключи которого находятся путем вычисления данной функции, а значениями являются список исходных элементов в исходном порядке. Для примера OP вызов this as
groupBy(lambda pair: pair[1], input)
вернет этот dict:И в соответствии с ответом @ PaulMcG запрошенный формат OP можно найти, обернув его в понимание списка. Итак, это сделает это:
источник
Следующая функция быстро ( без сортировки ) группирует кортежи любой длины по ключу с любым индексом:
В случае вашего вопроса индекс ключа, который вы хотите сгруппировать, равен 1, поэтому:
дает
что не совсем то, что вы просили, но вполне может удовлетворить ваши потребности.
источник
источник