Составьте список из нескольких списков

#python #list

Вопрос:

У меня есть три списка:

 list_01 = ['DOG','CAT','BEAR']
list_02 = ['V','W','X','Y','Z']
list_03 = ['A','B','C','D','E','F','G','H']
 

То, что я надеюсь получить, — это список, подобный следующему:

 list_04 = ['DOG','V','A','CAT','W','B','BEAR','X','C','Y','D','Z','E','F','G','H']
 

Предполагается, что этот список должен содержать один элемент из списка 1, затем один из списка 2 и один из списка 3. Затем это продолжается до тех пор, пока список 1 не будет исчерпан; затем список 1 следует игнорировать, и тот же процесс должен происходить только в списках 2 и 3, продолжаясь до тех пор, пока все списки не опустеют.

Ответ №1:

Похоже, вы хотите сделать это по порядку, а не случайным образом. Если это так, вы можете использовать zip_longest() из itertools и сделать понимание вложенного списка:

 from itertools import zip_longest

list_01 = ['DOG','CAT','BEAR']
list_02 = ['V','W','X','Y','Z']
list_03 = ['A','B','C','D','E','F','G','H']


list_04 = [n for group in zip_longest(list_01, list_02, list_03) 
           for n in group if n is not None]

# ['DOG', 'V', 'A', 'CAT', 'W', 'B', 'BEAR', 'X', 'C', 'Y', 'D', 'Z', 'E', 'F', 'G', 'H']
 

Примечание: zip_longest будет генерировать None значения, когда закончится один список. Вот почему мы ищем в понимании. None

Ответ №2:

Вы можете использовать zip_longest и chain из itertools модуля:

 from itertools import chain, zip_longest
list_04 = [i for i in chain(*zip_longest(list_01, list_02, list_03))
           if i is not None]
 

выход:

 ['DOG', 'V', 'A', 'CAT', 'W', 'B', 'BEAR', 'X', 'C', 'Y', 'D', 'Z', 'E', 'F', 'G', 'H']
 

Комментарии:

1. Это удалит все ложные значения, а не только ни одного, что может быть проблемой для OP.

2. @AKX Я видел у тебя интересную альтернативу. Я не склонен преждевременно оптимизировать, пример OP, похоже, указывает на то, что никаких ложных значений не ожидается 😉

3. Кстати, как обращаться со случаями, когда один из списков не содержит ни одного?

4. @eroot163pi Вы можете использовать fillvalue=XXX zip_longest с чем-то, что, как вы знаете, не будет соответствовать, и вместо этого проверить равенство с этим.

5. @eroot163pi проверьте итератор AKX, вот что он делает

Ответ №3:

Самый простой способ:

 result = list(roundrobin(list_01, list_02, list_03))
 

Просто скопируйте и вставьте roundrobin из рецептов Itertools или импортируйте их из more-itertools (как указано в разделе рецепты).


В качестве альтернативы мне нравится использовать heapq.merge :

 result = list(map(itemgetter(1), merge(*map(enumerate, lists), key=itemgetter(0))))
 

Вариант:

 index, value = map(itemgetter, (0, 1))
result = list(map(value, merge(*map(enumerate, lists), key=index)))
 

Полный код (попробуйте онлайн!):

 from operator import itemgetter
from heapq import merge

list_01 = ['DOG','CAT','BEAR']
list_02 = ['V','W','X','Y','Z']
list_03 = ['A','B','C','D','E','F','G','H']
lists = list_01, list_02, list_03
expect = ['DOG','V','A','CAT','W','B','BEAR','X','C','Y','D','Z','E','F','G','H']

result = list(map(itemgetter(1), merge(*map(enumerate, lists), key=itemgetter(0))))

print(result == expect)

index, value = map(itemgetter, (0, 1))
result = list(map(value, merge(*map(enumerate, lists), key=index)))

print(result == expect)
 

Ответ №4:

Вы можете использовать more_itertools.interleave_longest :

 >>> from more_itertools import interleave_longest
>>> list(interleave_longest(
...     ['DOG','CAT','BEAR'],
...     ['V','W','X','Y','Z'],
...     ['A','B','C','D','E','F','G','H'],
... ))
['DOG', 'V', 'A', 'CAT', 'W', 'B', 'BEAR', 'X', 'C', 'Y', 'D', 'Z', 'E', 'F', 'G', 'H']
 

Ответ №5:

 list_01 = ['DOG','CAT','BEAR']
list_02 = ['V','W','X','Y','Z']
list_03 = ['A','B','C','D','E','F','G','H']
L = [list_01, list_02, list_03]


def shuffle(L):
    result = []

    while any(L):
        for sub in L:
            if sub:
                result.append(sub.pop(0))

    return result

print(shuffle(L))

 

Выход:

 ['DOG', 'V', 'A', 'CAT', 'W', 'B', 'BEAR', 'X', 'C', 'Y', 'D', 'Z', 'E', 'F', 'G', 'H']
 

Комментарии:

1. Вы имеете в виду, не помещая вложенные списки в другой список?

2. Я обновил свое решение. Я думаю, проблема заключалась в том, что я удалил из списка, повторяя его, что создало некоторые неприятные побочные эффекты.

Ответ №6:

Вы можете использовать функцию zip

 
list_01 = ['DOG','CAT','BEAR']
list_02 = ['V','W','X','Y','Z']
list_03 = ['A','B','C','D','E','F','G','H']

minimum_size = min(len(list_01) , len(list_02) , len(list_03))

new_array = []

for item1 , item2 , item3 in zip(list_01 , list_02 , list_03):
    new_array.extend([item1 , item2 , item3])
    
new_array  = list_01[minimum_size:]   list_02[minimum_size:]   list_03[minimum_size:]

print(new_array)
 

Комментарии:

1. Это не работает корректно для списков разной длины

Ответ №7:

Редактировать: в этом ответе списки объединяются неупорядоченным образом, что не совсем то, что хотел ОП.

Используется itertools.chain для объединения списков в один список, а затем random.shuffle для перемешивания этого списка на месте:

 from itertools import chain
from random import shuffle

list_01 = ['DOG','CAT','BEAR']
list_02 = ['V','W','X','Y','Z']
list_03 = ['A','B','C','D','E','F','G','H']

full_list = list(chain(list_01, list_02, list_03))
shuffle(full_list)

print(full_list)  # in my case: ['BEAR', 'V', 'Z', 'W', 'A', 'Y', 'E', 'G', 'CAT', 'B', 'X', 'H', 'D', 'F', 'DOG', 'C']
 

Комментарии:

1. Идея заключается не в том, чтобы перетасовать их, а выбрать по порядку.

2. @AKX Ах, понятно, я не понял этого из вопроса. Не уверен, что мне следует удалить свой ответ, но я, по крайней мере, отредактирую его и добавлю предупреждение.

Ответ №8:

Используя простой python(без numpy), это лучшее, что я мог придумать.

Я считаю, что это работает для любого порядка, длины списков и не предполагает значения fill_value

 list_01 = ['DOG','CAT','BEAR']
list_02 = ['V','W','X','Y','Z']
list_03 = ['A','B','C','D','E','F','G','H']
L = [list_01, list_03, list_02]
def zigzag(*arg):
    i = 0
    LL = []
    all_done = False
    while not all_done:
        all_done = True
        for l in arg:
            if i >= len(l):
                continue
            all_done = False
            LL.append(l[i])
        i  = 1
    return LL
print(zigzag(list_01, list_02, list_03))
print(zigzag(list_01, list_03, list_02))