Slicing a dictionary

后端 未结 6 897
后悔当初
后悔当初 2020-12-02 10:28

I have a dictionary, and would like to pass a part of it to a function, that part being given by a list (or tuple) of keys. Like so:

# the dictionary
d = {1:         


        
相关标签:
6条回答
  • 2020-12-02 10:56

    You should be iterating over the tuple and checking if the key is in the dict not the other way around, if you don't check if the key exists and it is not in the dict you are going to get a key error:

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

    Some timings:

     {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
    

    I don't see how {k:d[k] for k in l} is not readable or elegant and if all elements are in d then it is pretty efficient.

    0 讨论(0)
  • 2020-12-02 10:59

    On Python 3 you can use the itertools islice to slice the dict.items() iterator

    import itertools
    
    d = {1: 2, 3: 4, 5: 6}
    
    dict(itertools.islice(d.items(), 2))
    
    {1: 2, 3: 4}
    

    Note: this solution does not take into account specific keys. It slices by internal ordering of d, which in Python 3.7+ is guaranteed to be insertion-ordered.

    0 讨论(0)
  • 2020-12-02 11:06

    Use a set to intersect on the dict.viewkeys() dictionary view:

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

    This is Python 2 syntax, in Python 3 use d.keys().

    This still uses a loop, but at least the dictionary comprehension is a lot more readable. Using set intersections is very efficient, even if d or l is large.

    Demo:

    >>> 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}
    
    0 讨论(0)
  • 2020-12-02 11:07

    Write a dict subclass that accepts a list of keys as an "item" and returns a "slice" of the dictionary:

    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)
    

    Usage:

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

    Or if you want to use a separate method for this type of access, you can use * to accept any number of arguments:

    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
    
    0 讨论(0)
  • 2020-12-02 11:11

    the dictionary

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

    the subset of keys I'm interested in

    l = (1,5)
    

    answer

    {key: d[key] for key in l}
    
    0 讨论(0)
  • 2020-12-02 11:18

    set intersection and dict comprehension can be used here

    # 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}
    
    0 讨论(0)
提交回复
热议问题