Asumsikan bahwa saya memiliki satu set pasangan data di mana indeks 0 adalah nilainya dan indeks 1 adalah tipe:
input = [
('11013331', 'KAT'),
('9085267', 'NOT'),
('5238761', 'ETH'),
('5349618', 'ETH'),
('11788544', 'NOT'),
('962142', 'ETH'),
('7795297', 'ETH'),
('7341464', 'ETH'),
('9843236', 'KAT'),
('5594916', 'ETH'),
('1550003', 'ETH')
]
Saya ingin mengelompokkan mereka berdasarkan tipenya (berdasarkan string yang diindeks pertama) seperti:
result = [
{
type:'KAT',
items: ['11013331', '9843236']
},
{
type:'NOT',
items: ['9085267', '11788544']
},
{
type:'ETH',
items: ['5238761', '962142', '7795297', '7341464', '5594916', '1550003']
}
]
Bagaimana saya bisa mencapai ini dengan cara yang efisien?
[('11013331', 'red', 'KAT'), ('9085267', 'blue' 'KAT')]
mana elemen terakhir tupel adalah kunci dan dua yang pertama sebagai nilai. Hasilnya harus seperti ini: result = [{type: 'KAT', items: [('11013331', red), ('9085267', blue)]}]from operator import itemgetter
d= {}; for k,v in input: d.setdefault(k, []).append(v)
itertools
Modul built-in Python sebenarnya memilikigroupby
fungsi, tetapi untuk itu elemen yang akan dikelompokkan harus diurutkan terlebih dahulu sehingga elemen yang akan dikelompokkan bersebelahan dalam daftar:Sekarang masukan terlihat seperti:
groupby
mengembalikan urutan 2-tupel, dari bentuk(key, values_iterator)
. Apa yang kita inginkan adalah mengubahnya menjadi daftar dicts di mana 'type' adalah kuncinya, dan 'items' adalah daftar elemen ke-0 dari tupel yang dikembalikan oleh values_iterator. Seperti ini:Sekarang
result
berisi dikt yang Anda inginkan, seperti yang dinyatakan dalam pertanyaan Anda.Anda dapat mempertimbangkan, meskipun, hanya membuat satu dikt dari ini, dikunci menurut jenis, dan setiap nilai yang berisi daftar nilai. Dalam formulir Anda saat ini, untuk menemukan nilai untuk tipe tertentu, Anda harus mengulang daftar untuk menemukan dikt yang berisi kunci 'tipe' yang cocok, dan kemudian mendapatkan elemen 'item' darinya. Jika Anda menggunakan satu dikt dan bukan daftar dict 1-item, Anda dapat menemukan item untuk tipe tertentu dengan pencarian kunci tunggal ke dikt utama. Menggunakan
groupby
, ini akan terlihat seperti:result
sekarang berisi dict ini (ini mirip denganres
defaultdict menengah dalam jawaban @ KennyTM):(Jika Anda ingin mengurangi ini menjadi satu baris, Anda dapat:
atau menggunakan bentuk dikt-pemahaman bermodel baru:
sumber
Saya juga menyukai pengelompokan sederhana panda . ini kuat, sederhana dan paling memadai untuk kumpulan data besar
result = pandas.DataFrame(input).groupby(1).groups
sumber
Jawaban ini mirip dengan jawaban @ PaulMcG tetapi tidak memerlukan penyortiran input.
Bagi mereka yang menjadi pemrograman fungsional,
groupBy
dapat ditulis dalam satu baris (tidak termasuk impor!), Dan tidak sepertiitertools.groupby
itu, tidak memerlukan input untuk diurutkan:(Alasan untuk
... or grp
dilambda
adalah bahwa untuk inireduce()
untuk bekerja,lambda
kebutuhan untuk kembali argumen pertama, karenalist.append()
selalu mengembalikanNone
yangor
akan selalu kembaligrp
. Yaitu itu hack untuk berkeliling pembatasan python yang lambda hanya dapat mengevaluasi ekspresi tunggal.)Ini mengembalikan sebuah dict yang kuncinya ditemukan dengan mengevaluasi fungsi yang diberikan dan yang nilainya adalah daftar item asli dalam urutan aslinya. Untuk contoh OP, memanggil ini sebagai
groupBy(lambda pair: pair[1], input)
akan mengembalikan perintah ini:Dan sesuai jawaban @ PaulMcG, format yang diminta OP dapat ditemukan dengan membungkusnya dalam pemahaman daftar. Jadi ini akan melakukannya:
sumber
Fungsi berikut akan dengan cepat ( tidak perlu penyortiran ) mengelompokkan tupel dengan panjang berapa pun dengan kunci yang memiliki indeks:
Dalam kasus pertanyaan Anda, indeks kunci yang ingin Anda kelompokkan adalah 1, oleh karena itu:
memberi
yang bukan merupakan keluaran yang Anda minta, tetapi mungkin juga sesuai dengan kebutuhan Anda.
sumber
sumber