簡體   English   中英

用Pythonic方式混合兩個列表

[英]Pythonic way to mix two lists

我有兩個長度為n和n + 1的列表:

[a_1, a_2, ..., a_n]
[b_1, b_2, ..., b_(n+1)]

我想要一個函數,給出一個包含兩個元素的列表,即

[b_1, a_1, ..., b_n, a_n, b_(n+1)]

以下工作原理,但看起來並不聰明:

def list_mixing(list_long,list_short):
    list_res = []
    for i in range(len(list_short)):
        list_res.extend([list_long[i], list_short[i]])
    list_res.append(list_long[-1])
    return list_res

誰能建議一種更Python化的方式來做到這一點? 謝謝!

>>> import itertools
>>> a
['1', '2', '3', '4', '5', '6']
>>> b
['a', 'b', 'c', 'd', 'e', 'f']
>>> list(itertools.chain.from_iterable(zip(a,b)))
['1', 'a', '2', 'b', '3', 'c', '4', 'd', '5', 'e', '6', 'f']

zip()產生一個具有最短參數長度的可迭代對象。 您可以將a[-1]附加到結果中,也可以將itertools.zip_longest (對於Python 2.x使用izip_longest)與填充值一起使用,然后刪除該值。

您可以在此解決方案中使用兩個以上的輸入序列。

對於不附加最后一個值的情況,您可以嘗試使用這種骯臟的方法,但是我並不推薦這樣做,目前尚不清楚:

>>> a
[1, 2, 3, 4, 5]
>>> b
['a', 'b', 'c', 'd', 'e', 'f']
>>> [a[i//2] if i%2 else b[i//2] for i in range(len(a)*2+1)]
['a', 1, 'b', 2, 'c', 3, 'd', 4, 'e', 5, 'f']

(對於Python 2.x,請使用single /

恕我直言,最好的方法是:

result = [item for sublist in zip(a,b) for item in sublist]

它比求和和歸約的方法還快。

UPD對不起,您的第二個列表大了一個元素:)還有另一種瘋狂的方式:

result = [item for sublist in map(None, a, b) for item in sublist][:-1]
>>> long = [1, 3, 5, 7]
>>> short = [2, 4, 6]
>>> mixed = []
>>> for i in range(len(long)):
>>>     mixed.append(long[i])
>>>     if i < len(short)
>>>         mixed.append(short[i])
>>> mixed
[1, 2, 3, 4, 5, 6, 7]

混合兩個列表是zip的工作:

res = []
for a,b in zip(list_long, list_short):
    res += [a,b]

對於不同長度的列表,請定義您自己的函數:

def mix(list_long, list_short):
    result = []
    i,j = iter(list_long), iter(list_short)
    for a,b in zip(i,j):
        res += [a,b]
    for rest in i:
        result += rest
    for rest in j:
        result += rest
    return result

使用Mihail給出答案 ,我們可以將其簡化為:

def mix(list_long, list_short):
    i,j = iter(list_long), iter(list_short)
    result = [item for sublist in zip(i,j) for item in sublist]
    result += [item for item in i]
    result += [item for item in j]
    return result

我會結合使用以上答案:

>>> a = ['1', '2', '3', '4', '5', '6']

>>> b = ['a', 'b', 'c', 'd', 'e', 'f', 'g']

>>> [i for l in izip_longest(a, b, fillvalue=object) for i in l if i is not object]
<<< ['1', 'a', '2', 'b', '3', 'c', '4', 'd', '5', 'e', '6', 'f', 'g']

使用izip_longest填補列表中沒有的內容,或者不想保留結果。 如果您不想保留任何解析為False ,請使用izip_longestfilter的默認值:

from itertools import chain, izip_longest
l1 = [1,3,5]
l2 = [2,4,6,8,10]
filter(None, chain(*izip_longest(l1,l2)))

結果是: [1, 2, 3, 4, 5, 6, 8, 10]

使用None填補空白並使用filter將其移除:

filter(lambda x: x is not None, chain(*izip_longest(l1,l2, fillvalue=None)))

為了提高效率,當l1l2不是短列表而是很長或無限的可迭代對象時,請使用ifilter代替filter ,它會為您提供可迭代對象,而不是將所有內存都放在列表中。 例:

from itertools import chain, izip_longest, ifilter
for value in ifilter(None, chain(*izip_longest(iter1,iter1))):
    print value
sum([[x,y] for x,y in zip(b,a)],[])+[b[-1]]

注意:這僅適用於給定的列表長度,但可以輕松擴展到任意長度的列表。

這是我發現的最好的:

import itertools

l1 = [1, 3, 5]
l2 = [2, 4, 6, 8, 10]

result = [
    x # do something
    for x in itertools.chain.from_iterable(itertools.zip_longest(l1, l2, l1))
    if x is not None
]
result
# [1, 2, 1, 3, 4, 3, 5, 6, 5, 8, 10]

為了更加清楚, zip_longest按索引將元素分組在一起:

iter = list(itertools.zip_longest(l1, l2, l1))
iter[0]
# (1, 2, 1)
iter[1]
# (3, 4, 3)
iter[-1] # last
# (None, 10, None)

之后, itertools.chain.from_iterable它們按順序展平。

最好的原因:

  • 濾波None ,不推薦了,使用列表理解
  • 列表理解還可以讓您立即使用x來“做某事”
  • 當某些列表比最短的列表長時,它不會丟棄項目
  • 它適用於任何數量的列表
  • 實際上,很容易推斷出發生了什么事,而與那里所有的“聰明”相反

more-itertools具有roundrobin ,可以准確地完成此工作:

from more_itertools import roundrobin

l1 = [1, 3, 5]
l2 = [2, 4, 6, 8, 10]

print(list(roundrobin(l1,l2)))
# [1, 2, 1, 3, 4, 3, 5, 6, 5, 8, 10]

您可以執行以下操作(假設len(list_long)==len(list_short)+1

def list_mixing(list_long,list_short):
    return [(list_long[i/2] if i%2==0 else list_short[i/2]) for i in range(len(list_long)+len(list_short)]

我在哪里使用/進行整數除法(確切的運算符取決於語言版本)。

使用郵編。 這將為您提供一個元組列表,例如:[('a_1','b_1'),('a_2','b_2'),('a_3','b_3')]

如果要將其清理成一個不錯的列表,只需使用enumerate遍歷元組列表即可:

alist = ['a_1', 'a_2', 'a_3']
blist = ['b_1', 'b_2', 'b_3']
clist = []

for i, (a, b) in enumerate(zip(alist, blist)):
    clist.append(a)
    clist.append(b)
print clist
['a_1', 'b_1', 'a_2', 'b_2', 'a_3', 'b_3']

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM