Как объединить несколько списков по их индексам

#python #list #indexing #merge

Вопрос:

Я хочу объединить вложенный список (списки в нем имеют разную длину) в один. Я хотел бы сначала добавить по индексу. Затем отсортируйте по размеру.

Пример:

 lsts = [
     [7, 23, 5, 2],
     [3, 8, 1],
     [99, 23, 9, 23, 74]
]

merged = [3, 7, 99, 8, 23, 23, 1, 5, 9, 2, 23, 74]
 

Я хотел бы решить эту проблему без импорта.

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

1. Вы пробовали написать цикл над индексами и использовать sorted функцию?

Ответ №1:

Предполагая, что ваш список списков не может содержать None s, вы можете сделать это с помощью itertools.zip_longest :

 from itertools import zip_longest

result = []
for row in zip_longest(*lsts):
    row = (x for x in row if x is not None)
    for x in sorted(row):
        result.append(x)

print(result)
 

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

1. Большое спасибо, но я хотел бы решить эту проблему без импорта. Я также отметил это в своем посте сейчас.

2. Почему бы не импортировать набор стандартных инструментов, которые, скорее всего, будут гораздо более производительными, чем ручной код wirtten? Возможно, это упражнение по кодированию или школьное задание? В противном случае я не вижу веской причины не использовать импорт стандартных библиотек.

3. Действительно, это задача, в первую очередь направленная на понимание логики. Но я уже давно не ходил в школу :’)

4. FWIW, в документах для itertools.zip_longest() приведен эквивалент кода на Python, который не использует импорт. То же самое для itertools.chain() . Вы можете использовать это для создания решения, фактически ничего не импортируя. 🙂

Ответ №2:

Вот однострочный:

 import functools
import itertools

functools.reduce(lambda x,y: x y, [sorted(x for x in p if x is not None) for p in itertools.zip_longest(*lsts)])
 

Выход:

 [3, 7, 99, 8, 23, 23, 1, 5, 9, 2, 23, 74]
 

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

1. Большое спасибо, но я хотел бы решить эту проблему без импорта. Я также отметил это в своем посте сейчас.

2. @red_joice Если вы хотите решить эту проблему без импорта, то это звучит как домашнее задание, которое вы должны попытаться решить самостоятельно. Что вы пробовали? Где ты застрял?

Ответ №3:

Я объясню решение шаг за шагом с каждым построением на результатах предыдущего шага.

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

 >>> import itertools as it

>>> MISSING = object()  # a sentinel

>>> lsts = [
     [7, 23, 5, 2],
     [3, 8, 1],
     [99, 23, 9, 23, 74]
]
>>> it.zip_longest(*lsts, fillvalue=MISSING)
>>> list(_)
[(7, 3, 99), (23, 8, 23), (5, 1, 9), (2, <object object at 0x7f529e9b4260>, 23), (<object object at 0x7f529e9b4260>, <object object at 0x7f529e9b4260>, 74)]
 

Это группирует элементы списка в n-кортежей, используя при необходимости ОТСУТСТВУЮЩЕЕ значение заполнения, поскольку списки могут быть разной длины.

Следующий шаг-выполнить итерацию по каждому n-кортежу и отсортировать его внутри (пропуская ПРОПУЩЕННЫЕ значения). Встроенная функция sorted() пригодится здесь:

 >>> list(
    sorted(x for x in ntuple if x is not MISSING)
    for ntuple in it.zip_longest(*lsts, fillvalue=MISSING)
)
[[3, 7, 99], [8, 23, 23], [1, 5, 9], [2, 23], [74]]
 

Последний шаг-сгладить эту последовательность списков, и мы будем использовать itertools.chain,from_iterable():

 >>> list(it.chain.from_iterable(
        sorted(x for x in ntuple if x is not MISSING)
        for ntuple in it.zip_longest(*lsts, fillvalue=MISSING)
    ))
[3, 7, 99, 8, 23, 23, 1, 5, 9, 2, 23, 74]
 

Хорошая вещь в том chain.from_iterable() , что он не многократно объединяет меньшие списки в более длинный и длинный окончательный список, что делает его эффективным. Он также делает это на уровне C, AFAIK.

Стоит отметить, что None это также можно использовать вместо MISSING sentinel, но я использовал MISSING, чтобы также продемонстрировать, как fillvalue это работает (например, вы можете использовать вместо нуля или что-то другое, если хотите).

Ответ №4:

zip_longest делает свою работу. Остальное-очистка/форматирование

 In [1]: from itertools import zip_longest, chain                                

In [2]: lsts = [ 

   ...:      [7, 23, 5, 2], 
   ...:      [3, 8, 1], 
   ...:      [99, 23, 9, 23, 74] 
   ...: ]           

In [3]: [v for v in chain.from_iterable(zip_longest(*lsts)) if v !=None]        
Out[3]: [7, 3, 99, 23, 8, 23, 5, 1, 9, 2, 23, 74]