Одинаково распределить и сжать два списка разной длины в Python - PullRequest
0 голосов
/ 20 декабря 2018

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

A = ["a","b","c","d","e","f","g","h","i"]
B = [1,2,3]

A в 3 раза длиннее, чем B, и поэтому я хотел бы сопоставить их, используя это, как показано ниже:

C = [("a",1"),("b",1"),("c",1"),
     ("d",2),("e",2),("f",2),
     ("g",3),("h",3),("i",3)]

Итакпервые 3 элемента A сопоставляются с первым элементом B, следующие 3 элемента A сопоставляются со вторым элементом B и т. д.

Далее, это очень упрощенный пример.Мне также было бы интересно узнать, как лучше всего распределить элементы, когда один список больше другого на число, которое не является целым числом.Например, два моих списка имеют длину 10001 и 511 элементов, поэтому первый на ~ 19,57 больше второго.Желательно использовать каждый элемент в обоих списках.

Ответы [ 5 ]

0 голосов
/ 20 декабря 2018

Вы также можете сгруппировать A в список подсписков, каждый подсписок имеет длину B:

A = ["a","b","c","d","e","f","g","h","i"]
B = [1,2,3]
_b = len(B)
new_a = [A[i:i+_b] for i in range(0, len(A), _b)]
final_result = [(c, i) for a, i in zip(new_a, B) for c in a]

Вывод:

[('a', 1), ('b', 1), ('c', 1), ('d', 2), ('e', 2), ('f', 2), ('g', 3), ('h', 3), ('i', 3)]
0 голосов
/ 20 декабря 2018

Я предполагаю, что первый список длиннее.

Вот простой способ:

rep = len(A) // len(B)
ia = iter(A)
C = [(next(ia), b) for b in B for i in range(rep)]
C.extend((a, B[-1]) for a in ia)         # in case len(A) is not an exact multiple of len(B)
0 голосов
/ 20 декабря 2018

Вы можете использовать grouper рецепт из itertools документов (или импортировать его из more_itertools).

Рецепт:

from itertools import zip_longest

def grouper(iterable, n, fillvalue=None):
    "Collect data into fixed-length chunks or blocks"
    # grouper('ABCDEFG', 3, 'x') --> ABC DEF Gxx"
    args = [iter(iterable)] * n
    return zip_longest(*args, fillvalue=fillvalue)

Применение:

>>> from more_itertools import grouper                                                               
>>> A = ["a","b","c","d","e","f","g","h","i"]                                                                          
>>> B = [1,2,3]                                                                                                        
>>> [(x, i) for vals, i in zip(grouper(A, len(B)), B) for x in vals]                                                   
[('a', 1),
 ('b', 1),
 ('c', 1),
 ('d', 2),
 ('e', 2),
 ('f', 2),
 ('g', 3),
 ('h', 3),
 ('i', 3)]
0 голосов
/ 20 декабря 2018

Вы также можете попробовать использовать zip() и повторить B со своим собственным пониманием списка:

>>> A = ["a","b","c","d","e","f","g","h","i"]
>>> B = [1,2,3]
>>> list(zip(A, (y for x in B for y in len(B) * [x])))
[('a', 1), ('b', 1), ('c', 1), ('d', 2), ('e', 2), ('f', 2), ('g', 3), ('h', 3), ('i', 3)]

Также рекомендуется не жестко кодировать len(B) * 3 и использовать scale = len(A) // len(B), чтобы получить пропорциональное распределение, как показано в @ coldspeed's answer

0 голосов
/ 20 декабря 2018

Предполагая, что длина A кратна B, вы можете легко сделать

>>> scale = len(A) // len(B)
>>> [(a, B[i // scale]) for i, a in enumerate(A)] 
[('a', 1),
 ('b', 1),
 ('c', 1),
 ('d', 2),
 ('e', 2),
 ('f', 2),
 ('g', 3),
 ('h', 3),
 ('i', 3)]

Как это работает:

  1. Определить значение k такой, что len(A) == k * len(B)
  2. Выполните итерацию по A и используйте k, чтобы определить, какое значение B выбрать, поделив на него текущий индекс, соответственно

Если длины не кратны, то получится

IndexError: list index out of range

. Вы можете обойти это, вычислив scale, чтобы быть

scale = len(A) // len(B) * len(B)

Например,

A = ["a", "b", "c", "d", "e", "f", "g", "h"]
B = [1, 2, 3]

>>> scale = len(A) // len(B) * len(B)
>>> [(a, B[i // scale]) for i, a in enumerate(A)] 
[('a', 1),
 ('b', 1),
 ('c', 1),
 ('d', 1),
 ('e', 1),
 ('f', 1),
 ('g', 2),
 ('h', 2)]

Вот функциональный подход с использованием itertools repeat и chain.from_iterable.

>>> from itertools import repeat, chain
>>> list(zip(A, chain.from_iterable(zip(*repeat(B, scale)))))
[('a', 1),
 ('b', 1),
 ('c', 1),
 ('d', 2),
 ('e', 2),
 ('f', 2),
 ('g', 3),
 ('h', 3),
 ('i', 3)]
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...