Mani interesē, vai ir kāds saīsinājums, lai Python programmā izveidotu vienkāršu sarakstu no sarakstu saraksta.
Es to varu izdarīt ar for
cilpu, bet varbūt ir kāds foršs "one-liner"? Es mēģināju to izdarīt ar reduce()
, bet man parādījās kļūda.
Kods
l = [[1, 2, 3], [4, 5, 6], [7], [8, 9]]
reduce(lambda x, y: x.extend(y), l)
Kļūdas ziņojums
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 1, in <lambda>
AttributeError: 'NoneType' object has no attribute 'extend'
Dots sarakstu saraksts l
,
plakanais saraksts = [item for sublist in l for item in sublist]
kas nozīmē:
flat_list = []
for sublist in l:
for item in sublist:
flat_list.append(item)
ir ātrāks par līdz šim publicētajiem saīsinājumiem. (l
ir saraksts, kas jāsalīdzina.)
Šeit ir atbilstošā funkcija:
flatten = lambda l: [item for sublist in l for item in sublist]
Kā pierādījumu var izmantot standarta bibliotēkas timeit
moduli:
$ python -mtimeit -s'l=[[1,2,3],[4,5,6], [7], [8,9]]*99' '[item for sublist in l for item in sublist]'
10000 loops, best of 3: 143 usec per loop
$ python -mtimeit -s'l=[[1,2,3],[4,5,6], [7], [8,9]]*99' 'sum(l, [])'
1000 loops, best of 3: 969 usec per loop
$ python -mtimeit -s'l=[[1,2,3],[4,5,6], [7], [8,9]]*99' 'reduce(lambda x,y: x+y,l)'
1000 loops, best of 3: 1.1 msec per loop
Paskaidrojums: saīsinājumi, kuru pamatā ir +
(ieskaitot netiešo lietošanu sum
), pēc nepieciešamības ir O(L**2)
, ja ir L apakšsarakstu - tā kā starprezultātu saraksts kļūst arvien garāks, katrā solī tiek piešķirts jauns starprezultātu saraksta objekts, un visi iepriekšējā starprezultāta elementi ir jāpārkopē (kā arī beigās jāpievieno daži jauni). Vienkāršības labad, nezaudējot vispārīgumu, pieņemsim, ka ir L apakšsarakstu ar I elementiem katrā: pirmie I elementi tiek kopēti turp un atpakaļ L-1 reizes, otrie I elementi - L-2 reizes utt.; kopiju kopējais skaits ir I reiz x summa, ja x no 1 līdz L izslēgts, t. i., I * (L**2)/2
.
Saraksta izpratne tikai vienu reizi ģenerē vienu sarakstu un katru elementu (no tā sākotnējās atrašanās vietas uz rezultātu sarakstu) arī kopē tieši vienu reizi.
Autora piezīme: Tas ir neefektīvi. Bet jautri, jo monoīdi ir forši. Tas nav piemērots ražošanas Python kodam.
>>> sum(l, [])
[1, 2, 3, 4, 5, 6, 7, 8, 9]
Tas vienkārši saskaita pirmajā argumentā nodotās iterablas elementus, otro argumentu uzskatot par summas sākotnējo vērtību (ja tā nav dota, tās vietā tiek izmantots 0
, un šajā gadījumā tiks pieļauta kļūda).
Tā kā tiek summēti iegulti saraksti, tad faktiski sum([[1,3],[2,4]],[])
rezultātā tiek iegūts [1,3]+[2,4]
, kas ir vienāds ar [1,3,2,4]
.
Ņemiet vērā, ka tas darbojas tikai sarakstu sarakstiem. Sarakstu sarakstu sarakstiem būs nepieciešams cits risinājums.
from functools import reduce #python 3
>>> l = [[1,2,3],[4,5,6], [7], [8,9]]
>>> reduce(lambda x,y: x+y,l)
[1, 2, 3, 4, 5, 6, 7, 8, 9]
Jūsu piemērā lietotā extend()
metode modificē x
, nevis atgriež noderīgu vērtību (ko sagaida reduce()
).
Ātrāks veids, kā veikt reducēt
versiju, būtu šāds
>>> import operator
>>> l = [[1,2,3],[4,5,6], [7], [8,9]]
>>> reduce(operator.concat, l)
[1, 2, 3, 4, 5, 6, 7, 8, 9]