ProgramingTip

Python에서 길이가 같은 여러 목록을 인터리브

bestdevel 2020. 10. 31. 09:56
반응형

Python에서 길이가 같은 여러 목록을 인터리브


어느 곳에서 길이가 같은 두 목록을 인터리브하는 좋은 방법이 있습니까?

I 'm 주어진 [1,2,3]하고 [10,20,30]. 나는 성가시다 [1,10,2,20,3,30].


질문을 게시 한 후 다음을 수행 할 수 있다고 생각합니다.

[val for pair in zip(l1, l2) for val in pair]

경우 l1l2두 목록입니다.


인터리브 할 목록이 N 개이면

lists = [l1, l2, ...]
[val for tup in zip(*lists) for val in tup]

더 많은 레시피를 보려면 접미사 값으로 목록을 인터리브하는 가장 좋은 방법을 보고세요 . 거기에서 설명 된 방법 중 일부는 동일한 길이의 두 개 이상의 목록으로 일반화 될 수 있습니다.


Python> = 2.3의 경우 확장 된 내부 구문이 있습니다 .

>>> a = [0, 2, 4, 6, 8]
>>> b = [1, 3, 5, 7, 9]
>>> c = a + b
>>> c[::2] = a
>>> c[1::2] = b
>>> c
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

c = a + b은 내용 길이의 새 목록을 만드는 방법으로 사용됩니다. (이 단계에서는 내용이 중요하지 않습니다.) 다음 두 줄은 인터리빙의 실제 수행 ab: 첫 번째는 작업 에 할당 a된 모든 짝수 작업에를 c; 두 번째는 b모든 홀수 수준에 의 요소를 할당합니다 c.


주어진

a = [1, 2, 3]
b = [10, 20, 30]
c = [100, 200, 300, 999]

암호

길이가 같은 목록을 가정하면 itertools.chainzip다음을 사용 하여 인터리브 된 목록을 얻을 수 있습니다 .

import itertools


list(itertools.chain(*zip(a, b)))
# [1, 10, 2, 20, 3, 30]

대안

itertools.zip_longest

일반적으로 같지 않은 목록의 경우 다음을 사용하십시오 zip_longest(권장).

[x for x in itertools.chain(*itertools.zip_longest(a, c)) if x is not None]
# [1, 100, 2, 200, 3, 300, 999]

많은 목록을 고용주 인터리브 할 수 있습니다.

[x for x in itertools.chain(*itertools.zip_longest(a, b, c)) if x is not None]
# [1, 10, 100, 2, 20, 200, 3, 30, 300, 999]

more_itertools+

roundrobinitertools 레시피 와 함께 제공되는 라이브러리 .interleaveinterleave_longest

import more_itertools


list(more_itertools.roundrobin(a, b))
# [1, 10, 2, 20, 3, 30]

list(more_itertools.interleave(a, b))
# [1, 10, 2, 20, 3, 30]

list(more_itertools.interleave_longest(a, c))
# [1, 100, 2, 200, 3, 300, 999]

yield from

마지막으로 Python 3에서 흥미로운 점 (권장되지 않은 현상) :

list(filter(None, ((yield from x) for x in zip(a, b))))
# [1, 10, 2, 20, 3, 30]

list([(yield from x) for x in zip(a, b)])
# [1, 10, 2, 20, 3, 30]

+ 사용하여 설치pip install more_itertools


대안 :

>>> l1=[1,2,3]
>>> l2=[10,20,30]
>>> [y for x in map(None,l1,l2) for y in x if y is not None]
[1, 10, 2, 20, 3, 30]

이것은 지도 가 목록에서 병렬로 작동하기 때문에 작동합니다. 그것은 동일하게 작동 2.2에서. 자체적으로 None호출 된 함수 map로 튜플 목록을 생성합니다.

>>> map(None,l1,l2,'abcd')
[(1, 10, 'a'), (2, 20, 'b'), (3, 30, 'c'), (None, None, 'd')]

