2

I have this input, where each value has a range of 200:

d = {'600-800': 3, '1800-2000': 3, '1000-1200': 5, '400-600': 1, '2600-2800': 1}

And I am looking for this expected order:

{'400-600': 1, '600-800': 3, '1000-1200': 5, '1800-2000': 3, '2600-2800': 1}

Already tried something like this, but the order is just wrong:

import collections
od = collections.OrderedDict(sorted(d.items()))
print od
anvd
  • 3,997
  • 19
  • 65
  • 126
  • Well, that's not the order `sorted()` returns your items in. So if you want a different order you should pass a sorting `key` to `sorted()` that sorts the `dict` the way you want it to be sorted. – Fynn Becker Jan 27 '19 at 14:16
  • what is your sorting criteria?? – Talha Israr Jan 27 '19 at 14:16
  • ... when your range is a constant value of `200`, why not use the minimum value as key ? `600-800` is just eye candy. – Maurice Meyer Jan 27 '19 at 14:18
  • @TalhaIsrar The order that I am expecting is ascending from the lowest range to the maximum, in the example 400-600 to 2600-2800. – anvd Jan 27 '19 at 14:18

2 Answers2

4

You can split the key into parts at '-' and use the first part as integer value to sort it. The second part is irrelevant for ordering because of the nature of your key-values (when converted to integer):

d = {'600-800': 3, '1800-2000': 3, '1000-1200': 5, '400-600': 1, '2600-2800': 1}
import collections
od = collections.OrderedDict(sorted(d.items(),key =lambda x: int(x[0].split("-")[0])))
print od

Output:

OrderedDict([('400-600', 1), ('600-800', 3), ('1000-1200', 5), 
             ('1800-2000', 3), ('2600-2800', 1)])

Doku:

Related:

Patrick Artner
  • 50,409
  • 9
  • 43
  • 69
2

If you want to order your dictionary by the first year first (and then by the second year if needed, which is unnecessary in the given example, but feels more natural), you need to convert to integers and set a custom key:

d = {'600-800': 3, '1800-2000': 3, '1000-1200': 5, '400-600': 1, '2600-2800': 1}

sorted(d.items(), key=lambda t: tuple(map(int, t[0].split("-"))))
# [('400-600', 1),
#  ('600-800', 3),
#  ('1000-1200', 5),
#  ('1800-2000', 3),
#  ('2600-2800', 1)]

The conversion to integers is needed because e.g. "1000" < "200", but 1000 > 200. This list can be passed to OrderedDict afterwards like in your code, if needed.

Graipher
  • 6,891
  • 27
  • 47
  • 1
    I like this solution because it takes both the lower and the upper bound into account. Although not specified in the question this seems like a more "natural" way to sort ranges. – Fynn Becker Jan 27 '19 at 14:25
  • 1
    In Python 2.x the output **must** be passed to `OrderedDict` to preserve the sorted order—ordinary `dict` don't preserver order before version 3.6. – martineau Jan 27 '19 at 14:33
  • @martineau: Note that my output is a list of tuples, which is ordered. You only need to pass it to `OrderedDict` if you literally want an ordered dictionary. If all you need are the keys and values in order for a loop for example, this should be fine. – Graipher Jan 27 '19 at 14:36
  • @Graipher: I know how `OrderDict`s can be created. I believe the OP wants the result to be a dictionary that preserves order (in Python 2.x)—which is why I made the comment. – martineau Jan 27 '19 at 14:39
  • @martineau: I clarified the answer a bit by stating that this can be passed to `OrderedDict` just like in the code OP showed. – Graipher Jan 27 '19 at 14:42