2

I have a dictionary with tuples as keys (containing a string and an int) and floats as values. An example:

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

Now, I need to make a new dictionary, which has the original dictionary key's second element as it's key. The new dictionary's value should be the the place it stands if the keys were sorted. Added to this, there are two exceptions:

  1. If two dicts have values that are equal, but have different strings in the key, the one with the lowest int in the key should be placed higher.

  2. If two dicts have values that are equal, but have different ints in the key, they should be placed equal in the new dict and all get the same values.

So, the new dictionary should be as the following:

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

I know that it's ignorant to ask someone else to solve my problem without giving my code for it. But i'm simply don't know how to approach the problem. I would be glad if you could provide me with an explanation how would you solve this problem , or even give me a pseudocode of the algorithm.

4

3 回答 3

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)键进行排序。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因为当值相同时有特殊规则first[k]。可以使用itertools.groupby来实现分组:

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.groupbyordered正在根据键的值将项目收集成束, 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

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

previous = None
for name, num in group:
    if name != previous:
        counter += 1
    ...
    previous = name   

警告:请注意,rkd91 的代码和我的代码会产生不同的答案

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

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

@rdk91 的代码产生

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

我的代码产生

{1: 4, 2: 2, 3: 3, 4: 5, 6: 1}
于 2013-02-13T21:53:22.077 回答
2

1)使用获取键值元组列表first_list = first.items()

2) 创建一个自定义比较器函数,该函数将根据您的标准对列表进行排序。

3)使用排序列表first_list.sort(comparator)

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

于 2013-02-13T21:39:01.510 回答
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}
于 2013-02-13T21:55:44.503 回答