itsource

두 목록을 교대로 결합(인터리브, 인터레이스, 서로 얽힘)하는 파이썬 방식?

mycopycode 2023. 8. 30. 21:42
반응형

두 목록을 교대로 결합(인터리브, 인터레이스, 서로 얽힘)하는 파이썬 방식?

저는 두 개의 목록을 가지고 있는데, 첫 번째 목록은 두 번째 목록보다 정확히 하나많은 항목을 포함하고 있습니다.짝수 지수 값이 첫 번째 목록에서 나오고 홀수 지수 값이 두 번째 목록에서 나오는 새로운 목록을 만드는 가장 파이썬적인 방법을 알고 싶습니다.

# example inputs
list1 = ['f', 'o', 'o']
list2 = ['hello', 'world']

# desired output
['f', 'hello', 'o', 'world', 'o']

효과는 있지만 예쁘지는 않습니다.

list3 = []
while True:
    try:
        list3.append(list1.pop(0))
        list3.append(list2.pop(0))
    except IndexError:
        break

달리 어떻게 해야만 이를 달성할 수 있습니까?가장 파이썬적인 접근법은 무엇입니까?


일치하지 않는 길이의 목록을 처리해야 하는 경우(예: 두 번째 목록이 더 길거나 첫 번째 목록에 두 개 이상의 요소가 있는 경우) 일부 솔루션은 작동하는 반면 다른 솔루션은 조정이 필요합니다.자세한 답변은 길이가 다른개의 목록을 인터리브하는 방법을 참조하십시오. 마지막에 과도한 요소를 남기는 방법을 참조하거나, 길이가 불균일한 개의 목록을 우아하게 인터리브하는 방법참조하여 요소를 고르게 인터리브합니다.또는 각 "추가된" 요소 앞에 특정 개수의 요소가 와야 하는 경우 n번째 요소 뒤에 Python 목록에 요소를 삽입합니다.

슬라이스를 통해 이를 수행하는 한 가지 방법은 다음과 같습니다.

>>> list1 = ['f', 'o', 'o']
>>> list2 = ['hello', 'world']
>>> result = [None]*(len(list1)+len(list2))
>>> result[::2] = list1
>>> result[1::2] = list2
>>> result
['f', 'hello', 'o', 'world', 'o']

에 대한 방법은 설명서에 나와 있습니다(참고: Python 3의 경우).

from itertools import cycle, islice

def roundrobin(*iterables):
    "roundrobin('ABC', 'D', 'EF') --> A D E B F C"
    # Recipe credited to George Sakkis
    num_active = len(iterables)
    nexts = cycle(iter(it).__next__ for it in iterables)
    while num_active:
        try:
            for next in nexts:
                yield next()
        except StopIteration:
            # Remove the iterator we just exhausted from the cycle.
            num_active -= 1
            nexts = cycle(islice(nexts, num_active))
import itertools
print([x for x in itertools.chain.from_iterable(itertools.zip_longest(list1,list2)) if x])

저는 이것이 가장 부정적인 방법이라고 생각합니다.

Python 2에서 이것은 당신이 원하는 것을 해야 합니다:

>>> iters = [iter(list1), iter(list2)]
>>> print list(it.next() for it in itertools.cycle(iters))
['f', 'hello', 'o', 'world', 'o']

반복 도구를 사용하지 않고 l1이 l2보다 1개 더 길다고 가정할 경우:

>>> sum(zip(l1, l2+[0]), ())[:-1]
('f', 'hello', 'o', 'world', 'o')

python 2에서 iter 도구를 사용하고 목록에 없음이 포함되어 있지 않다고 가정하는 경우:

>>> filter(None, sum(itertools.izip_longest(l1, l2), ()))
('f', 'hello', 'o', 'world', 'o')

두 목록의 길이가 같을 경우 다음 작업을 수행할 수 있습니다.

[x for y in zip(list1, list2) for x in y]

첫 번째 목록에 요소가 하나 더 있으므로 다음을 추가할 수 있습니다.

[x for y in zip(list1, list2) for x in y] + [list1[-1]]

편집: 첫 번째 목록 이해에서 무슨 일이 일어나고 있는지 설명하기 위해 루프에 대한 중첩으로 철자를 지정하는 방법은 다음과 같습니다.

result = []
for y in zip(list1, list2): # y is is a 2-tuple, containining one element from each list
    for x in y: # iterate over the 2-tuple
        result.append(x) # append each element individually

한 항목이 다른 항목보다 많은 두 개의 목록에 대한 질문이 있다는 것을 알지만, 이 질문을 찾을 수 있는 다른 사람들을 위해 이 질문을 넣기로 했습니다.

크기가 다른 두 개의 목록과 함께 작동하도록 조정된 Duncan의 솔루션이 여기 있습니다.

