Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Python: Indexing list for element in nested list

I know what I'm looking for. I want python to tell me which list it's in.

Here's some pseudocode:

item = "a"

nested_list = [["a", "b"], ["c", "d"]]

list.index(item) #obviously this doesn't work

here I would want python to return 0 (because "a" is an element in the first sub-list in the bigger list). I don't care which sub-element it is. I don't care if there are duplicates, e.g., ["a", "b", "a"] should return the same thing as the above example.

like image 954
aquateenfan Avatar asked Mar 09 '10 00:03

aquateenfan


2 Answers

In Python 2.6 or better,

next((i for i, sublist in enumerate(nested_list) if "a" in sublist), -1)

assuming e.g. you want a -1 result if 'a' is present in none of the sublists.

Of course it can be done in older versions of Python, too, but not quite as handily, and since you don't specify which Python versions you're interested in, I think it's best to use the latest production-solid one (just edit your answer if you need to specify other, older versions of Python).

Edit: per request, let me try to explain how this work. I'm using the (new in 2.6) built-in function next, specifically I'm calling next(iterator, default): returns the next item of the iterator (and thus the first, since this is the first time we're advancing that iterator), or the default value if the iterator's finished (which means "empty" if it's finished before we ever advanced it;-). The default is clearly that -1 and gets returned if "a is present in none of the sublists", which means the same as "the iterator is empty" in this case.

Let's look at the iterator again:

(i for i, sublist in enumerate(nested_list) if "a" in sublist)

the (rounded) parentheses and for and if keywords mean this is a generator expression, also known for brevity as genexp. i (the index) and sublist (the item at that index) advance over enumerate(nested_list) -- if we didn't have enumerate here then we wouldn't be keeping track of the index, but in this case we do need it. They're only considered when the if clause is satisfied, that is, when the element you're looking for is present in the current sublist.

So this genexp produces, one at a time, each value of the index such that the sublist at that index satisfies the condition "a" in sublist. Since we're using it inside next, we only take the first such index.

The OP might be justified for thinking that a magical builtin doing all of this in three or four characters would be handier -- and so it would, for this very specific requirement, which I believe I've never met before in over ten years of use of Python; however, if every such specific requirement had its own very specialized builtin the language and builtins would grown to be larger than the tax code. Instead, Python offers many lower-level "lego bricks" and a few handy way to snap them together, to clearly (and reasonably concisely) express the solution to a combinatorially-large variety of specific requirements, like the OP's.

like image 59
Alex Martelli Avatar answered Oct 03 '22 18:10

Alex Martelli


You'll need to use a looping construct of some sort:

next((sublist for sublist in mainlist if item in sublist))

That will give you a generator for all sublists containing the item you want, and give you the first one.

like image 45
sykora Avatar answered Oct 03 '22 19:10

sykora