【问题标题】:Python creating list of lists where first item is of length one and the second item is of length n?Python创建列表的列表,其中第一项的长度为1,第二项的长度为n?
【发布时间】:2018-09-17 19:54:20
【问题描述】:

我在 python 中创建列表时遇到问题。假设我有以下列表:

fruitlist = [('Vendor A', 'Apples'),
('Vendor B', 'Apples'),
('Vendor C', 'Bananas'),
('Vendor A', 'Grapes'),
('Vendor A', 'Bananas'),
('Vendor B', 'Oranges')]

我想做的是创建这样的列表:[[Vendor A, (Apples, Grapes, Bananas)], [Vendor B, (Apples, Oranges)], [Vendor C, (Bananas)]]

所以基本上是供应商,然后是他们的产品。这是我目前拥有的代码,它基本上会遍历并仅提取供应商列表,然后循环遍历并捕获每个产品,但是,输出并不是我想要的。

vendors = list(set([x[0] for x in fruitlist]))
# this creates a list of just vendors:
output = [[] for x in range (len(vendors))]
#This creates a list with 3 empty lists inside (one for each vendor) where my output will be housed
    for x in range(0,len(vendors)):
        for y in range(0,len(fruitlist)):
            if fruitlist[y][0] == vendors[x]:
                output[x].append(fruitlist[y][1])

输出看起来像这样:

[['Apples', 'Oranges'], ['Apples', 'Grapes', 'Bananas'], ['Bananas']]

所以输出现在按供应商细分,每个供应商的产品现在都在自己的列表中,但现在我必须弄清楚如何在其中插入供应商名称,而我根本做不到。如果我在 for 循环的附加部分中包含供应商名称,

output[x].append((fruitlist[y][0],fruitlist[y][1]))

它会重复每个水果的供应商名称。如果我使用插入方法,它似乎创建了一个全新的项目,并增加了列表的长度。我尝试了一些事情,我尝试过谷歌搜索,但我无法找出正确的措辞。如果有人能指出我正确的方向,我将不胜感激。

当我查找供应商时,任何人都可以解释为什么:

 ['Vendor B', 'Vendor A', 'Vendor C']

它把“B”放在“A”之前?在我的原始列表 A 中,set 函数是否随机分配顺序?

【问题讨论】:

  • 套装是_un_ordered。它们的打印方式取决于您放入的内容,并且可能会发生变化。为什么不使用字典 vendorname->productlist?
  • 试试collections.defaultdict
  • 你真的需要一个列表列表吗?列表的字典可能是更好的选择。如果您需要供应商按特定顺序排列,您可以使用 OrderedDict 或 Python 3.6+
  • 是的,它不需要是一个列表,我之前没有真正使用过dicts,我可以试试,ty 的建议
  • 你的问题是一种XY问题:因为你不熟悉你试图做某事的字典,这比字典简单得多,使用列表列表,导致一些严重的并发症.其他答案解决了您问题的这个 XY 方面,建议使用字典。 My answer below 从表面上理解您的问题,并展示了一种使用列表列表解决问题的简单方法。

标签: python list


【解决方案1】:

集合只是元素的集合,没有列表那样的顺序。

我写这个的方法是创建一个字典,然后,当我们将它转​​换为一个列表时,我们可以对其进行排序以匹配输入顺序。

fruitlist = [('Vendor A', 'Apples'),
('Vendor B', 'Apples'),
('Vendor C', 'Bananas'),
('Vendor A', 'Grapes'),
('Vendor A', 'Bananas'),
('Vendor B', 'Oranges')]
vendors = {}
for vendor, fruit in fruitlist:
    vendors.setdefault(vendor, []).append(fruit)
ordered_fruitlist_vendors = [t[0] for t in fruitlist]
vendors_list = [[k, tuple(v)] for k,v in vendors.items()]
vendors_list.sort(key=lambda t: ordered_fruitlist_vendors.index(t[0]))

vendors_list 设为:

[['Vendor A', ('Apples', 'Grapes', 'Bananas')], ['Vendor B', ('Apples', 'Oranges')], ['Vendor C', ('Bananas',)]]

但是我怀疑是否有必要将一个简洁的字典转换为这个带有元组的 2 元素列表的笨重列表。当然,您希望能够在O(1) 时间使用vendors['Vendor A'] 从供应商处检索水果,而不是必须遍历这个将是O(n) 的列表?无论如何,这两种方法现在都是可选的!


setdefault的解释。

字典的setdefault 方法有两个参数——一个键和一个值。如果键已经存在于字典中,则返回当前值,否则使用传递给函数的值创建键并返回该值。

例如:

>>> d = {1:2}
>>> d.setdefault(1,3)
2
>>> d
{1: 2}
>>> d.setdefault(3,4)
4
>>> d
{1: 2, 3: 4}

因此,使用此方法的一个巧妙技巧是将键设置为空列表 ([])。然后,如果我们还没有那个键(在我们的例子中,还没有看到供应商),则返回一个空列表。否则,我们会得到一个列表的引用,其中包含我们迄今为止看到的所有供应商的成果。美妙之处在于我们可以将我们的新水果添加到返回的 whatever 中,并且将为该供应商创建一个新条目并附加新水果,或者如果该供应商已经存在,我们将只追加到之前创建的列表。