list1 = ['f', 'o', 'o', 'b', 'a', 'r']
list2 = ['hello', 'world']
num = min(len(list1), len(list2))
result = [None]*(num*2)
result[::2] = list1[:num]
result[1::2] = list2[:num]
result.extend(list1[num:])
result.extend(list2[num:])
result

다음 출력은 다음과 같습니다.

['f', 'hello', 'o', 'world', 'o', 'b', 'a', 'r'] 

다음은 이를 수행하는 하나의 라이너입니다.

list3 = [ item for pair in zip(list1, list2 + [0]) for item in pair][:-1]

다른 라이브러리가 없는 목록 이해를 사용하는 라이너는 다음과 같습니다.

list3 = [sub[i] for i in range(len(list2)) for sub in [list1, list2]] + [list1[-1]]

부작용으로 초기 목록1을 변경할 수 있는 경우 다음과 같은 다른 접근법이 있습니다.

[list1.insert((i+1)*2-1, list2[i]) for i in range(len(list2))]

이는 여러 항목의 그룹을 교대로 선택하고 모든 항목이 출력에 있는지 확인할 수 있는 옵션과 함께 위의 Carlos Valiente의 기여를 기반으로 합니다.

A=["a","b","c","d"]
B=[1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16]

def cyclemix(xs, ys, n=1):
    for p in range(0,int((len(ys)+len(xs))/n)):
        for g in range(0,min(len(ys),n)):
            yield ys[0]
            ys.append(ys.pop(0))
        for g in range(0,min(len(xs),n)):
            yield xs[0]
            xs.append(xs.pop(0))

print [x for x in cyclemix(A, B, 3)]

목록 A와 B를 각각 3개의 값 그룹으로 묶습니다.

['a', 'b', 'c', 1, 2, 3, 'd', 'a', 'b', 4, 5, 6, 'c', 'd', 'a', 7, 8, 9, 'b', 'c', 'd', 10, 11, 12, 'a', 'b', 'c', 13, 14, 15]

조금 늦을 수도 있지만 파이썬 원라이너를 하나 더 구입합니다.두 목록의 크기가 동일하거나 동일하지 않을 때 작동합니다.한 가지 가치가 없는 것은 그것이 a와 b를 수정할 것이라는 것입니다.문제가 있는 경우 다른 솔루션을 사용해야 합니다.

a = ['f', 'o', 'o']
b = ['hello', 'world']
sum([[a.pop(0), b.pop(0)] for i in range(min(len(a), len(b)))],[])+a+b
['f', 'hello', 'o', 'world', 'o']
from itertools import chain
list(chain(*zip('abc', 'def')))  # Note: this only works for lists of equal length
['a', 'd', 'b', 'e', 'c', 'f']

itertools.zip_longest 하나의 목록에 누락된 요소가 있는 튜플 쌍의 반복기를 반환합니다.fillvalue=None)로 표시됩니다.fillvalue=object사용할 수 있습니다.None값으로서). 쌍들을 평평하게 만든 경우, 필터합니다.fillvalue목록 이해에서, 이것은 다음을 제공합니다.

>>> from itertools import zip_longest
>>> def merge(a, b):
...     return [
...         x for y in zip_longest(a, b, fillvalue=object)
...         for x in y if x is not object
...     ]
...
>>> merge("abc", "defgh")
['a', 'd', 'b', 'e', 'c', 'f', 'g', 'h']
>>> merge([0, 1, 2], [4])
[0, 4, 1, 2]
>>> merge([0, 1, 2], [4, 5, 6, 7, 8])
[0, 4, 1, 5, 2, 6, 7, 8]

임의 반복 가능 항목으로 일반화:

>>> def merge(*its):
...     return [
...         x for y in zip_longest(*its, fillvalue=object)
...         for x in y if x is not object
...     ]
...
>>> merge("abc", "lmn1234", "xyz9", [None])
['a', 'l', 'x', None, 'b', 'm', 'y', 'c', 'n', 'z', '1', '9', '2', '3', '4']
>>> merge(*["abc", "x"]) # unpack an iterable
['a', 'x', 'b', 'c']

마지막으로 목록 이해 대신 제너레이터를 반환할 수 있습니다.

>>> def merge(*its):
...     return (
...         x for y in zip_longest(*its, fillvalue=object)
...         for x in y if x is not object
...     )
...
>>> merge([1], [], [2, 3, 4])
<generator object merge.<locals>.<genexpr> at 0x000001996B466740>
>>> next(merge([1], [], [2, 3, 4]))
1
>>> list(merge([1], [], [2, 3, 4]))
[1, 2, 3, 4]

다른 패키지에 문제가 없으면 다음을 시도할 수 있습니다.

