Застрял в расширенных срезах при попытке объединить списки путем чередования значений - PullRequest
1 голос
/ 11 февраля 2020

У меня есть фрагмент кода следующим образом:

ascii_key = [None]*(len(ascii_username) + len(ascii_password))
ascii_key[0::2] = ascii_username
ascii_key[1::2] = ascii_password

Я продолжаю получать следующую ошибку:

ValueError: попытка назначить последовательность размера 8 расширенному срезу размера 6

Я думаю, что это как-то связано с тем, что он хочет, чтобы я заполнил весь расширенный список точно, и если это так, есть ли способ объединить два списка до того, как он разозлится?

Идеальный процесс - списки ["A", "B", "C"] и ["D", "E", "F"] становятся

["A", "D", "B", "E", "C", "F"]

Я попытался следовать решению из этого поста Pythoni c способ объединения два списка поочередно?

- заранее извиняюсь, я начинающий программист.

Ответы [ 2 ]

3 голосов
/ 11 февраля 2020

То, что вы пытаетесь сделать, это чередование двух последовательностей. Причина, по которой вы видите ошибку, заключается в том, что ascii_username и ascii_password не имеют одинаковую длину. Когда вы пытаетесь присвоить фрагменту списка, вы должны указать точное количество элементов в фрагменте.

В этом примере это легко увидеть: нарезка x при размере шага 2 содержит больше элементов, чем y.

x = [1, 2, 3, 4, 5, 6, 7, 8]
y = 'yes'
z = 'nope!'

print(x[::2])
# prints:
[1, 3, 5, 7]
print(list(y))
['y', 'e', 's']

При попытке присвоить x[::2] остается висячий 7, который не переназначается.

Чтобы решить эту проблему, вы можете использовать interleave_longest из пакета more_itertools.

from more_itertools import interleave_longest

list(interleave_longest(x, y))
# returns:
['y', 'n', 'e', 'o', 's', 'p', 'e', '!']

Или, если вы не хотите устанавливать новый пакет, исходный код функции довольно мал.

from itertools import chain, zip_longest

_marker = object()

def interleave_longest(*iterables):
    """Return a new iterable yielding from each iterable in turn,
    skipping any that are exhausted.

        >>> list(interleave_longest([1, 2, 3], [4, 5], [6, 7, 8]))
        [1, 4, 6, 2, 5, 7, 3, 8]

    This function produces the same output as :func:`roundrobin`, but may
    perform better for some inputs (in particular when the number of iterables
    is large).

    """
    i = chain.from_iterable(zip_longest(*iterables, fillvalue=_marker))
    return [x for x in i if x is not _marker]


interleave_longest(x, y)
# returns:
['y', 'n', 'e', 'o', 's', 'p', 'e', '!']
1 голос
/ 11 февраля 2020

Для этой задачи вы можете использовать roundrobin, как показано в itertools recipes

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

Тогда:

t1 = ['A', 'B', 'C']
t2 = ['D', 'E', 'F']
interleaved = list(roundrobin(t1,t2))
print(interleaved)  # ['A', 'D', 'B', 'E', 'C', 'F']

Обратите внимание, что roundrobin(t1,t2) генератор Я передаю его в функцию list, чтобы получить list. Он будет использовать все элементы, например, для t1 = ['A', 'B', 'C'], t2 = ['D', 'E', 'F', 'G', 'H'] результат равен ['A', 'D', 'B', 'E', 'C', 'F', 'G', 'H'].

...