Reputation: 2835
It seems trivial on first look, yet surprisingly I haven't managed to find any answer online - consider the following list:
my_list = [[1,2,3], [4,5,6], [7,8,9]]
In order to get 5, I can go my_list[1][1]
, by 5's position of course.
Suppose I have the following tuple:
t = (1, 1)
Can I use this tuple in order to get 5 in a more appealing way then my_list[t[0]][t[1]]
?
Edit: please also take assignment into account, i.e more appealing then
my_list[t[0]][t[1]] = value
and final elements which are not necessarily numeric, e.g [['a', 'b'], ['c', 'd']]
Upvotes: 2
Views: 2036
Reputation: 23753
You could create operator.itemgetter
objects and apply them successively.
Example for two levels of nesting:
import operator
a = [[1,2,3], [4,5,6], [7,8,9]]
t = (1,2)
i1, i2 = map(operator.itemgetter, t)
>>> i2(i1(a))
6
Example for n levels of nesting (you have to ensure the target structure can accommodate the length of the tuple, maybe wrap it in a try/except):
a = [[[1,2,3], [4,5,6]], [[7,8,9],['a','b','c']]]
t = (0,1,0) # should produce 4
z = a[:]
for op_ig in map(operator.itemgetter, t):
z = op_ig(z)
>>> z
4
To go a bit further using a couple of functions from functionally
from functionally import compose, thrush
a = [[[1,2,3], [4,5,6]], [[7,8,9],['a','b','c']]]
t = (1,1,0) # should produce a
foo = compose(*map(operator.itemgetter, reversed(t)))
>>> foo(a)
'a'
>>> thrush(a, *(operator.itemgetter(i) for i in t))
'a'
Upvotes: 0
Reputation: 6333
use reduce
:
result = reduce(lambda acc, i: acc[i], t, my_list)
demo:
>>> my_list = [[1,2,3], [4,5,6], [7,8,9]]
>>> t = (1, 1)
>>> reduce(lambda acc, i: acc[i], t, my_list)
5
if an update is required:
reduce(lambda acc, i: acc[i], t[:-1], my_list)[t[-1]]
returns a "left value"(if i may say so). but it becomes ugly then, since the consistency of the expression is broken. and really, it can't wrapped as a function either.
i would suggest to write a simple wrapper like this:
class mdlist(list):
def __getitem__(self, item):
if isinstance(item, tuple):
assert len(item) >= 1
return self[item[0]][item[1:]] if len(item) > 1 else self[item[0]]
else:
return super(mdlist, self).__getitem__(item)
def __setitem__(self, item, value):
if isinstance(item, tuple):
assert len(item) >= 1
if len(item) > 1:
self[item[0]][item[1:]] = value
else:
self[item[0]] = value
else:
super(mdlist, self).__setitem__(item, value)
it doesn't take more than you think and ease your life a lot.
Upvotes: 3
Reputation: 582
I think NumPy package just fit what you need. First turn the list into a NumPy array, then you can select a item by its position tuple.
import numpy as np
my_list = [[1,2,3], [4,5,6], [7,8,9]]
my_array = np.array(my_list)
t = (1, 1)
print my_array[t]
Upvotes: 2
Reputation: 1399
You can write a function to do that:
def nested_index(l, t):
e = l
for i in t:
e = e[i]
return e
Then you can call the function as:
nested_index(my_list, t)
Upvotes: 1
Reputation: 2567
You could use tuple unpacking to get your tuple values ( and ultimately you r list indices into variables )
>>> one , two = t
>>> mylist[one][two]
5
Upvotes: 1