字典值排序

时间:2013-02-13 21:19:38

标签: python dictionary

我有一个字典,其中元组作为键(包含字符串和int)并浮动为值。一个例子:

first = {}
first['monkey', 1] = 130.0 
first['dog', 2] = 123.0-
first['cat', 3] = 130.0
first['cat', 4] = 130.0
first['mouse', 6] = 100.0

现在,我需要创建一个新的字典,其原始字典键的第二个元素为 这是关键。如果键被排序,新词典的值应该是它所代表的位置。除此之外,还有两个例外:

  1. 如果两个dicts的值相等,但键中的字符串不同,则键中int值最低的那个应该放在更高的位置。

  2. 如果两个dicts的值相等但在键中具有不同的int,则它们应该在新dict中相等,并且所有值都相同。
  3. 因此,新词典应如下所示:

    second[1] = 3
    second[2] = 2
    second[3] = 4
    second[4] = 4
    second[6] = 1
    

    我知道要求别人解决我的问题而不提供我的代码是无知的。 但我只是不知道如何处理这个问题。如果你能给我一个解释如何解决这个问题,甚至给我一个算法的伪代码,我会很高兴。

3 个答案:

答案 0 :(得分:3)

import itertools as IT

first = {
    ('monkey',1): 130.0,
    ('dog',2): 123.0,
    ('cat', 3): 130.0,
    ('cat', 4): 130.0,
    ('mouse', 6): 100.0
    }

counter = 0
ordered = sorted(first, key = lambda k: (first[k], k[1], k[0]))

second = {}
for key, group in IT.groupby(ordered, first.__getitem__):
    # group = list(group)
    # print(key, group)
    # (100.0, [('mouse', 6)])
    # (123.0, [('dog', 2)])
    # (130.0, [('monkey', 1), ('cat', 3), ('cat', 4)])
    previous = None
    for name, num in group:
        if name != previous:
            counter += 1
        second[num] = counter
        previous = name

print(second)

产量

{1: 3, 2: 2, 3: 4, 4: 4, 6: 1}

<强>解释

第一步是根据相关值对(name, num)的{​​{1}}键进行排序。但是,如果是关系,则使用first。如果仍有平局,num用于打破平局。

name

接下来,我们需要对In [96]: ordered = sorted(first, key = lambda k: (first[k], k[1], k[0])) In [97]: ordered Out[97]: [('mouse', 6), ('dog', 2), ('monkey', 1), ('cat', 3), ('cat', 4)] 中的项目进行分组,因为当ordered值相同时存在特殊规则。可以使用itertools.groupby

来实现分组
first[k]

In [99]: for key, group in IT.groupby(ordered, first.__getitem__): ....: print(key, list(group)) ....: ....: (100.0, [('mouse', 6)]) (123.0, [('dog', 2)]) (130.0, [('monkey', 1), ('cat', 3), ('cat', 4)]) 根据密钥itertools.groupby的值将ordered中的项目收集到一起。例如,

first.__getitem__(item)

In [100]: first.__getitem__(('monkey', 1)) Out[100]: 130.0 In [101]: first.__getitem__(('cat', 3)) Out[101]: 130.0 只是写first.__getitem__(item)的一种奇特方式。我使用first[item]的原因是因为first.__getitem__期望第二个参数有一个函数,而itertools.groupby是适合该法案的函数。


最后,我们遍历每个组。基本上,我们想要这样做:

first.__getitem__

外,当名称相同时,我们不想推进计数器。因此,要检查名称是否相等,有助于存储以前的名称:

for name, num in group:
    counter += 1
    second[num] = counter

警告:请注意,rkd91的代码和我的代码会为

生成不同的答案
previous = None
for name, num in group:
    if name != previous:
        counter += 1
    ...
    previous = name   

可能是由于对规范的不同解释。我会留给你做决定哪个产生所需的输出。

@ rdk91的代码产量

first = {
    ('monkey',1): 130.0,
    ('dog',2): 123.0,
    ('cat', 3): 129.0,
    ('cat', 4): 130.0,
    ('mouse', 6): 100.0
    }

我的代码产生

{1: 4, 2: 2, 3: 5, 4: 3, 6: 1}

答案 1 :(得分:2)

1)使用first_list = first.items()

获取键值元组列表

2)创建一个custom comparator function,根据您的标准对列表进行排序。

3)使用first_list.sort(comparator)

对列表进行排序

4)从排序列表中构建新词典。

答案 2 :(得分:1)

rob@rivertam:~/Programming$ cat sorter.py 
first = {}
first['monkey', 1] = 130.0
first['dog', 2] = 123.0
first['cat', 3] = 130.0
first['cat', 4] = 130.0
first['mouse', 6] = 100.0

# Get the keys of first, sorted by the value (ascending order), and then by the integer in the key (descending order) if two keys have the same value

s = sorted(first, key=lambda x: x[0])
s.reverse()
s = sorted(s, key=lambda x: first[x])

# Loop through these, and create a new list where the key is the integer in the old key, and the value is the position in the sorted order.

last_val = None
last = (None, None)
index = 0
new_dict = {}

for item in s:
    if not ((first[item] == last_val) and (item[1] != last[1]) and item[0] == last[0]):
        # When we have the same value, the same string but a different integer from the last key, consider it to be the same position in the sorted order.
        index += 1
    new_dict[item[1]] = index
    last_val = first[item]
    last = item

print new_dict
rob@rivertam:~/Programming$ python sorter.py 
{1: 3, 2: 2, 3: 4, 4: 4, 6: 1}