切片字典

Zak*_*Zak 38 python dictionary

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

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

# the subset of keys I'm interested in
l = (1,5)
Run Code Online (Sandbox Code Playgroud)

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

>>> d[l]
{1:2, 5:6}
Run Code Online (Sandbox Code Playgroud)

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

我知道我可以这样做:

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

或这个:

>>> dict([(key, d[key]) for key in l])
Run Code Online (Sandbox Code Playgroud)

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

(我使用的是Python 2.7)

Pad*_*ham 27

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

print({k:d[k] for k in l if k in d})
Run Code Online (Sandbox Code Playgroud)

一些时间:

 {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
Run Code Online (Sandbox Code Playgroud)

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

  • 在这种情况下,我认为[Perl](/sf/answers/68549351/)和[Ruby](/sf/answers/905924631/)都提供了更“优雅”的解决方案。 (4认同)
  • 感谢您的时间安排!{{k:d [k] for k in l}}对于具有一定经验的人(比我的问题中稍微复杂的版本更合理)可读,但类似于d.intersect(l) ``会更好:有一个字典,一个列表,我正在为他们做一些事情,无需三次提及k,这既不是操作的输入也不是输出。我知道我在抱怨很高:) (2认同)

Ces*_*ssa 23

在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}
Run Code Online (Sandbox Code Playgroud)

注意:此解决方案并没有考虑到特定按键.它按内部排序切片d,在Python 3.7+中保证按插入顺序排列.

  • 这个答案与问题无关. (5认同)
  • 所以......这会给我前两个元素,对吧?Python 3 中的字典是否以某种方式排序?因为否则不知道将返回哪些元素,并且它只能对连续的元素起作用,当我真的希望通过键列表选择它们时 (2认同)

Mar*_*ers 18

使用集合在dict.viewkeys()字典视图上相交:

l = {1, 5}
{key: d[key] for key in d.viewkeys() & l}
Run Code Online (Sandbox Code Playgroud)

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

这仍然使用循环,但至少字典理解更具可读性.使用集合交叉点非常有效,即使d或者l很大.

演示:

>>> 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}
Run Code Online (Sandbox Code Playgroud)

  • @itzmeontv:那么如果`l` 很大而`d` 很小呢?只需将其留给 Python 即可创建交集,而无需自己循环。 (2认同)

小智 12

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

这里。

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

获取前 2 个项目

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

第一个_两个

{1: 2, 3: 4}

  • 我喜欢这个答案。它完全回答了我正在寻找的标题“切片字典”。 (2认同)
  • 简单直接的答案,是最好的答案。+1 (2认同)

kin*_*all 8

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

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)
Run Code Online (Sandbox Code Playgroud)

用法:

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

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

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
Run Code Online (Sandbox Code Playgroud)


itz*_*nTV 6

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}
Run Code Online (Sandbox Code Playgroud)