Функция Python, которая чередует произвольное количество списков в качестве параметров.

Отредактировано для простоты, так как я указал проблему на "распаковку аргументов".
Я пытаюсь написать функцию, которая чередует произвольное количество списков в качестве параметров. Все списки имеют одинаковую длину. Функция должна возвращать один список, содержащий все элементы из чередующихся входных списков.

def interleave(*args):

    for i, j, k in zip(*args):
        print(f"On {i} it was {j} and the temperature was {k} degrees celsius.")

interleave(["Monday Tuesday Wednesday Thursday Friday Saturday Sunday".split()],["rainy rainy sunny cloudy rainy sunny sunny".split()],[10,12,12,9,9,11,11])

Выход:

On ['Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday'] it was ['rainy', 'rainy', 'sunny', 'cloudy', 'rainy', 'sunny', 'sunny'] and the temperature was 10 degrees celsius.

желаемый результат:

On Monday it was rainy and the temperature was 10 degrees celsius.
On Tuesday it was rainy and the temperature was 12 degrees celsius.
On Wednesday it was sunny and the temperature was 12 degrees celsius.
On Thursday it was cloudy and the temperature was 9 degrees celsius.
On Friday it was rainy and the temperature was 9 degrees celsius.
On Saturday it was sunny and the temperature was 11 degrees celsius.
On Sunday it was sunny and the temperature was 11 degrees celsius.

person Saurus    schedule 18.01.2020    source источник


Ответы (2)


Не заключайте результат split в список. Итак, измените

interleave(["Monday Tuesday Wednesday Thursday Friday Saturday Sunday".split()],["rainy rainy sunny cloudy rainy sunny sunny".split()],[10,12,12,9,9,11,11])

to

interleave("Monday Tuesday Wednesday Thursday Friday Saturday Sunday".split(),"rainy rainy sunny cloudy rainy sunny sunny".split(),[10,12,12,9,9,11,11]).

В то время как первое приведет к двум спискам длины 1 и списку длины 7 в качестве аргументов для interleave, последнее/изменение приведет к трем спискам длины 7 в качестве аргументов. Последнее — это то, что вам нужно, чтобы оператор zip работал так, как вы хотите.

person Venkatesh-Prasad Ranganath    schedule 18.01.2020

В разделе рецептов itertools документации это называется roundrobin:

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

В частности, для списков (равного размера) вы можете упростить это до

def interleave(*args):
    return list(chain.from_iterable(zip(*args)))
person chepner    schedule 18.01.2020
comment
Кажется немного продвинутым для 1 недели Python. Функции напоминают интерфейсы из java. - person Saurus; 18.01.2020
comment
@Saurus Функции напоминают интерфейсы из Java. Какие функции и как? - person AMC; 18.01.2020
comment
Итерируемый интерфейс в java также имеет метод next(). В приведенном выше примере также использовался итератор. - person Saurus; 18.01.2020
comment
@ Заурус Ну да. Он использует протокол итератора. iterables не ограничивается списками; вы можете передать смесь списков, кортежей, наборов, строк, словарей или чего-либо еще, что реализует протокол итератора. - person chepner; 18.01.2020