Looks like it will be really hard to get any faster than a dict()
. Just see how long random.choice()
takes without any lookup:
>>> order = list(itertools.product(range(4),repeat=6))
>>> order_dic = {i:order.index(i) for i in order}
>>> %timeit order.index(random.choice(order))
>>> %timeit order_dic[random.choice(order)]
>>> %timeit random.choice(order)
10000 loops, best of 3: 98.6 µs per loop
1000000 loops, best of 3: 1.6 µs per loop
1000000 loops, best of 3: 1.39 µs per loop
So, the lookup consists mere 15% of the total you were measuring.
But maybe you could consider storing the index in the tuple? Or storing the tuple in another tuple, that also has the index? For example order = list(enumerate(order))
.
You could assign the index to each tuple object:
order = list(itertools.product(range(4),repeat=6))
order_dic = {i:order.index(i) for i in order}
%timeit order.index(random.choice(order))
%timeit order_dic[random.choice(order)]
%timeit random.choice(order)
class mytuple(tuple): pass
order = list(map(mytuple, order))
for i, t in enumerate(order): t.rev_index = i
%timeit random.choice(order).rev_index
## -- End pasted text --
10000 loops, best of 3: 101 µs per loop
1000000 loops, best of 3: 1.59 µs per loop
1000000 loops, best of 3: 1.44 µs per loop
1000000 loops, best of 3: 1.53 µs per loop
It's faster than the hash map.
You can't set attributes of builtins dynamically, so we have to subclass it. We also can't use __slots__
because variable-size types like tuple
don't support it, so every mytuple
will have an additional __dict__
. But apparently this still has a smaller memory footprint (almost twice) than using one dict
to map all the indexes:
>>> from pympler.asizeof import asizeof
>>> asizeof(order_dic) \
... / (asizeof(order) - asizeof(list(itertools.product(range(4),repeat=6))))
1.8341168569509738