这意味着我们只需要迭代fruitlist 一次,这样解决方案就很有效。


另一个使用列表的方法示例:

>>> d = {}
>>> d.setdefault(1, []).append(2)
>>> d
{1: [2]}
>>> d.setdefault(1, []).append(3)
>>> d.setdefault(1, []).append(4)
>>> d
{1: [2, 3, 4]}
>>> d.setdefault(2, []).append(3)
>>> d.setdefault(2, []).append(3)
>>> d.setdefault(2, []).append(3)
>>> d
{1: [2, 3, 4], 2: [3, 3, 3]}

【讨论】:

  • 嗨,乔,我对 Python 有点陌生,你能试着解释一下你的代码中发生了什么吗?我有点困惑。因此,使用第一行创建一个空字典,然后填充。你的 forloop 的第二行让我有点困惑,你是否将供应商映射到一个空列表?这也不会造成欺骗吗?您的代码有效,因为我刚刚尝试过,但我不太确定您的映射在这里是如何工作的
  • @JedBartlet 没问题,总是乐于提供帮助!不过请接受。
  • @JoeIddon:请注意,使用collections.defaultdict(list) 会避免setdefault 的丑陋(vendors[vendor].append(fruit) 看起来更好),实际上在大多数情况下运行得更快(setdefault 必须构造空list 每次,即使密钥存在;defaultdict 是惰性的,只有当密钥丢失时才构造一个新的list
  • @Joe Iddon。头脑。吹。这是一个如此优雅的解决方案,哇。这难以置信。有没有,就像一个简单问题的优雅答案的存储库,我的意思是我喜欢看到这样的东西,太聪明了!
  • Imo 这对于一个可以在一个循环中完成的解决方案来说过于复杂,只需我的 2 美分
【解决方案2】:

看,没有字典

数据

In [15]: fruitlist = [('Vendor A', 'Apples'),
    ...:              ('Vendor B', 'Apples'),
    ...:              ('Vendor C', 'Bananas'),
    ...:              ('Vendor A', 'Grapes'),
    ...:              ('Vendor A', 'Bananas'),
    ...:              ('Vendor B', 'Oranges')]

输出列表,最初为空

In [16]: output = []

我们将使用 Python 的 for 循环的不常见功能,即 else 子句。如果for 正文正常结束,即没有break,则执行else 子句的正文

In [17]: for vendor, fruit in fruitlist:
    ...:     for sublist in output:
    ...:         if sublist[0] == vendor:
    ...:             sublist[1].append(fruit)
    ...:             break
    ...:     else:
    ...:         output.append([vendor, [fruit]])

最终我们检查我们的结果

In [18]: output
Out[18]: 
[['Vendor A', ['Apples', 'Grapes', 'Bananas']],
 ['Vendor B', ['Apples', 'Oranges']],
 ['Vendor C', ['Bananas']]]

我不得不说,原来的问题提到子列表,其中第二个元素是一个元组,而我有一个列表,但元组是不可变的......

【讨论】:

    【解决方案3】:

    您可以使用简单的for 循环和dictionary,无需过于复杂

    fruits = [ 
        ('Vendor A', 'Apples'),
        ('Vendor B', 'Apples'),
        ('Vendor C', 'Bananas'),
        ('Vendor A', 'Grapes'),
        ('Vendor A', 'Bananas'),
        ('Vendor B', 'Oranges')
    ]
    
    dicta = {}
    
    for vendor, item in fruits:
        if vendor not in dicta:
            dicta[vendor] = [item]
        else:
            dicta[vendor].append(item)
    
    print(dicta)
    
    (xenial)vash@localhost:~/python/stack_overflow$ python3.7 fruits.py
    {'Vendor A': ['Apples', 'Grapes', 'Bananas'], 'Vendor B': ['Apples', 'Oranges'], 'Vendor C': ['Bananas']}
    

    【讨论】:

    • vash,当我尝试将 append 方法与 dict 一起使用时,我不断收到错误消息,提示元组 ojbect 没有附加属性。供应商={'供应商A':'Apple'} | vendor['Vendor A'].append('Banana') 例如,该代码会产生一个错误,指出元组对象没有属性 append
    • 这是您尝试使用附加的方式,例如我调用 dicta[vendor] 这是一个 valuevalue 是一个 list 所以我只是附加一个列表,你不能追加到字典
    • 在这个dicta[vendor]中,让我们说在循环中它代表dicta['Vendor A'],它返回dicta['Vendor A']value,这是一个包含listlist,因为我们现在指的是list 我们可以使用dicta['Vendor A'].append('Grapes')
    • 如果value 不是list,您将无法将append 发送给它,在您发送给我vendors ={'Vendor A': 'Apple'} 的示例中,您会看到value 只是一个string 你不能 append 到一个字符串
    • 啊,我的错误,愚蠢的错误。非常感谢,这是了解更多有关 dicts 的好方法。
    猜你喜欢
    • 2018-08-29
    • 2021-03-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多