Saya bertanya-tanya apakah ada jalan pintas untuk membuat daftar sederhana dari daftar daftar dengan Python.
Saya bisa melakukannya dalam satu for
lingkaran, tapi mungkin ada beberapa "satu-liner" yang keren? Saya mencobanya dengan reduce()
, tetapi saya mendapatkan kesalahan.
Kode
l = [[1, 2, 3], [4, 5, 6], [7], [8, 9]]
reduce(lambda x, y: x.extend(y), l)
Pesan eror
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 1, in <lambda>
AttributeError: 'NoneType' object has no attribute 'extend'
Jawaban:
Diberikan daftar daftar
l
,flat_list = [item for sublist in l for item in sublist]
yang berarti:
lebih cepat daripada pintasan yang diposting sejauh ini. (
l
adalah daftar untuk diratakan.)Berikut adalah fungsi yang sesuai:
Sebagai bukti, Anda dapat menggunakan
timeit
modul di perpustakaan standar:Penjelasan: pintasan berdasarkan
+
(termasuk penggunaan tersirat dalamsum
) adalah, tentu saja,O(L**2)
ketika ada L daftar - karena daftar hasil menengah terus bertambah, pada setiap langkah objek daftar hasil menengah baru dialokasikan, dan semua item dalam hasil antara sebelumnya harus disalin (serta beberapa yang baru ditambahkan di akhir). Jadi, untuk kesederhanaan dan tanpa kehilangan generalitas yang sebenarnya, katakan Anda memiliki masing-masing sub daftar L item I: item I pertama disalin bolak-balik L-1 kali, item I kedua L-2 kali, dan seterusnya; jumlah total salinan adalah I kali jumlah x untuk x dari 1 hingga L yang dikecualikan, yaituI * (L**2)/2
,.Pemahaman daftar hanya menghasilkan satu daftar, sekali, dan menyalin setiap item di atas (dari tempat asalnya ke daftar hasil) juga tepat sekali.
sumber
itertools.chain.from_iterable
:$ python -mtimeit -s'from itertools import chain; l=[[1,2,3],[4,5,6], [7], [8,9]]*99' 'list(chain.from_iterable(l))'
. Ini berjalan sedikit lebih dari dua kali lebih cepat dari pemahaman daftar bersarang yang tercepat dari alternatif yang ditampilkan di sini.list()
untuk mewujudkan iterator ke dalam daftar.list(itertools.chain.from_iterable(l))
adalah yang terbaik - seperti yang diperhatikan dalam komentar lain dan jawaban Shawn.Anda bisa menggunakan
itertools.chain()
:Atau Anda dapat menggunakan
itertools.chain.from_iterable()
yang tidak memerlukan pembongkaran daftar dengan*
operator :sumber
*
adalah hal yang rumit yang membuatnyachain
lebih mudah daripada pemahaman daftar. Anda harus tahu bahwa rantai hanya bergabung bersama iterables yang diteruskan sebagai parameter, dan * menyebabkan daftar tingkat atas diperluas menjadi parameter, jadichain
bergabunglah bersama semua iterables itu, tetapi tidak turun lebih jauh. Saya pikir ini membuat pemahaman lebih mudah dibaca daripada penggunaan rantai dalam kasus ini.for
lingkaran yang berulang kaliappend
lebih jelas.list = [["abc","bcd"],["cde","def"],"efg"]
akan menghasilkan keluaran["abc", "bcd", "cde", "def", "e", "f", "g"].
*
operator tidak dapat digunakan di python2Catatan dari penulis : Ini tidak efisien. Tapi menyenangkan, karena monoids mengagumkan. Ini tidak sesuai untuk kode Python produksi.
Ini hanya menjumlahkan elemen iterable yang diteruskan dalam argumen pertama, memperlakukan argumen kedua sebagai nilai awal dari jumlah (jika tidak diberikan,
0
digunakan sebagai gantinya dan kasus ini akan memberi Anda kesalahan).Karena Anda menjumlahkan daftar bersarang, Anda benar-benar mendapatkan
[1,3]+[2,4]
sebagai akibat darisum([[1,3],[2,4]],[])
, yang sama dengan[1,3,2,4]
.Perhatikan bahwa hanya berfungsi pada daftar daftar. Untuk daftar daftar daftar, Anda membutuhkan solusi lain.
sumber
Monoid
, yang merupakan salah satu abstraksi yang paling nyaman untuk memikirkan+
operasi dalam pengertian umum (tidak terbatas pada angka saja). Jadi jawaban ini layak diberi +1 dari saya untuk perlakuan daftar (yang benar) sebagai monoid. Pertunjukannya memprihatinkan ...Saya menguji sebagian besar solusi yang disarankan dengan perfplot (proyek peliharaan saya, pada dasarnya pembungkus
timeit
), dan ditemukanmenjadi solusi tercepat, baik ketika banyak daftar kecil dan beberapa daftar panjang digabungkan. (
operator.iadd
sama cepatnya.)Kode untuk mereproduksi plot:
sumber
The
extend()
metode dalam contoh Anda memodifikasix
bukannya kembali nilai yang berguna (yangreduce()
mengharapkan).Cara yang lebih cepat untuk melakukan
reduce
versi itusumber
reduce(operator.add, l)
akan menjadi cara yang benar untuk melakukanreduce
versi. Built-in lebih cepat dari lambdas.timeit.timeit('reduce(operator.add, l)', 'import operator; l=[[1, 2, 3], [4, 5, 6, 7, 8], [1, 2, 3, 4, 5, 6, 7]]', number=10000)
0.017956018447875977 *timeit.timeit('reduce(lambda x, y: x+y, l)', 'import operator; l=[[1, 2, 3], [4, 5, 6, 7, 8], [1, 2, 3, 4, 5, 6, 7]]', number=10000)
0.025218963623046875integers
. Tetapi bagaimana jika daftar berisistring
?operator.add
Fungsi ini berfungsi dengan baik untuk daftar bilangan bulat dan daftar string.Jangan menemukan kembali roda jika Anda menggunakan Django :
... Pandaas :
... Itertools :
... Matplotlib
... Unipath :
... Setuptools :
sumber
flatten = itertools.chain.from_iterable
harus menjadi jawaban yang tepatlist_of_menuitems = [1, 2, [3, [4, 5, [6]]]]
, maka akan mengakibatkan pada:[1, 2, 3, 4, 5, 6]
. Yang saya rindukan adalah level rata.Berikut ini adalah pendekatan umum yang berlaku untuk angka , string , daftar bersarang dan campuran wadah .
Kode
Catatan :
yield from flatten(x)
bisa digantifor sub_x in flatten(x): yield sub_x
collection.abc
ketyping
modul.Demo
Referensi
sumber
more_itertools
antara lain yang dibahas dalam posting ini. Bersulang.traverse
juga bisa menjadi nama yang bagus untuk sebatang pohon ini, sedangkan aku akan membuatnya kurang universal untuk jawaban ini dengan menempel pada daftar bersarang.if hasattr(x, '__iter__')
alih-alih mengimpor / memeriksaIterable
dan itu akan mengecualikan string juga.Jika Anda ingin meratakan struktur data di mana Anda tidak tahu seberapa dalam sarangnya Anda bisa menggunakan 1
iteration_utilities.deepflatten
Ini generator sehingga Anda perlu memberikan hasilnya ke
list
atau secara eksplisit beralih di atasnya.Untuk meratakan hanya satu tingkat dan jika masing-masing item itu sendiri iterable Anda juga dapat menggunakan
iteration_utilities.flatten
yang itu sendiri hanya pembungkus tipis di sekitaritertools.chain.from_iterable
:Hanya untuk menambahkan beberapa timing (berdasarkan jawaban Nico Schlömer yang tidak menyertakan fungsi yang disajikan dalam jawaban ini):
Ini adalah plot log-log untuk mengakomodasi rentang nilai yang sangat besar. Untuk alasan kualitatif: Lebih rendah lebih baik.
Hasil penelitian menunjukkan bahwa jika iterable hanya berisi beberapa iterables internal maka
sum
akan lebih cepat, namun untuk iterables lama hanyaitertools.chain.from_iterable
,iteration_utilities.deepflatten
atau pemahaman bersarang memiliki kinerja yang masuk akal denganitertools.chain.from_iterable
menjadi yang tercepat (seperti yang telah diperhatikan oleh Nico Schlömer).1 Penafian: Saya penulis perpustakaan itu
sumber
sum
tidak lagi bekerja pada urutan sewenang-wenang seperti yang dimulai dengan0
, membuatfunctools.reduce(operator.add, sequences)
penggantian (bukankah kita senang mereka dihapusreduce
dari builtin?). Ketika jenis diketahui mungkin lebih cepat untuk digunakantype.__add__
.sum
. Apakah Anda mengetahui versi Python mana yang berhenti berfungsi?0
hanyalah nilai awal default, jadi ini berfungsi jika seseorang menggunakan argumen awal untuk memulai dengan daftar kosong ... tapi itu masih berupa case strings khusus dan memberitahu saya untuk menggunakan join. Ini menerapkanfoldl
bukanfoldl1
. Masalah yang sama muncul di 2.7.Saya mengambil kembali pernyataan saya. jumlah bukanlah pemenang. Meskipun lebih cepat ketika daftar kecil. Tetapi kinerjanya menurun secara signifikan dengan daftar yang lebih besar.
Versi penjumlahannya masih berjalan lebih dari satu menit dan belum selesai diproses!
Untuk daftar sedang:
Menggunakan daftar kecil dan batas waktu: angka = 1000000
sumber
Tampaknya ada kebingungan dengan
operator.add
! Saat Anda menambahkan dua daftar bersama, istilah yang benar untuk itu adalahconcat
, bukan menambahkan.operator.concat
adalah apa yang perlu Anda gunakan.Jika Anda berpikir fungsional, semudah ini ::
Anda melihat mengurangi menghormati jenis urutan, jadi ketika Anda memasok tuple, Anda mendapatkan kembali tuple. Mari kita coba dengan daftar ::
Aha, Anda mendapatkan kembali daftar.
Bagaimana dengan kinerja ::
from_iterable
cukup cepat! Tetapi tidak ada perbandingan untuk dikurangi denganconcat
.sumber
list(chain.from_iterable(...))
dan 2,5 detik untukreduce(concat, ...)
. Masalahnya adalah yangreduce(concat, ...)
memiliki runtime kuadrat, sedangkanchain
linear.Mengapa Anda menggunakan ext?
Ini seharusnya bekerja dengan baik.
sumber
from functools import reduce
Pertimbangkan untuk menginstal
more_itertools
paket.Ini dikirimkan dengan implementasi untuk
flatten
( sumber , dari resep itertools ):Pada versi 2.4, Anda dapat meratakan iterables yang lebih rumit dan bersarang
more_itertools.collapse
( sumber , disumbangkan oleh abarnet).sumber
Alasan fungsi Anda tidak berfungsi adalah karena ekstensi memanjang array di tempat dan tidak mengembalikannya. Anda masih dapat mengembalikan x dari lambda, menggunakan sesuatu seperti ini:
Catatan: ekstensi lebih efisien daripada + pada daftar.
sumber
extend
lebih baik digunakan sebagainewlist = []
,extend = newlist.extend
,for sublist in l: extend(l)
karena menghindari (agak besar) overhead darilambda
, atribut lookup padax
, danor
.from functools import reduce
sumber
def flatten(l, a=None): if a is None: a = []
[...]Versi rekursif
sumber
matplotlib.cbook.flatten()
akan bekerja untuk daftar bersarang bahkan jika mereka bersarang lebih dalam dari contoh.Hasil:
Ini 18x lebih cepat dari garis bawah ._. Ratakan:
sumber
Jawaban yang diterima tidak berfungsi untuk saya ketika berhadapan dengan daftar panjang variabel berdasarkan teks. Berikut adalah pendekatan alternatif yang berhasil bagi saya.
Jawaban yang diterima yang tidak berhasil:
Baru yang diusulkan solusi yang melakukan pekerjaan untuk saya:
sumber
Fitur buruk dari fungsi Anil di atas adalah mengharuskan pengguna untuk selalu secara manual menentukan argumen kedua sebagai daftar kosong
[]
. Ini seharusnya menjadi default. Karena cara kerja objek Python, ini harus diatur di dalam fungsi, bukan dalam argumen.Ini fungsi yang berfungsi:
Pengujian:
sumber
Mengikuti tampaknya paling sederhana bagi saya:
sumber
Satu juga dapat menggunakan flat NumPy :
Sunting 11/02/2016: Hanya berfungsi ketika sublists memiliki dimensi yang identik.
sumber
Anda bisa menggunakan numpy:
flat_list = list(np.concatenate(list_of_list))
sumber
[1, 2, [3], [[4]], [5, [6]]]
Jika Anda bersedia memberikan sedikit kecepatan untuk tampilan yang lebih bersih, maka Anda dapat menggunakan
numpy.concatenate().tolist()
ataunumpy.concatenate().ravel().tolist()
:Anda dapat menemukan lebih banyak di sini di docs numpy.concatenate dan numpy.ravel
sumber
[1, 2, [3], [[4]], [5, [6]]]
Solusi tercepat yang saya temukan (untuk daftar besar):
Selesai! Tentu saja Anda dapat mengubahnya kembali menjadi daftar dengan menjalankan daftar (l)
sumber
Kode sederhana untuk
underscore.py
kipas paketIni memecahkan semua masalah mendatar (tidak ada item daftar atau bersarang kompleks)
Anda dapat menginstal
underscore.py
dengan pipsumber
sumber
[[1, 2, 3], [4, 5, 6], [7], [8, 9]]
Catatan : Di bawah ini berlaku untuk Python 3.3+ karena digunakan
yield_from
.six
juga merupakan paket pihak ketiga, meskipun stabil. Bergantian, Anda bisa menggunakansys.version
.Dalam hal
obj = [[1, 2,], [3, 4], [5, 6]]
, semua solusi di sini baik, termasuk pemahaman daftar danitertools.chain.from_iterable
.Namun, pertimbangkan kasus yang sedikit lebih rumit ini:
Ada beberapa masalah di sini:
6
hanyalah skalar; itu tidak dapat diubah, sehingga rute di atas akan gagal di sini.'abc'
, adalah teknis iterable (semuastr
s adalah). Namun, membaca yang tersirat sedikit, Anda tidak ingin memperlakukannya seperti itu - Anda ingin memperlakukannya sebagai elemen tunggal.[8, [9, 10]]
itu sendiri adalah iterable bersarang. Pemahaman daftar dasar danchain.from_iterable
hanya mengekstrak "1 level ke bawah."Anda dapat memperbaiki ini sebagai berikut:
Di sini, Anda memeriksa bahwa sub-elemen (1) dapat diubah dengan
Iterable
, sebuah ABC dariitertools
, tetapi juga ingin memastikan bahwa (2) elemen tersebut tidak seperti "string-like."sumber
yield from
kefor
loop, misalnyafor x in flatten(i): yield x
Kode ini juga berfungsi dengan baik karena hanya memperpanjang daftar sepanjang jalan. Meskipun sangat mirip tetapi hanya memiliki satu untuk loop. Jadi itu memiliki kompleksitas lebih sedikit daripada menambahkan 2 untuk loop.
sumber
Keuntungan dari solusi ini daripada kebanyakan orang lain di sini adalah jika Anda memiliki daftar seperti:
sementara sebagian besar solusi lain membuat kesalahan, solusi ini menangani mereka.
sumber
Ini mungkin bukan cara yang paling efisien tetapi saya berpikir untuk menempatkan satu-liner (sebenarnya dua-liner). Kedua versi akan bekerja pada daftar bersarang hierarki sewenang-wenang, dan mengeksploitasi fitur bahasa (Python3.5) dan rekursi.
Outputnya adalah
Ini bekerja secara mendalam terlebih dahulu. Rekursi turun hingga menemukan elemen non-daftar, lalu memperluas variabel lokal
flist
dan kemudian mengembalikannya ke induk. Setiap kaliflist
dikembalikan, diperpanjang ke orang tuaflist
dalam pemahaman daftar. Oleh karena itu, pada root, daftar datar dikembalikan.Yang di atas membuat beberapa daftar lokal dan mengembalikannya yang digunakan untuk memperpanjang daftar induk. Saya pikir jalan keluar untuk ini mungkin menciptakan gloabl
flist
, seperti di bawah ini.Outputnya lagi
Meskipun saya tidak yakin saat ini tentang efisiensi.
sumber
Pendekatan lain yang tidak biasa yang berfungsi untuk daftar bilangan bulat hetero dan homogen:
sumber
wierd_list = [[1, 2, 3], [4, 5, 6], [7], [8, 9], 10]
>>nice_list=[1, 2, 3, 4, 5, 6, 7, 8, 9, 1, 0]
flat_list = [int(e.replace('[','').replace(']','')) for e in str(deep_list).split(',')]
[int(e.strip('[ ]')) for e in str(deep_list).split(',')]
. Tapi saya sarankan untuk tetap dengan proposal Deleet untuk kasus penggunaan nyata. Itu tidak mengandung transformasi tipe hacky, lebih cepat dan lebih fleksibel karena secara alami juga menangani daftar dengan tipe campuran.