그런 다음 튜플 목록을 평면화하십시오.

물론 장점 map은 목록의 수에 관계없이 작동하며 길이가 다른 경우에도 작동한다는 것입니다.

>>> l1=[1,2,3]
>>> l2=[10,20,30]
>>> l3=[101,102,103,104]
>>> [y for x in map(None,l1,l2,l3) for y in x if y in not None]
[1, 10, 101, 2, 20, 102, 3, 30, 103, 104]

나는 수용된 대답이 다루지 않는 다른 크기의 목록으로 수행하는 방법이 필요했습니다.

내 솔루션은 생성기를 사용하고 그 사용은 그 때문에 약간 더 좋아합니다.

def interleave(l1, l2):
    iter1 = iter(l1)
    iter2 = iter(l2)
    while True:
        try:
            if iter1 != None:
                yield next(iter1)
        except StopIteration:
            iter1 = None
        try:
            if iter2 != None:
                yield next(iter2)
        except StopIteration:
            iter2 = None
        if iter1 == None and iter2 == None:
            raise StopIteration()

그리고 그 사용법 :

>>> a = [1, 2, 3, 4, 5]
>>> b = ['a', 'b', 'c', 'd', 'e', 'f', 'g']
>>> list(interleave(a, b))
[1, 'a', 2, 'b', 3, 'c', 4, 'd', 5, 'e', 'f', 'g']
>>> list(interleave(b, a))
['a', 1, 'b', 2, 'c', 3, 'd', 4, 'e', 5, 'f', 'g']

나는 aix의 솔루션을 가장 좋아합니다. 2.2에서 작동해야 생각하는 또 다른 방법이 있습니다.

>>> x=range(3)
>>> x
[0, 1, 2]
>>> y=range(7,10)
>>> y
[7, 8, 9]
>>> sum(zip(x,y),[])
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: can only concatenate list (not "tuple") to list
>>> sum(map(list,zip(x,y)),[])
[0, 7, 1, 8, 2, 9]

한 가지 더 방법 :

>>> a=[x,y]
>>> [a[i][j] for j in range(3) for i in (0,1)]
[0, 7, 1, 8, 2, 9]

과 :

>>> sum((list(i) for i in zip(x,y)),[])
[0, 7, 1, 8, 2, 9]

[el for el in itertools.chain(*itertools.izip_longest([1,2,3], [4,5])) if el is not None]

당신이없는만큼 None유지하려는 것을


"파이썬에서 같은 길이의 여러 목록을 인터리브"라는 질문의 제목에 답하기 위해 @ekhumoro의 2 개 목록 답을 일반화 할 수 있습니다. 이를 위해서는 @NPE의 (우아한) 솔루션과 달리 목록의 길이가 동일해야합니다.

import itertools

def interleave(lists):
    """Interleave a list of lists.

    :param lists: List of lists; each inner length must be the same length.
    :returns: interleaved single list
    :rtype: list

    """
    if len(set(len(_) for _ in lists)) > 1:
        raise ValueError("Lists are not all the same length!")
    joint = list(itertools.chain(*lists))
    for l_idx, li in enumerate(lists):
        joint[l_idx::len(lists)] = li
    return joint

예 :

>>> interleave([[0,2,4], [1, 3, 5]])
[0, 1, 2, 3, 4, 5]
>>> interleave([[0,2,4], [1, 3, 5], [10, 11, 12]])
[0, 1, 10, 2, 3, 11, 4, 5, 12]
>>> interleave([[0,2,4], [1, 3, 5], [10, 11, 12], [13, 14, 15]])
[0, 1, 10, 13, 2, 3, 11, 14, 4, 5, 12, 15]
>>> interleave([[0,2,4], [1, 3, 5], [10, 11, 12], [13, 14]])
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 10, in interleave
ValueError: Lists are not all the same length!
>>> interleave([[0,2,4]])
[0, 2, 4]

참고 URL : https://stackoverflow.com/questions/7946798/interleave-multiple-lists-of-the-same-length-in-python

반응형