【问题标题】:Sort list of dictionaries by appearance of key in a second ordered list按在第二个有序列表中出现的键对字典列表进行排序
【发布时间】:2014-09-30 16:56:48
【问题描述】:

我有两个列表。我的第一个列表 first_list_ordered 包含字符串。

first_list_ordered = ["id1", "id2", "id3", "id4", "id5", "id6", "id7"]

我的第二个列表second_list_unsorted 包含至少有一个名为id 的键的字典,其中的值可能出现在first_list_ordered 中。

second_list_unordered = [{"id": "id6", "content": "sth"},
                         {"id": "id4", "content": "sth"},
                         {"id": "id1", "content": "sth"},
                         {"id": "id3", "content": "sth"}]

现在我想按照id 在第一个列表中的值的出现顺序对第二个列表进行排序。 结果应如下所示:

result = [{"id": "id1", "content": "sth"},
          {"id": "id3", "content": "sth"},
          {"id": "id4", "content": "sth"},
          {"id": "id6", "content": "sth"}]

因此,如果您为second_list_unordered 中的每个字典创建所有值id 的列表,您将获得first_list_ordered 的无序子集。

我的方法如下:

>>> first_list_ordered = ["id1", "id2", "id3", "id4", "id5", "id6", "id7"]
>>> second_list_unordered = [{"id": "id6", "content": "sth"}, {"id": "id4", "content": "sth"}, {"id": "id1", "content": "sth"}, {"id": "id3", "content": "sth"}]
>>> indices = {c: i for i, c in enumerate(first_list_ordered)}
>>> result = sorted(second_list_unordered, key=indices.get)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: unhashable type: 'dict'

显然它不能那样工作......现在我被卡住了。

感谢任何提示!

【问题讨论】:

    标签: python list sorting python-3.x dictionary


    【解决方案1】:

    您需要将id 键传递给indices.get,而不是整个字典:

    result = sorted(second_list_unordered, key=lambda d: indices.get(d['id']))
    

    演示:

    >>> from pprint import pprint
    >>> first_list_ordered = ["id1", "id2", "id3", "id4", "id5", "id6", "id7"]
    >>> second_list_unordered = [{"id": "id6", "content": "sth"},
    ...                          {"id": "id4", "content": "sth"},
    ...                          {"id": "id1", "content": "sth"},
    ...                          {"id": "id3", "content": "sth"}]
    >>> indices = {c: i for i, c in enumerate(first_list_ordered)}
    >>> sorted(second_list_unordered, key=lambda d: indices.get(d['id']))
    [{'content': 'sth', 'id': 'id1'}, {'content': 'sth', 'id': 'id3'}, {'content': 'sth', 'id': 'id4'}, {'content': 'sth', 'id': 'id6'}]
    >>> pprint(_)
    [{'content': 'sth', 'id': 'id1'},
     {'content': 'sth', 'id': 'id3'},
     {'content': 'sth', 'id': 'id4'},
     {'content': 'sth', 'id': 'id6'}]
    

    为了让它更有趣一点,改组first_list_ordered,因为id 值的排序顺序有点模糊了目的:

    >>> import random
    >>> random.shuffle(first_list_ordered)
    >>> first_list_ordered
    ['id2', 'id7', 'id1', 'id4', 'id6', 'id5', 'id3']
    >>> indices = {c: i for i, c in enumerate(first_list_ordered)}
    >>> sorted(second_list_unordered, key=lambda d: indices.get(d['id']))
    [{'content': 'sth', 'id': 'id1'}, {'content': 'sth', 'id': 'id4'}, {'content': 'sth', 'id': 'id6'}, {'content': 'sth', 'id': 'id3'}]
    >>> pprint(_)
    [{'content': 'sth', 'id': 'id1'},
     {'content': 'sth', 'id': 'id4'},
     {'content': 'sth', 'id': 'id6'},
     {'content': 'sth', 'id': 'id3'}]
    

    【讨论】:

      【解决方案2】:

      如果速度不是问题,那为什么不手动呢?

      这里又便宜又脏。

      In [55]: second_list_unordered = [{"id": "id6", "content": "sth"}, {"id": "id4", "content": "sth"}, {"id": "id1", "content": "sth"}, {"id": "id3", "content": "sth"}]
      
      In [56]: first_list_ordered = ["id1", "id2", "id3", "id4", "id5", "id6", "id7"]
      In [57]: f = first_list_ordered
      
      In [58]: s = second_list_unordered
      
      In [59]: [oval[0] for oval in [[val for val in s if (val["id"] == key)] for key in f] if oval]
      Out[59]: 
      [{'content': 'sth', 'id': 'id1'},
       {'content': 'sth', 'id': 'id3'},
       {'content': 'sth', 'id': 'id4'},
       {'content': 'sth', 'id': 'id6'}]
      
      In [60]: fff = ["id3", "id4", "id5", "id2", "id1", "id6", "id7"]
      
      In [61]: [oval[0] for oval in [[val for val in s if (val["id"] == key)] for key in fff] if oval]
      Out[61]: 
      [{'content': 'sth', 'id': 'id3'},
       {'content': 'sth', 'id': 'id4'},
       {'content': 'sth', 'id': 'id1'},
       {'content': 'sth', 'id': 'id6'}]
      

      相同,但为了便于理解,分为两个操作:

      In [62]: temp = [[val for val in s if (val["id"] == key)] for key in f]
      
      In [63]: [val[0] for val in temp if val]
      Out[63]: 
      [{'content': 'sth', 'id': 'id1'},
       {'content': 'sth', 'id': 'id3'},
       {'content': 'sth', 'id': 'id4'},
       {'content': 'sth', 'id': 'id6'}]
      

      【讨论】:

      • sorted()函数帮你搞定,为什么还要手动呢?
      • 有时手动执行这些算法操作会让人耳目一新:)。否则,是的,没有理由。
      猜你喜欢
      • 2014-02-11
      • 1970-01-01
      • 2019-12-30
      • 2011-01-16
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多