切片字典

时间:2015-03-23 17:45:26

标签: python dictionary

我有一个字典,并希望将其中一部分传递给一个函数,该部分由一个列表(或元组)给出。像这样:

# the dictionary
d = {1:2, 3:4, 5:6, 7:8}

# the subset of keys I'm interested in
l = (1,5)

现在,理想情况下,我希望能够做到这一点:

>>> d[l]
{1:2, 5:6}

...但这不起作用,因为它会查找名为(1,5)的密钥。 并且d[1,5]甚至不是有效的Python(虽然它看起来很方便)。

我知道我可以这样做:

>>> dict([(key, value) for key,value in d.iteritems() if key in l])
{1: 2, 5: 6}

或者这个:

>>> dict([(key, d[key]) for key in l])

更紧凑 ......但我觉得必须有一个更好的"这样做的方式。我错过了一个更优雅的解决方案吗?

(我使用的是Python 2.7)

7 个答案:

答案 0 :(得分:25)

你应该迭代元组并检查密钥是否在dict中,而不是相反,如果你不检查密钥是否存在而且它不在dict中你将得到一个密钥错误:

print({k:d[k] for k in l if k in d})

一些时间:

 {k:d[k] for k in set(d).intersection(l)}

In [22]: %%timeit                        
l = xrange(100000)
{k:d[k] for k in l}
   ....: 
100 loops, best of 3: 11.5 ms per loop

In [23]: %%timeit                        
l = xrange(100000)
{k:d[k] for k in set(d).intersection(l)}
   ....: 
10 loops, best of 3: 20.4 ms per loop

In [24]: %%timeit                        
l = xrange(100000)
l = set(l)                              
{key: d[key] for key in d.viewkeys() & l}
   ....: 
10 loops, best of 3: 24.7 ms per

In [25]: %%timeit                        

l = xrange(100000)
{k:d[k] for k in l if k in d}
   ....: 
100 loops, best of 3: 17.9 ms per loop

我不知道{k:d[k] for k in l}如何不可读或优雅,如果所有元素都在d中,那么效率非常高。

答案 1 :(得分:17)

使用一个集合在dict.viewkeys() dictionary view

上相交
l = {1, 5}
{key: d[key] for key in d.viewkeys() & l}

这是Python 2语法,在Python 3中使用d.keys()

这仍然使用循环,但至少字典理解更具可读性。即使dl很大,使用集合交叉也非常有效。

演示:

>>> d = {1:2, 3:4, 5:6, 7:8}
>>> l = {1, 5}
>>> {key: d[key] for key in d.viewkeys() & l}
{1: 2, 5: 6}

答案 2 :(得分:15)

在Python 3上,你可以使用itertools islice来切片dict.items()迭代器

import itertools

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

dict(itertools.islice(d.items(), 2))

{1: 2, 3: 4}

注意:此解决方案会考虑特定密钥。它按d的内部排序进行切片,在Python 3.7+中保证按插入顺序排列。

答案 3 :(得分:7)

编写一个dict子类,接受一个键列表作为"项目"并返回"切片"字典:

class SliceableDict(dict):
    default = None
    def __getitem__(self, key):
        if isinstance(key, list):   # use one return statement below
            # uses default value if a key does not exist
            return {k: self.get(k, self.default) for k in key}
            # raises KeyError if a key does not exist
            return {k: self[k] for k in key}
            # omits key if it does not exist
            return {k: self[k] for k in key if k in self}
        return dict.get(self, key)

用法:

d = SliceableDict({1:2, 3:4, 5:6, 7:8})
d[[1, 5]]   # {1: 2, 5: 6}

或者,如果您想为此类访问使用单独的方法,可以使用*接受任意数量的参数:

class SliceableDict(dict):
    def slice(self, *keys):
        return {k: self[k] for k in keys}
        # or one of the others from the first example

d = SliceableDict({1:2, 3:4, 5:6, 7:8})
d.slice(1, 5)     # {1: 2, 5: 6}
keys = 1, 5
d.slice(*keys)    # same

答案 4 :(得分:7)

要对字典进行切片,请使用 d.items() 将其转换为元组列表,对列表进行切片并从中创建字典。

这里。

d = {1:2, 3:4, 5:6, 7:8}

获取前两个项目

first_two = dict(list(d.items())[:2])

first_two

{1: 2, 3: 4}

答案 5 :(得分:3)

字典

d = {1:2, 3:4, 5:6, 7:8}

我感兴趣的键的子集

l = (1,5)

answer

{key: d[key] for key in l}

答案 6 :(得分:2)

set intersectiondict comprehension可以在这里使用

# the dictionary
d = {1:2, 3:4, 5:6, 7:8}

# the subset of keys I'm interested in
l = (1,5)

>>>{key:d[key] for key in set(l) & set(d)}
{1: 2, 5: 6}