【问题标题】:Python: Sorting a list by class objectsPython:按类对象对列表进行排序
【发布时间】:2013-10-11 02:06:59
【问题描述】:

正在为 CS1 开发一个项目,我快要破解它了,但是这部分代码让我很难过!该项目的目标是通过引用一个包含数千个名字的文件来创建任何给定年份的前 20 个名字的列表。每个文件中的每一行都包含名称、性别和出现的次数。该文件按性别分隔(因此女性姓名按出现顺序排列,男性姓名按出现顺序排列)。我已经得到了代码,每个条目都包含在列表中的一个类中(所以这个列表是一长串内存条目)。这是我到目前为止的代码。

class entry():
    __slots__ = ('name' , 'sex' , 'occ')

def mkEntry( name, sex, occ ):
    dat = entry()
    dat.name = name
    dat.sex = sex
    dat.occ = occ
    return dat

##test = mkEntry('Mary', 'F', '7065')
##print(test.name, test.sex, test.occ)

def readFile(fileName):
    fullset = []
    for line in open(fileName):
        val = line.split(",")
        sett = mkEntry(val[0] , val[1] , int(val[2]))
        fullset.append(sett)
    return fullset

fullset = readFile("names/yob1880.txt")
print(fullset)

我现在想知道是否可以通过使用 sort() 或其他函数对列表进行排序,但是按列表的出现次数(每个条目中的 dat.occ)对列表进行排序,以便最终结果我将有一个独立于性别排序的列表,然后我可以打印列表中的第一个条目,因为它们应该是我正在寻找的。是否可以像这样对列表进行排序?

【问题讨论】:

    标签: python list class sorting


    【解决方案1】:

    是的,您可以使用sort() 对对象列表进行排序。 sort() 将函数作为可选参数 key。在进行比较之前,key 函数将应用于列表中的每个元素。例如,如果您想按绝对值对整数列表进行排序,您可以执行以下操作

    >>> a = [-5, 4, 6, -2, 3, 1]
    >>> a.sort(key=abs)
    >>> a
    [1, -2, 3, 4, -5, 6]
    

    在您的情况下,您需要一个自定义 key 来提取每个对象的出现次数,例如

    def get_occ(d): return d.occ
    fullset.sort(key=get_occ)
    

    (您也可以使用匿名函数:fullset.sort(key=lambda d: d.occ))。然后你只需要从这个列表中提取前 20 个元素。

    请注意,默认情况下 sort 按升序返回元素,您可以对其进行操作,例如fullset.sort(key=get_occ, reverse=True)

    【讨论】:

    • 这很完美!非常感谢^.^我们还没有了解关键功能但是很不幸,如果我的教授不接受,我可能不得不找到一种全新的方法 D:但感谢您向我展示它:)
    【解决方案2】:

    这使用occ 属性按降序对列表进行排序:

    fullset.sort(key=lambda x: x.occ, reverse=True)
    

    【讨论】:

      【解决方案3】:

      您的意思是您只想按 occ 对列表进行排序? sort() 有一个名为key 的参数,你可以这样做:
      fullset.sort(key=lambda x: x.occ)

      【讨论】:

        【解决方案4】:

        我想你只是想对每个对象的 'occ' 属性的值进行排序,对吧?您只需对 Python 可用的各种排序函数中的任何一个使用 key 关键字参数。例如

        getocc = lambda entry: entry.occ
        sorted(fullset, key=getocc)
        # or, for in-place sorting
        fullset.sort(key=getocc)
        

        或者有些人可能认为使用 operator.attrgetter 而不是自定义 lambda 更符合 Python 风格:

        import operator
        getocc = operator.attrgetter('occ')
        sorted(fullset, key=getocc)
        

        但听起来列表很大。如果您只想要列表中的前几个条目,则排序可能是一项不必要的昂贵操作。例如,如果你只想要 first 值,你可以在 O(N) 时间内得到它:

        min(fullset, key=getocc) # Same getocc as above
        

        如果你想要前三个,比如说,你可以use a heap 而不是排序。

        import heapq
        heapq.nsmallest(3, fullset, key=getocc)
        

        堆是一种有用的数据结构,用于从列表中获取有序元素的切片,而无需对整个列表进行排序。以上等价于sorted(fullset, key=getocc)[:3],但如果列表很大,则速度更快。

        希望很明显,您可以使用heapq.nlargest 和相同的参数获得最大的三个。同样,您可以反转任何排序或将min 替换为max

        【讨论】:

        • 我真的不认为operator.*getter 工具特别 Pythonic,尽管人们似乎出于某种原因喜欢它们。有一点性能上的好处,但它们非常脆弱:当你想要对结果做任何有趣的事情时,你无论如何都必须使用一个函数。
        • @DSM 我不同意,我认为他们的力量在于他们的专业化。如果他们是一般的,他们会因为太 TIMTOWDI 而变得不合情理。
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2021-01-25
        • 1970-01-01
        • 2012-06-26
        相关资源
        最近更新 更多