1

I'm trying to split a dict from a certain point in the dict. It seemed like doing a simple items_dict[3:] would work but it did not work.

items_dict = {
    "Cannon barrels":10,
    "Cannon furnace":12,
    "Candle":36,
    "Bronze arrowheads":39,
    "Iron arrowheads":40,
    "Steel arrowheads":41,
    "Mithril arrowheads":42,
    "Adamant arrowheads":4
}
print items_dict[3:] # Nope, this won't work
print items_dict["Candle"] # This will of course, but only returns the Candle's number

I only figured out how to slice a dictionary by keys that start with a certain string, but I just want to know how to slice a dictionary similar to a list.

Community
  • 1
  • 1
Hairr
  • 1,088
  • 2
  • 11
  • 19
  • 2
    Looks like maybe you should rethink your datastructures. I don't think it's a good idea to use an OrderedDict here. – John La Rooy May 20 '13 at 02:54

6 Answers6

4

Dictionaries don't have order, so you can't split it from a certain point. Looking at the dictionary you have there, you can't know ahead of time what the first element will be.

mgilson
  • 300,191
  • 65
  • 633
  • 696
2

If you want to split after n keys - no guarantee over the order.

n=3
d1 = {key: value for i, (key, value) in enumerate(d.items()) if i < n}
d2 = {key: value for i, (key, value) in enumerate(d.items()) if i >= n}
karthikr
  • 97,368
  • 26
  • 197
  • 188
  • `viewitems` is python2.7. `items` will work on python2 or python3. – mgilson May 20 '13 at 02:53
  • You could also do something like: `{k:d[k] for k in islice(d,...)}` – mgilson May 20 '13 at 02:54
  • Using an OrderedDict as suggested in an answer below and in the comment above, this worked just as needed! – Hairr May 20 '13 at 03:12
  • @mgilson, islice is much better, but with an `iter(d)` so you save looping over stuff multiple times. – John La Rooy May 20 '13 at 03:36
  • @gnibbler -- Sorry, you're going to need to walk me through this one a bit more. How does using `islice` cause you to loop multiple times? – mgilson May 20 '13 at 12:54
  • @mgilson, if you do `islice(d, n)` followed by `islice(d, n, None)` you will be iterating over the first `n` of `d` twice. – John La Rooy May 20 '13 at 12:59
  • @gnibbler -- Oh, I got ya. You mean to split the list into 2 parts. In that case I suppose it becomes `iterd = iter(d); {k:d[k] for k in islice(iterd,n)}; {k:d[k] for k in iterd}` – mgilson May 20 '13 at 13:03
2

If you want a dictionary where the keys are stored in order, use collections.OrderedDict

http://docs.python.org/2/library/collections.html#collections.OrderedDict

xuanji
  • 5,007
  • 2
  • 26
  • 35
1
items = [
    ("Cannon barrels",10),
    ("Cannon furnace",12),
    ("Candle",36),
    ....
   ]

items_dict = dict(items)

items_3_dict = dict(items[3:])

doesnt exactly answer your question (see @mgilson answer) , but provides a path forward

Joran Beasley
  • 110,522
  • 12
  • 160
  • 179
1
ditems = items_dict.items()
d1, d2 = dict(ditems[:3]), dict(ditems[3:])

print(d1)
print(d2)
{'Iron arrowheads': 40, 'Adamant arrowheads': 4, 'Mithril arrowheads': 42}
{'Candle': 36, 'Cannon barrels': 10, 'Steel arrowheads': 41, 'Cannon furnace': 12, 'Bronze arrowheads': 39}

Or creating a function to split an iterable about an n-th value

from itertools import islice

def split(iterable,point): 
    return islice(iterable,None,point), islice(iterable,point,None)

d1, d2 = (dict(segment) for segment in split(items_dict.items(),3))

This will split it about the third entry.

HennyH
  • 7,794
  • 2
  • 29
  • 39
  • no it wont ... a dict has no concept of "third entry" ... it will create a dict with 3 of the items and another dict with the rest ... but there is no concept of "third entry" – Joran Beasley May 20 '13 at 03:10
  • @JoranBeasley (yes it's unorderded) but it still has N (k,v) pairs which I meant by entry, so even though the 3rd pair is indeterminate it still has a third pair. – HennyH May 20 '13 at 03:19
0

You could make a custom class (example only - slicing only works for [1:4] syntax, and dict[missing_key] returns None instead of throwing an exception):

>>> class SliceDict(collections.OrderedDict):
...     def __getitem__(self, val):
...         if isinstance(val, slice):
...             return {key: value for i, (key, value) in enumerate(d.items()) if val.start < i < val.stop}
...         else:
...             return self.get(val)

Now we can add your items dict:

>>> d = SliceDict(items_dict)
SliceDict([('Adamant arrowheads', 4), ('Mithril arrowheads', 42), ('Iron arrowheads', 40), ('Candle', 36), ('Cannon barrels', 10), ('Steel arrowheads', 41), ('Cannon furnace', 12), ('Bronze arrowheads', 39)])
>>> d[1:5]
{'Candle': 36, 'Cannon barrels': 10, 'Iron arrowheads': 40}
>>> d['Candle']
36
Alex L
  • 8,748
  • 5
  • 49
  • 75