Apakah mungkin untuk mengembalikan 2 (atau lebih) item untuk setiap item dalam pemahaman daftar?
Yang saya inginkan (contoh):
[f(x), g(x) for x in range(n)]
harus kembali [f(0), g(0), f(1), g(1), ..., f(n-1), g(n-1)]
Jadi, sesuatu untuk menggantikan blok kode ini:
result = list()
for x in range(n):
result.add(f(x))
result.add(g(x))
python
list-comprehension
Hashmush
sumber
sumber
Jawaban:
>>> from itertools import chain >>> f = lambda x: x + 2 >>> g = lambda x: x ** 2 >>> list(chain.from_iterable((f(x), g(x)) for x in range(3))) [2, 0, 3, 1, 4, 4]
Waktu:
from timeit import timeit f = lambda x: x + 2 g = lambda x: x ** 2 def fg(x): yield f(x) yield g(x) print timeit(stmt='list(chain.from_iterable((f(x), g(x)) for x in range(3)))', setup='gc.enable(); from itertools import chain; f = lambda x: x + 2; g = lambda x: x ** 2') print timeit(stmt='list(chain.from_iterable(fg(x) for x in range(3)))', setup='gc.enable(); from itertools import chain; from __main__ import fg; f = lambda x: x + 2; g = lambda x: x ** 2') print timeit(stmt='[func(x) for x in range(3) for func in (f, g)]', setup='gc.enable(); f = lambda x: x + 2; g = lambda x: x ** 2') print timeit(stmt='list(chain.from_iterable((f(x), g(x)) for x in xrange(10**6)))', setup='gc.enable(); from itertools import chain; f = lambda x: x + 2; g = lambda x: x ** 2', number=20) print timeit(stmt='list(chain.from_iterable(fg(x) for x in xrange(10**6)))', setup='gc.enable(); from itertools import chain; from __main__ import fg; f = lambda x: x + 2; g = lambda x: x ** 2', number=20) print timeit(stmt='[func(x) for x in xrange(10**6) for func in (f, g)]', setup='gc.enable(); f = lambda x: x + 2; g = lambda x: x ** 2', number=20)
sumber
(f(x), g(x))
. Bisa lebih baik ditulis sebagai:def fg(x): yield x + 2; yield x ** 2; list(chain.from_iterable(fg(x) for x in range(3)))
.chain.from_iterable((func(x) for func in funcs) for x in range(n)))
. Yang pada akhirnya akan menghilangkan keluhan khachik. (Meskipun dalam arti tertentu, milik saya dan miliknya pada dasarnya sama dalam hal proses. Kami hanya mendefinisikan generator dalam secara berbeda.)sum(..., [])
jawaban saya karena tidak perlu membuat ulang daftar pada setiap + (sehingga memiliki kinerja O (N) daripada kinerja O (N ^ 2)). Saya masih akan menggunakansum(..., [])
saat saya ingin satu baris cepat atau saya sedang terburu-buru, atau saat jumlah suku yang digabungkan dibatasi (mis. <= 10).[y for x in range(n) for y in (f(x), g(x))]
Tapi ini mungkin lebih lambat. @jamylak Anda dapat menguji ini juga jika Anda mau.Pemahaman daftar ganda:
[f(x) for x in range(5) for f in (f1,f2)]
Demo:
>>> f1 = lambda x: x >>> f2 = lambda x: 10*x >>> [f(x) for x in range(5) for f in (f1,f2)] [0, 0, 1, 10, 2, 20, 3, 30, 4, 40]
sumber
for x in range(5): for f in (f1, f2): newlist.append(f(x))
. Saya dulu merasa mereka sedikit membingungkan karena saya terus mencoba membalikkan urutan.sum( ([f(x),g(x)] for x in range(n)), [] )
Ini sama dengan
[f(1),g(1)] + [f(2),g(2)] + [f(3),g(3)] + ...
Anda juga bisa menganggapnya sebagai:
def flatten(list): ... flatten( [f(x),g(x)] for x in ... )
Catatan: Cara yang benar adalah dengan menggunakan
itertools.chain.from_iterable
atau pemahaman daftar ganda. (Tidak perlu membuat ulang daftar pada setiap +, sehingga memiliki kinerja O (N) daripada kinerja O (N ^ 2).) Saya masih akan menggunakansum(..., [])
ketika saya ingin one-liner cepat atau saya sedang terburu-buru , atau ketika jumlah suku yang digabungkan dibatasi (misalnya <= 10). Itulah mengapa saya masih menyebutkannya di sini, dengan peringatan ini. Anda juga dapat menggunakan tupel:((f(x),g(x)) for ...), ()
(atau menurut komentar khachik, memiliki generator fg (x) yang menghasilkan dua tupel).sumber
[f(1),g(1)] + [f(2),g(2)] + [f(3),g(3)] + ...
sum()
cara ini sebagai antipattern, dan saya tidak melihat adanya pembenaran untuk menggunakannya dalam keadaan apa pun. Kode di jawaban Anda yang lain kurang mengetik, jadi bahkan alasan "ketika saya ingin satu baris cepat atau saya sedang terburu-buru" tidak benar-benar memotongnya.Fungsi lambda ini menggabungkan dua daftar menjadi satu:
zipped = lambda L1, L2: [L[i] for i in range(min(len(L1), len(L2))) for L in (L1, L2)]
Contoh:
>>> f = [x for x in range(5)] >>> g = [x*10 for x in range(5)] >>> zipped(f, g) [0, 0, 1, 10, 2, 20, 3, 30, 4, 40]
sumber
Saya tahu OP sedang mencari solusi pemahaman daftar, tetapi saya ingin menawarkan penggunaan alternatif
list.extend()
.f = lambda x: x g = lambda x: 10*x result = [] extend = result.extend for x in range(5): extend((f(x),g(x)))
yang sedikit lebih cepat daripada menggunakan pemahaman daftar ganda.
nums = range(100000) def double_comprehension(): return [func(x) for x in nums for func in (f,g)] def list_extend(): result = [] extend = result.extend for x in nums: extend((f(x),g(x))) return result %timeit -n100 double_comprehension() 23.4 ms ± 67 µs per loop (mean ± std. dev. of 7 runs, 100 loops each) %timeit -n100 list_extend() 20.5 ms ± 213 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
Versi Python: 3.8.0
sumber
Solusi dengan menggunakan pengurangan :
from functools import reduce f = lambda x: f"f({x})" ## Just for example g = lambda x: f"g({x})" data = [1, 2, 3] reduce(lambda acc, x: acc + [f(x), g(x)], data, []) # => ['f(1)', 'g(1)', 'f(2)', 'g(2)', 'f(3)', 'g(3)']
Meskipun bukan pemahaman daftar, ini adalah cara fungsional untuk mendekati masalah. Pemahaman daftar pada dasarnya adalah cara lain untuk
map
mengolah data, tetapi dalam kasus ini di mana pemetaan tidak satu lawan satu antara masukan dan keluaran,reduce
memungkinkan beberapa ruang gerak dengan bagaimana keluaran dapat dihasilkan.Secara umum, setiap
for
implementasi bentuk:result = [] for n in some_data: result += some_operation() ## etc.
(Yaitu untuk loop yang dimaksudkan untuk menghasilkan efek samping pada daftar atau struktur data serupa)
Dapat direfraktorisasi menjadi
map/reduce/filter
implementasi deklaratif .sumber