python-3.x 具有单个元素的压缩列表

xwmevbvl  于 2023-03-20  发布在  Python
关注(0)|答案(9)|浏览(158)

我有一个包含一些元素的列表,例如[1, 2, 3, 4],还有一个对象,例如'a',我想生成一个元组列表,列表中的元素在第一个位置,对象在第二个位置:[(1, 'a'), (2, 'a'), (3, 'a'), (4, 'a')] .
我可以像这样用zip来实现:

def zip_with_scalar(l, o): # l - the list; o - the object
    return list(zip(l, [o] * len(l)))

但是,这给我一种创建和重复元素的不必要列表的感觉。
另一种可能是

def zip_with_scalar(l, o):
    return [(i, o) for i in l]

这是非常干净和pythonic确实,但在这里我做整个事情“手动”。在Haskell我会这样做

zipWithScalar l o = zip l $ repeat o

是否有任何内置函数或技巧,无论是标量压缩还是使我能够使用普通zip的东西,即sort-of无限列表?

b5lpy0ml

b5lpy0ml1#

这是最接近您的Haskell解决方案:

import itertools

def zip_with_scalar(l, o):
    return zip(l, itertools.repeat(o))

你也可以使用生成器,它可以避免像解析那样创建一个列表:

def zip_with_scalar(l, o):
    return ((i, o) for i in l)
xriantvc

xriantvc2#

您可以使用内置的map函数:

>>> elements = [1, 2, 3, 4]
>>> key = 'a'
>>> map(lambda e: (e, key), elements)
[(1, 'a'), (2, 'a'), (3, 'a'), (4, 'a')]
bejyjqdl

bejyjqdl3#

对于itertools.cycle类来说,这是一个完美的工作。

from itertools import cycle

def zip_with_scalar(l, o):
    return zip(i, cycle(o))

演示:

>>> from itertools import cycle
>>> l = [1, 2, 3, 4]
>>> list(zip(l, cycle('a')))
[(1, 'a'), (2, 'a'), (3, 'a'), (4, 'a')]
zzwlnbp8

zzwlnbp84#

lst = [1,2,3,4]
tups = [(itm, 'a') for itm in lst]
tups

> [(1, 'a'), (2, 'a'), (3, 'a'), (4, 'a')]
v1l68za4

v1l68za45#

>>> l = [1, 2, 3, 4]
>>> list(zip(l, "a"*len(l)))
[(1, 'a'), (2, 'a'), (3, 'a'), (4, 'a')]
epfja78i

epfja78i6#

您也可以将 zip_longestofillvalue一起使用:

from itertools import zip_longest

def zip_with_scalar(l, o): # l - the list; o - the object
    return zip_longest(l, [o], fillvalue=o)

print(list(zip_with_scalar([1, 2, 3, 4] ,"a")))

请注意,无论使用zip_longest还是repeat,用于o的任何可变值都不会被复制。

ar7v8xwq

ar7v8xwq7#

more-itertools库最近添加了一个zip_broadcast()函数,很好地解决了这个问题:

>>> from more_itertools import zip_broadcast
>>> list(zip_broadcast([1,2,3,4], 'a'))
[(1, 'a'), (2, 'a'), (3, 'a'), (4, 'a')]

这是一个比这里发布的其他答案更通用的解决方案:

  • 正确处理空可迭代对象。
  • 可以有多个可迭代和/或标量参数。
  • 标量/可迭代参数的顺序不需要知道。
  • 如果有多个可迭代参数,可以使用strict=True检查它们是否具有相同的长度。
  • 您可以轻松地控制字符串是否应被视为可迭代对象(默认情况下不是)。
z4iuyo4d

z4iuyo4d8#

只需要定义一个带有无限迭代器的类,它是用你想要注入到列表中的单个元素初始化的:

class zipIterator:
    def __init__(self, val):
        self.__val = val

    def __iter__(self):
        return self

    def __next__(self):
        return self.__val

然后从这个类和你现有的列表中创建一个新的列表:

elements = [1, 2, 3, 4]
key = 'a'
res = [it for it in zip(elements, zipIterator(key))]

其结果将是:

>>res
[(1, 'a'), (2, 'a'), (3, 'a'), (4, 'a')]
kxxlusnw

kxxlusnw9#

我很惊讶没有人提出一个使用列表解析或生成器对象的简单Python解决方案。
假设我们有一个字符串列表-〉data,我们想使用zip(),在每个项中添加一个整数2001(年份),我们可以创建一个与data列表长度相同的列表,在每个项中包含整数2001。

data = ['RIN1', 'RIN2', 'RIN3', 'RIN4', 'RIN5', 'RIN6', 'RIN7']
zipped = list(zip(data, [2001 for _ in data]))

但是有一个更好的解决方案使用生成器-这样我们就可以避免创建一个潜在的相同值的巨大列表。

data = ['RIN1', 'RIN2', 'RIN3', 'RIN4', 'RIN5', 'RIN6', 'RIN7']
zipped = list(zip(data, (2001 for _ in data)))

所以不用[2001 for _ in data]创建实际的列表
我们可以定义一个生成器对象:(2001 for _ in data)
区别(表面上)只是括号的类型:[.] -〉(.)
我希望你们中的一些人觉得这有用。

相关问题