【问题标题】:slicing dictionary with values用值切片字典
【发布时间】:2018-03-05 09:57:02
【问题描述】:

我有一本像这样的字典:

d = {1: 'a', 2:'b', 3:'c', 4:'c', 5:'c', 6:'c'}

我想对这个字典进行切片,如果最后的值相同,它应该只返回遇到的第一个值。所以返回是:

d = {1: 'a', 2:'b', 3:'c'}

我使用collections.defaultdict(OrderedDict) 来保持按键排序。

目前,我正在使用循环。有没有一种pythonic的方式来做到这一点?


更新

字典值也可以是字典:

d = {1: {'a': 'a1', 'b': 'b1'}, 2:{'a': 'a1', 'b': 'b2'}, 3:{'a': 'a1', 'b': 'c1'}, 4:{'a': 'a1', 'b': 'c1'}, 5:{'a': 'a1', 'b': 'c1'}, 6:{'a': 'a1', 'b': 'c1'}}

输出:

d = {1: {'a': 'a1', 'b': 'b1'}, 2:{'a': 'a1', 'b': 'b2'}, 3:{'a': 'a1', 'b': 'c1'}}

【问题讨论】:

  • 字典是否总是按其键排序?我看到你有 1,2,3,4,5,6 的键。如果是这样,那么使用列表代替字典是不必要的。
  • 循环是pythonic。我不会说理解总是比循环更 Pythonic,这是主观的。

标签: python dictionary ordereddictionary


【解决方案1】:

您可以使用itertools.groupy 和列表理解来实现您的结果

>>> from itertools import groupby

>>> d = {1: 'a', 2:'b', 3:'c', 4:'c', 5:'c', 6:'c'}
>>> n = [(min([k[0] for k in list(g)]),k) for k,g in groupby(d.items(),key=lambda x: x[1])]
>>> n
>>> [(1, 'a'), (2, 'b'), (3, 'c')]

上面的表达式也可以写成

 >>> from operator import itemgetter
 >>> n = [(min(map(itemgetter(0), g)), k) for k, g in groupby(d.items(), key=itemgetter(1))]

您可以将其转换为 dict,只需使用

>>> dict(n)
>>> {1: 'a', 2: 'b', 3: 'c'}

这显然不保持键的顺序,所以你可以使用OrderedDict

>>> OrderedDict(sorted(n))
>>> OrderedDict([(1, 'a'), (2, 'b'), (3, 'c')])

【讨论】:

  • 这归结为一个偏好问题,但您也可以使用operator.itemgetter:[(min(map(itemgetter(0), g)), k) for k, g in groupby(d.items(), key=itemgetter(1))]。尽管如此,我还是投了赞成票:)。
  • 谢谢!这有效,但当值也是字典时它不起作用。对不起,我已经更新了 OP
  • @AbhishekThakur 我检查了如果值为dict,它实际上正在工作。你能确认一下吗?
【解决方案2】:

如果你想摆脱 for 循环 - 你可以这样做:

{a:b for b,a in {y:x for x,y in sorted(d.iteritems(), reverse=True)}.iteritems()}

但它不是那么 Pythonic 也不是那么高效。

【讨论】:

  • 我也在想同样的事情。不确定这是否是个好主意。
  • 我会说循环的效率和可读性要好得多 =)
【解决方案3】:

与使用表示索引的键的有序字典不同,更 Python 的方式是使用列表。在这种情况下,您将使用索引而不是键,并且能够更有效地对列表进行切片。

>>> d = {1: 'a', 2:'b', 3:'c', 4:'c', 5:'c', 6:'c'}
>>> a = list(d.values())
>>> a[:a.index(a[-1])+1]
['a', 'b', 'c']

【讨论】:

    【解决方案4】:

    以防万一,pandas的解决方案

    import pandas as pd
    
    df = pd.DataFrame(dict(key=list(d.keys()),val=list(d.values())))
    print(df)
       key val
    0    1   a
    1    2   b
    2    3   c
    3    4   c
    4    5   c
    5    6   c
    
    df = df.drop_duplicates(subset=['val'])
    df.index=df.key
    df.val.to_dict()
    
    {1: 'a', 2: 'b', 3: 'c'}
    

    不知道最大数据集的性能问题,或者它是否更 Pythonic。
    然而,没有循环。

    【讨论】:

      【解决方案5】:

      您可以检查最后两个值是否相同:

      d = OrderedDict({1: 'a', 2:'b', 3:'c', 4:'c', 5:'c', 6:'c'})
      
      while d.values()[-1] == d.values()[-2]:
          d.popitem()
      
      print d
      # OrderedDict([(1, 'a'), (2, 'b'), (3, 'c')])
      

      【讨论】:

        猜你喜欢
        • 2018-12-31
        • 2015-05-26
        • 2021-09-14
        • 2017-06-03
        • 1970-01-01
        • 2021-11-19
        • 2020-09-20
        • 2020-02-08
        相关资源
        最近更新 更多