4

I have a need to take an integer value and index into a table of corresponding strings. In this case, contiguous ranges of integers should all map to the same string. Something like (with a non-working dictionary example):

int_dict = { 0              : "String1",
             1              : "String2",
             2              : "String3",
             range(3,15)    : "String4",
             16             : "String5"   };

As expected, using range here just fails and trying to use lists gives the error TypeError: unhashable type: 'list'.

Perhaps a dictionary is not the best data structure for this task. My question, then, is how can something like this be easily done? The ranges tend to be quite large, so doing this via manual definition (unless something like range can be used) is not an option.

sherrellbc
  • 4,650
  • 9
  • 48
  • 77
  • 5
    That's not what a dictionary is defined for. Dictionaries do equality checks. You can use a datastructure called an *interval tree*, which does lookup in *O(log n)*. – Willem Van Onsem Jun 15 '17 at 11:28
  • @WillemVanOnsem, That was my original conclusion. There seems to be ways to [make it work](https://stackoverflow.com/questions/2974022/is-it-possible-to-assign-the-same-value-to-multiple-keys-in-a-dict-object-at-onc#2974082), though. I'll check out _interval trees_. – sherrellbc Jun 15 '17 at 11:29
  • 3
    yes but this will simply generate a key for every element in `range(..)` so if you range over millions of elements, the dictionary will blow up. Of course that will work (given Python has enough memory). – Willem Van Onsem Jun 15 '17 at 11:31
  • How about a list of tuples – khelili miliana Jun 15 '17 at 11:31
  • @KHELILIHamza Then you'll need the tuple for lookup, not a single value. – Moses Koledoye Jun 15 '17 at 11:32
  • @KHELILIHamza, The underlying data structure is less important. I effectively need something that provides `datastruct[5] => "TheString"`. – sherrellbc Jun 15 '17 at 11:32
  • https://stackoverflow.com/questions/39358092/range-as-dictionary-key-in-python – Anup Jun 15 '17 at 11:49

5 Answers5

3

Is it what you want to achieve ?

int_dict = { 0              : "String1",
             1              : "String2",
             2              : "String3",
             16             : "String5"   };
#range is first inclusive last exlusif, watch out for that
for i in range(3,15)    :
    int_dict[i] = "String4"

output :

{0: 'String1',
 1: 'String2',
 2: 'String3',
 3: 'String4',
 4: 'String4',
 5: 'String4',
 6: 'String4',
 7: 'String4',
 8: 'String4',
 9: 'String4',
 10: 'String4',
 11: 'String4',
 12: 'String4',
 13: 'String4',
 14: 'String4',
 16: 'String5'}

Edit : you can also use tuple as key

int_dict = { (0,0)              : "String1",
             (1,1)              : "String2",
             (2,2)              : "String3",
              (3,15)             :"String4",
             (16,16)             : "String5"};

def ValueInDict(value):
    for i,j in int_dict.items():
        if value >= i[0]:
            if value <= i[1]:
                print(j)
                return
    print("NOT THERE")

ValueInDict(5)

ouput :

 String4
Tbaki
  • 1,013
  • 7
  • 12
  • This is useful, but I was hoping there may be some supported syntax for doing this. Like using `range`. Thanks for the reply. – sherrellbc Jun 15 '17 at 11:31
  • @sherrellbc, maybe you can use tuple as key ? then you can check if it is within – Tbaki Jun 15 '17 at 11:33
1

I don't think there is a special syntax for that rare case. But you can create a dict with a range of keys and the values you want. And add it to you int_dict using update.

int_dict = {
    0: "String1",
    1: "String2",
    2: "String3",
    16: "String5"
}
int_dict.update({i: "String4" for i in range(3, 16)})
Leonid Mednikov
  • 943
  • 4
  • 13
1

With dict comprehension:

int_dict = {n:'String{}'.format(n+1) for n in range(0,4)}
int_dict.update({n:'String4' for n in range(3,16)})
int_dict.update({16:'String5'})
juankysmith
  • 11,839
  • 5
  • 37
  • 62
1

I propose a solution that I find more pythonic: first a dictionary with the keys having different values is created, then it is updated with a dictionary the keys having the same values by using dict.fromkeys

int_dict = {
    0: "String1",
    1: "String2",
    2: "String3",
    16: "String5"
}
int_dict.update(dict.fromkeys(range(3,15), "String4"))
Dr Fabio Gori
  • 1,105
  • 16
  • 21
0

What about nested dictionaries? First level key being left side of the interval and second level key being the right side?

d = {0:{0:"String1"},
...
 3:{15:"String4"},
 16:{16:"String5"}};
c-garcia
  • 598
  • 1
  • 9
  • 17