Python - 根据索引对数字列表进行排序

3
我需要创建一个程序,其中有一个类来创建一个名为“Food”的对象,并且有一个名为“fridge”的列表来保存这些由“Food”类创建的对象。
class Food:
    def __init__(self, name, expiration):
        self.name = name
        self.expiration = expiration


fridge = [Food("beer",4), Food("steak",1),  Food("hamburger",1),  Food("donut",3),]

这并不难。然后我创建了一个函数,它会给你一个保质期最长的食品。
def exp(fridge):
    expList=[]
    xen = 0
    for i in range(0,len(fridge)):
        expList.append(fridge[xen].expiration)
        xen += 1
    print(expList)
    sortedList = sorted(expList)
    return sortedList.pop()

exp(fridge)

这个也可以,现在我需要创建一个函数,返回一个列表,其中列表的索引是过期日期,该索引的数量是具有该过期日期的食品数量。输出应该像这样:[0,2,1,1] - 第一个索引0表示没有过期日期为“0”的食品。索引1表示剩余1天的食品有2件。以此类推。我卡在了太多的if语句上,根本无法让它工作。我该如何解决?感谢您的帮助。

“expList”是每个物品的过期日期吗?您希望从该列表中获得您提到的输出吗? - Vikas Periyadath
你能说一下你现在得到的第一个输出和你需要的精确输出吗? - Vikas Periyadath
我的问题已经在下面的评论中得到了回答。感谢您的关注。expList是每个项目的过期日期,是的。 - Adam Beňko
5个回答

1
你可以遍历 Food 对象列表,并更新一个以过期日期为键、值为该过期日期对应的食品数量的字典。使用 collections.Counter 对象(它是 dict 的子类)可以避免像在列表中保留零计数这样的冗余:
from collections import Counter

d = Counter(food.expiration for food in fridge)
# fetch number of food with expiration 0
print(d[0]) # -> 0
# fetch number of food with expiration 1
print(d[1]) # -> 2

1
为了将其作为列表返回,您首先需要确定冰箱中的最大过期日期。
max_expiration = max(food.expiration for food in fridge) +1 # need +1 since 0 is also a possible expiration
exp_list = [0] * max_expiration
for food in fridge:
    exp_list[food.expiration] += 1
print(exp_list)

返回 [0, 2, 0, 1, 1]

非常感谢您的回答。您能否更详细地描述一下您的函数?即使在调试器中,我仍然很难理解它。谢谢 :) - Adam Beňko
1
当然,max(food.expiration for food in fridge)将遍历冰箱中的食物,查看过期日期并返回最大的过期日期。在您的示例中,这将是4。在您的示例中,您想返回一个长度为5的列表,您想显示0、1、2、3和4过期日期被返回的次数(因此加上1)。然后,您可以使用[0] * max_expiration这一行初始化一个包含5个零的列表。然后,您遍历冰箱中的食物,并相应地更新匹配到的过期日期的索引。 - DJanssens
非常感谢。现在我明白了 :) - Adam Beňko

1
你可以使用 itertools.groupby 来创建一个 dict,其中键将是食品过期日期,值将是它在列表中出现的次数。
>>> from itertools import groupby
>>> fridge = [Food("beer",4), Food("steak",1),  Food("hamburger",1),  Food("donut",3),]
>>> d = dict((k,len(list(v))) for k,v in groupby(sorted(l,key=lambda x: x.expiration), key=lambda x: x.expiration))

在这里,我们使用groupby指定按照相同的expiration(请注意groupby中的key参数)来分组列表的所有元素。 groupby操作的输出大致等同于(k,[v]),其中k是组键,[v]是属于该特定组的值列表。

这将产生如下输出:

>>> d
>>> {1: 2, 3: 1, 4: 1}

此时我们有一个存储在字典 d 中的过期时间和特定过期时间出现次数的列表。

接下来,我们需要创建一个列表,如果元素在字典 d 中存在,则输出该元素,否则输出 0。我们需要从 0 迭代到字典 d 键的最大数字。为了做到这一点,我们可以执行以下操作:

>>> [0 if not d.get(x) else d.get(x) for x in range(0, max(d.keys())+1)]

这将产生您所需的输出

>>> [0,2,0,1,1]

0

这里有一个使用collections.defaultdict的灵活方法:

from collections import defaultdict

def ReverseDictionary(input_dict):
    reversed_dict = defaultdict(set)
    for k, v in input_dict.items():
        reversed_dict[v].add(k)
    return reversed_dict

fridge_dict = {f.name: f.expiration for f in fridge}

exp_food = ReverseDictionary(fridge_dict)
# defaultdict(set, {1: {'hamburger', 'steak'}, 3: {'donut'}, 4: {'beer'}})

exp_count = {k: len(exp_food.get(k, set())) for k in range(max(exp_food)+1)}
# {0: 0, 1: 2, 2: 0, 3: 1, 4: 1}

0

使用count()函数修改你的代码。

def exp(fridge):
    output = []
    exp_list = [i.expiration for i in fridge]
    for i in range(0, max(exp_list)+1):
        output.append(exp_list.count(i))
    return output

谢谢你的答案。你能否请解释一下,你的代码是如何工作的? - Adam Beňko
我发现如果过期时间的最大值大于冰箱长度,那么就会出错。因此,我将其从range(0, len(fridge)+1)修改为range(0, max(exp_list)+1 ) - wipi
1
无论如何,创建一个包含所有到期日期的列表,并从0迭代到最大到期日期。count()是用于计算列表中特定项数目的函数,在循环中它将按顺序将到期日期的计数附加到输出列表中,例如output[0] = exp_list.count(0)等等。 - wipi

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接