Suponha que eu tenha um conjunto de pares de dados em que o índice 0 seja o valor e o índice 1 seja o tipo:
input = [
('11013331', 'KAT'),
('9085267', 'NOT'),
('5238761', 'ETH'),
('5349618', 'ETH'),
('11788544', 'NOT'),
('962142', 'ETH'),
('7795297', 'ETH'),
('7341464', 'ETH'),
('9843236', 'KAT'),
('5594916', 'ETH'),
('1550003', 'ETH')
]
Quero agrupá-los por seu tipo (pela primeira string indexada) da seguinte forma:
result = [
{
type:'KAT',
items: ['11013331', '9843236']
},
{
type:'NOT',
items: ['9085267', '11788544']
},
{
type:'ETH',
items: ['5238761', '962142', '7795297', '7341464', '5594916', '1550003']
}
]
Como posso conseguir isso de maneira eficiente?
[('11013331', 'red', 'KAT'), ('9085267', 'blue' 'KAT')]
onde o último elemento da tupla é a chave e os dois primeiros como valor. O resultado deve ser assim: result = [{type: 'KAT', itens: [('11013331', vermelho), ('9085267', azul)])]]from operator import itemgetter
d= {}; for k,v in input: d.setdefault(k, []).append(v)
O
itertools
módulo interno do Python realmente tem umagroupby
função, mas para que os elementos a serem agrupados sejam primeiro classificados, de modo que os elementos a serem agrupados sejam contíguos na lista:Agora, a entrada se parece com:
groupby
retorna uma sequência de 2 tuplas, do formulário(key, values_iterator)
. O que queremos é transformar isso em uma lista de dictos onde o 'tipo' é a chave e 'itens' é uma lista dos 0'ésimos elementos das tuplas retornadas pelo values_iterator. Como isso:Agora
result
contém o ditado desejado, conforme indicado na sua pergunta.Você pode considerar, no entanto, criar um único ditado, digitado por tipo e cada valor contendo a lista de valores. Em seu formulário atual, para encontrar os valores para um tipo específico, você precisará percorrer a lista para encontrar o ditado que contém a chave 'type' correspondente e, em seguida, obter o elemento 'items'. Se você usar um único ditado em vez de uma lista de ditados de 1 item, poderá encontrar os itens para um tipo específico com uma única pesquisa com chave no ditado mestre. Usando
groupby
, seria assim:result
agora contém este ditado (é semelhante aores
padrão intermediário na resposta do @ KennyTM):(Se você deseja reduzir isso para uma linha, você pode:
ou usando o novo formulário de compreensão de ditados:
fonte
Eu também gostei de agrupamento simples de pandas . é poderoso, simples e mais adequado para grandes conjuntos de dados
result = pandas.DataFrame(input).groupby(1).groups
fonte
Esta resposta é semelhante à resposta de @ PaulMcG, mas não requer classificação da entrada.
Para aqueles em programação funcional,
groupBy
pode ser escrito em uma linha (não incluindo importações!) E, ao contrárioitertools.groupby
, não exige que a entrada seja classificada:(A razão para
... or grp
noslambda
é que para estereduce()
ao trabalho, aslambda
necessidades para retornar seu primeiro argumento, porquelist.append()
sempre retornaNone
aor
voltar sempregrp
. Ou seja, é um hack para contornar a restrição de python que uma lambda só pode avaliar uma única expressão.)Isso retorna um ditado cujas chaves são encontradas avaliando a função especificada e cujos valores são uma lista dos itens originais na ordem original. Para o exemplo do OP, chamar isso como
groupBy(lambda pair: pair[1], input)
retornará este ditado:E de acordo com a resposta do @ PaulMcG, o formato solicitado do OP pode ser encontrado envolvendo-o em uma lista de compreensão. Então, isso fará isso:
fonte
A função seguinte irá rapidamente ( sem ordenação necessária) tuplos do grupo de qualquer comprimento por uma chave que tem qualquer índice:
No caso da sua pergunta, o índice da chave que você deseja agrupar é 1, portanto:
dá
que não é exatamente a saída solicitada, mas também pode atender às suas necessidades.
fonte
fonte