programing

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

shortcode 2023. 7. 22. 12:10
반응형

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

파이썬에서 같은 길이의 두 목록을 인터리브할 수 있는 좋은 방법이 있습니까?

내가 주어진다고 해요.[1,2,3]그리고.[10,20,30]저는 그것들을 로 바꾸고 싶습니다.[1,10,2,20,3,30].

질문을 올리면서 다음을 간단히 수행할 수 있다는 것을 깨달았습니다.

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

어디에l1그리고.l2두 목록입니다.


인터리브할 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는 정확하게 올바른 길이의 새 목록을 만드는 간단한 방법으로 사용됩니다(현 단계에서는 내용이 중요하지 않음).다음 두 줄은 실제 인터리빙 작업을 수행합니다.a그리고.b첫 번째 사람은 요소를 할당합니다.a의 모든 짝수 색인에.c두 번째 것은 요소를 할당합니다.b의 모든 홀수 지수에.c.

정해진

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

코드

동일한 길이의 리스트를 가정하면 다음과 같은 인터리브 리스트를 얻을 수 있습니다.itertools.chain그리고.zip:

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+

이터 도구 레시피와 함께 제공되는 라이브러리 및

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

저는 다른 크기의 목록으로 이 작업을 수행할 방법이 필요했는데, 이 목록은 승인된 답변에 포함되지 않습니다.

내 솔루션은 제너레이터를 사용하며 그 사용법은 다음과 같습니다.

def interleave(l1, l2):
    iter1 = iter(l1)
    iter2 = iter(l2)
    while True:
        try:
            if iter1 is not None:
                yield next(iter1)
        except StopIteration:
            iter1 = None
        try:
            if iter2 is not None:
                yield next(iter2)
        except StopIteration:
            iter2 = None
        if iter1 is None and iter2 is 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']

대안:

>>> 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]

저는 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]

다음과 같은 방법도 있습니다.

list1 = [1, 2, 3]
list2 = [10, 20, 30]

list(sum(zip(list1, list2), ()))

그 생각은 비슷합니다.

  1. 명단을 정리해 주세요(zip 사용)
  2. 튜플로 납작하게 만들기(합(..., ()) 사용)
  3. 명부로 전환.

재미있는 접근법은 최종 목록의 위치를 키로 사용하는 것입니다.

from heapq import merge
from itertools import count

a = [1,2,3]
b = [10,20,30]

counter = count()
res = list(merge(a, b, key=lambda x: next(counter)))
print(res)

산출량

[1, 10, 2, 20, 3, 30]

여러 목록의 경우 다음과 같이 압축을 풀 수 있습니다.

from heapq import merge
from itertools import count

a = [1, 2, 3]
b = [10, 20, 30]
c = [11, 21, 31]

counter = count()
res = list(merge(*[a, b, c], key=lambda x: next(counter)))
print(res)

산출량

[1, 10, 11, 2, 20, 21, 3, 30, 31]
[el for el in itertools.chain(*itertools.izip_longest([1,2,3], [4,5])) if el is not None]

이 없으면 None 것.

"파이썬에서 길이가 같은 여러 목록을 인터리브"라는 질문의 제목에 답하기 위해, 우리는 @ekhumoro의 2-list 답변을 일반화할 수 있습니다.따라서 @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]

파티에 너무 늦었고, 좋은 답변들이 많지만, 저는 또한 다음을 사용하여 간단한 해결책을 제공하고 싶습니다.extend()방법:

list1 = [1, 2, 3]
list2 = [10, 20, 30]

new_list = []
for i in range(len(list1)):
    new_list.extend([list1[i], list2[i]])
print(new_list)

출력:

[1, 10, 2, 20, 3, 30]

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

반응형