Empresas
Empleos
  • Sobre nosotros
  • Soluciones
    • Publicación de vacantes
      Publica tu vacante y recibe candidatos calificados en 48h.
    • Evaluación de candidatos
      500+ pruebas técnicas y psicológicas, más anti-fraude.
    • Headhunting
      Búsqueda ejecutiva a la medida de principio a fin.
    • Nómina + EOR
      Dispersión de nómina y EOR en más de 15 países de LATAM.
  • Precios
  • Empleos

0

280
Vistas
zip_longest for the left list always

I know about the zip function (which will zip according to the shortest list) and zip_longest (which will zip according to the longest list), but how would I zip according to the first list, regardless of whether it's the longest or not?

For example:

Input:  ['a', 'b', 'c'], [1, 2]
Output: [('a', 1), ('b', 2), ('c', None)]

But also:

Input:  ['a', 'b'], [1, 2, 3]
Output: [('a', 1), ('b', 2)]

Do both of these functionalities exist in one function?

over 4 years ago · Santiago Trujillo
9 Respuestas
Responde la pregunta

0

Here's another take, if the goal is readable, easy to understand code:

def zip_first(first, *rest, fillvalue=None):
    rest = [iter(r) for r in rest]
    for x in first:
        yield x, *(next(r, fillvalue) for r in rest)

This uses the two-argument form of next() to return the fill value for all iterables that are exhausted.

For exactly two iterables, this can be simplified to

def zip_first(first, second, fillvalue=None):
    second = iter(second)
    for x in first:
        yield x, next(second, fillvalue)
over 4 years ago · Santiago Trujillo Denunciar

0

Return only len(a) elements from zip_longest:

from itertools import zip_longest

def zip_first(a, b):
    z = zip_longest(a, b)
    for i, r in zip(range(len(a)), z):
        yield r
over 4 years ago · Santiago Trujillo Denunciar

0

A little bit ugly, but I would go with this one. The idea is to shorten the second list to the size of the first one if it is longer. Then we use zip_longest guaranteeing that the result is at least as long as the first argument of zip.

import itertools

input1 = [['a', 'b', 'c'], [1, 2]]
input2 = [['a', 'b'], [1, 2, 3]]

zip1 = itertools.zip_longest(input1[0], input1[1][:len(input1[0])])
zip2 = itertools.zip_longest(input2[0], input2[1][:len(input2[0])])

print(list(zip1))
print(list(zip2))

Output:

[('a', 1), ('b', 2), ('c', None)]
[('a', 1), ('b', 2)]

To zip multiple lists this can be used:

import itertools

def zip_first(lists):
    equal_lists = [l[:len(lists[0])] for l in lists]
    return itertools.zip_longest(*equal_lists)
over 4 years ago · Santiago Trujillo Denunciar

0

I don't know of one readymade, but you can define your own.

Using object() as a sentinel ensures it will always test as unique, and never get confused with None or any other fill value. Thus this should behave properly even if either of your iterables contain None.

Like zip_longest, it takes any number of iterables (not necessarily two), and you can specify the fillvalue.

from itertools import zip_longest

def zip_left(*iterables, fillvalue=None):
    SENTINEL = object()
    
    for first, *others in zip_longest(*iterables, fillvalue=SENTINEL):
        if first is SENTINEL:
            return
        others = [i if i is not SENTINEL else fillvalue for i in others]
        yield (first, *others)


print(list(zip_left(['a', 'b', 'c'], [1, 2])))
print(list(zip_left(['a', 'b'], [1, 2, 3])))

Output:

[('a', 1), ('b', 2), ('c', None)]
[('a', 1), ('b', 2)]
over 4 years ago · Santiago Trujillo Denunciar

0

For generic iterators (or lists as well), you can use this. We yield pairs until we hit StopIteration on a. If we hit StopIteration on b first, we use None as the second value.

def zip_first(a, b):
    ai, bi = iter(a), iter(b)
    while True:
        try:
            aa = next(ai)
        except StopIteration:
            return           
        try:
            bb = next(bi)
        except StopIteration:
            bb = None
        yield aa, bb
over 4 years ago · Santiago Trujillo Denunciar

0

You can repurpose the "roughly equivalent" python code shown in the docs for itertools.zip_longest to make a generalized version that zips according to the length of the first argument:

from itertools import repeat

def zip_by_first(*args, fillvalue=None):
    # zip_by_first('ABCD', 'xy', fillvalue='-') --> Ax By C- D-
    # zip_by_first('ABC', 'xyzw', fillvalue='-') --> Ax By Cz
    if not args:
        return
    iterators = [iter(it) for it in args]
    while True:
        values = []
        for i, it in enumerate(iterators):
            try:
                value = next(it)
            except StopIteration:
                if i == 0:
                    return
                iterators[i] = repeat(fillvalue)
                value = fillvalue
            values.append(value)
        yield tuple(values)

You might be able to make some small improvements like caching repeat(fillvalue) or so. The issue with this implementation is that it's written in Python, while most of itertools uses a much faster C implementation. You can see the effects of this by comparing against Kelly Bundy's answer.

over 4 years ago · Santiago Trujillo Denunciar

0

If the inputs are lists (or other collections which can be used with len), you can use zip_longest and lazily limit the result to the length of the first list1, by using islice:

from itertools import islice, zip_longest

def zip_first(a, b):
    return islice(zip_longest(a, b), len(a))

1This basic idea was taken from the answer by Jan Christoph Terasa.

over 4 years ago · Santiago Trujillo Denunciar

0

idk but

first = ['a', 'b', 'c']
last = [1, 2, 3, 4]
if len(first) < len(last):
    b = list(zip(first, last))
else:
    b = list(zip_longest(first, last))
print(b)
over 4 years ago · Santiago Trujillo Denunciar

0

Make the second one infinite, and then just use normal zip:

from itertools import chain, repeat

a = ['a', 'b', 'c']
b = [1, 2]

b = chain(b, repeat(None))

print(*zip(a, b))
over 4 years ago · Santiago Trujillo Denunciar
Responde la pregunta
Encuentra empleos remotos

¡Descubre la nueva forma de encontrar empleo!

Top de empleos
Top categorías de empleo
Empresas
Publicar vacante Precios Comercial
Legal
Términos y condiciones Política de privacidad
© 2026 PeakU Inc. All Rights Reserved.
Andres GPT
Recomiéndame algunas ofertas
Necesito ayuda