【问题标题】:Using Insertion sort to sort list of dictionary使用插入排序对字典列表进行排序
【发布时间】:2014-03-26 16:27:06
【问题描述】:

这种排序是出于教育目的。不允许内置排序。

如果您认为我的问题和答案有帮助,请投票给我和第一个回答的人: @J.F.塞巴斯蒂安

我在 SO 上找到了这个—— "How to do an insertion sort on a list of dictionaries in python?"

但这个答案似乎不对。

使用上述问题的答案代码会引发此错误:

TypeError:列表索引必须是整数,而不是字典

例子:

lst = [{'a':20, 'b':30, 'c':25, 'd': 600},{'a':60, 'b':10, 'c':43, 'd': 20}]`

使用插入排序进行排序,例如排序b,我们应该得到

[{'a':60, 'b':10, 'c':43, 'd': 20},{'a':20, 'b':30, 'c':25, 'd': 600}]

但是我的代码得到了

[{'b': 10, 'c': 25, 'a': 20, 'd': 600}, {'b': 30, 'c': 43, 'a': 60, 'd': 20}]

他替换了字典列表中的键和值

这是我的代码:

def insertionSort(allData, key):

    for i in range(len(allData)):
        temp = allData[i][key]
        j = i
        while j > 0 and temp < allData[j - 1][key]:
               allData[j][key] = allData[j - 1][key]
               j = j - 1
        allData[j][key] = temp

我的作业排序结果:

{'snow': 19.2, 'minT': -10.8, 'month': 12, 'maxT': 9.0, 'rain': 45.0, 'year': 2003, 'meanT': -0.1, 'yearmonth': 193801}
{'snow': 35.6, 'minT': -20.0, 'month': 1, 'maxT': 8.9, 'rain': 34.3, 'year': 1974, 'meanT': -5.9, 'yearmonth': 193802}
{'snow': 0.0, 'minT': 9.7, 'month': 8, 'maxT': 34.8, 'rain': 20.8, 'year': 2007, 'meanT': 22.4, 'yearmonth': 193803}`

yearmonth进行排序后,他们将yearmonth从小到大替换,但不改变字典。

为什么会发生这种情况,我应该如何改变它?

===================================

答案:

在“J.F.”的一些基本副本之后。塞巴斯蒂安密码 我发现我不能直接使用代码

sort(a,b)

输出:

TypeError: 'str' 对象不可调用

我应该使用 排序(a,b=lambda x: x['thekey']) 然后,JFS 制作了一个新函数来使其工作。

我还找到了另一种方法: 只需更改 JFS 代码第 5 行:

来自

    if key(L[j]) <= key(d):

    if L[j][key] <= d[key]:

然后一切正常! 希望这也可以帮助其他人,以及那些使用谷歌并与我做相同任务的人。

【问题讨论】:

  • 我不太明白这个问题。这是关于如何对字典列表进行排序,比较该列表中所有字典中存在的给定键的值?
  • 字典的排序标准是什么?内置 sorted 返回第二个结果(如果字典相同)。注意:inside 字典的键是无序的,即{'a':1, 'b':2}{'b':2, 'a':1} 是相同的。
  • 问题是我如何通过字典中的键值对dict列表进行排序
  • @J.F.Sebastian - 重点是不允许使用内置排序。

标签: python sorting python-3.x dictionary


【解决方案1】:

尝试编写一个适用于整数列表的插入排序过程。然后很容易修改它以接受key 参数,以允许任意比较:

def insertion_sort_impl(L, *, key):
    for i in range(1, len(L)): # loop-invariant: `L[:i]` is sorted
        d = L[i]
        for j in range(i - 1, -1, -1): 
            if key(L[j]) <= key(d): 
               break
            L[j + 1] = L[j]
        else: # `key(L[j]) > key(d)` for all `j`
            j -= 1
        L[j + 1] = d

例子:

lst = [{'a':20, 'b':30, 'c':25, 'd': 600},{'a':60, 'b':10, 'c':43, 'd': 20}]
insertion_sort_impl(lst, key=lambda x: x['d']) # sort by `d` key
print(lst)

输出

[{'a': 60, 'c': 43, 'b': 10, 'd': 20}, {'a': 20, 'c': 25, 'b': 30, 'd': 600}]

注意:忽略字典中键的顺序。它可能会随着运行而变化,但具有较小值的键 d 的字典将始终位于左侧。

insertion_sort_impl() 函数的名称 key 与字典键无关。这是许多内置函数使用的命名约定; key 用于获取用于比较的值:

>>> max([1, 2], key=lambda x: -x)
1
>>> min([1, -2], key=lambda x: x*x)
1
>>> sorted([-1, 0, 1], key=lambda x: x*x-x)
[0, 1, -1]

要了解为什么循环从1 开始,您可以阅读Insertion sort 的一般描述。

如果insertion_sort函数的接口是固定的,那么你可以用insertion_sort_impl来定义它:

from operator import itemgetter

def insertion_sort(L, key):
    return insertion_sort_impl(L, key=itemgetter(key))

【讨论】:

  • 您好,问题是,在 sort(L, key) 中,key 是从另一个函数调用的。我将得到的是 key='a'。例如,函数是 isort(abc, 'a') 而不是 isort(abc, key=lambda x: x['a'])。比它会引发“TypeError:'str' object is not callable”。使用 insert_sort(lst, key=lambda x: x['d']) 时。一切正常。那么如何让 sort(lst, 'key') 也能正常工作呢?我什至不明白为什么我的范围从 1 开始。你能解释一下吗?我是菜鸟:)
  • @MarquisRandell:阅读我帖子中的“按'd' 键排序。您认为该行中应该更改什么以按'a' 键排序?注意:lambda x: x['d']类似于operator.itemgetter('d')
  • @MarquisRandell:我在答案中添加了算法一般描述的链接
  • 我的意思是当使用 sort(abc, 'd') 时不起作用,但 sort(abc, key=lambda x: x['d']) 起作用了。但我的关键是通过不修改代码老师来控制。这是称为 -->insertion_sort(lst, 'd') 的主要函数。然后出现“TypeError:'str'对象不可调用”
  • @MarquisRandell:我已经添加了关于为什么在insertion_sort_impl() 函数中将 key 命名为 key 的解释。
猜你喜欢
  • 2014-02-14
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多