>>> list(roundrobin('ABC', 'D', 'EF'))
['A', 'D', 'E', 'B', 'F', 'C']

내 생각엔:

a = "hlowrd"
b = "el ol"

def func(xs, ys):
    ys = iter(ys)
    for x in xs:
        yield x
        yield ys.next()

print [x for x in func(a, b)]
def combine(list1, list2):
    lst = []
    len1 = len(list1)
    len2 = len(list2)

    for index in range( max(len1, len2) ):
        if index+1 <= len1:
            lst += [list1[index]]

        if index+1 <= len2:
            lst += [list2[index]]

    return lst

뚱딴지는?문자열에서도 작동합니다.

import numpy as np

np.array([[a,b] for a,b in zip([1,2,3],[2,3,4,5,6])]).ravel()

결과:

array([1, 2, 2, 3, 3, 4])

최단 거리에서 멈춤:

def interlace(*iters, next = next) -> collections.Iterable:
    """
    interlace(i1, i2, ..., in) -> (
        i1-0, i2-0, ..., in-0,
        i1-1, i2-1, ..., in-1,
        .
        .
        .
        i1-n, i2-n, ..., in-n,
    )
    """
    return map(next, cycle([iter(x) for x in iters]))

물론, 다음/_next__method를 해결하는 것이 더 빠를 수 있습니다.

다른 질문에 대한 답변에서 영감을 얻은 여러 개의 단문:

import itertools

list(itertools.chain.from_iterable(itertools.izip_longest(list1, list2, fillvalue=object)))[:-1]

[i for l in itertools.izip_longest(list1, list2, fillvalue=object) for i in l if i is not object]

[item for sublist in map(None, list1, list2) for item in sublist][:-1]

기능적이고 불변적인 방식의 대안(파이썬 3):

from itertools import zip_longest
from functools import reduce

reduce(lambda lst, zipped: [*lst, *zipped] if zipped[1] != None else [*lst, zipped[0]], zip_longest(list1, list2),[])

루프에 사용하면 다음과 같이 쉽게 달성할 수 있습니다.

list1 = ['f', 'o', 'o']
list2 = ['hello', 'world']
list3 = []

for i in range(len(list1)):
    #print(list3)
    list3.append(list1[i])
    if i < len(list2):
        list3.append(list2[i])
        
print(list3)

출력:

['f', 'hello', 'o', 'world', 'o']

또한 목록 이해를 사용하면 이를 줄일 수 있습니다.그러나 이해를 위해 이 루프를 사용할 수 있습니다.

제 접근 방식은 다음과 같습니다.

from itertools import chain, zip_longest

def intersperse(*iterators):
    # A random object not occurring in the iterators
    filler = object()

    r = (x for x in chain.from_iterable(zip_longest(*iterators, fillvalue=filler)) if x is not filler)

    return r

list1 = ['f', 'o', 'o']
list2 = ['hello', 'world']

print(list(intersperse(list1, list2)))

는 임의수의반에대반작산를때다지니문원습했에기출의하복기고하동해복기▁it▁applied다니임습지▁an▁so원▁works,ator했▁i▁yields▁number의▁of때▁iterators를 적용했습니다.list()에.

def alternate_elements(small_list, big_list):
mew = []
count = 0
for i in range(len(small_list)):
    mew.append(small_list[i])
    mew.append(big_list[i])
    count +=1
return mew+big_list[count:]

if len(l2)>len(l1):
    res = alternate_elements(l1,l2)
else:
    res = alternate_elements(l2,l1)

print(res)

여기서는 크기에 따라 목록을 교환하고 수행합니다. 시간 복잡성 O(len(l1)+len(l2))로 더 나은 솔루션을 제공할 수 있는 사람이 있습니까?

간단한 일을 할 겁니다.

chain.from_iterable( izip( list1, list2 ) )

추가 스토리지 요구사항 없이 반복기를 사용할 수 있습니다.

이는 매우 불쾌하지만 목록의 크기에 관계없이 작동합니다.

list3 = [
    element for element in 
    list(itertools.chain.from_iterable([
        val for val in itertools.izip_longest(list1, list2)
    ]))
    if element != None
]

분명히 파티에 늦었지만, 여기 같은 길이의 목록을 위한 간결한 것이 있습니다.

output = [e for sub in zip(list1,list2) for e in sub]

임의 개수의 동일한 길이의 목록에 대해서도 일반화됩니다.

output = [e for sub in zip(list1,list2,list3) for e in sub]

기타.

나는 목록 이해력이 떨어지기에는 너무 늙었어, 그래서:

import operator
list3 = reduce(operator.add, zip(list1, list2))

언급URL : https://stackoverflow.com/questions/3678869/pythonic-way-to-combine-interleave-interlace-intertwine-two-lists-in-an-alte

반응형