Steven Lu Steven Lu - 3 months ago 21
Python Question

Python argmin/argmax: Finding the index of the value which is the min or max

I've got a structure of the form:

>>> items
[([[0, 1], [2, 20]], 'zz', ''), ([[1, 3], [5, 29], [50, 500]], 'a', 'b')]


The first item in each tuple is a list of ranges, and I want to make a generator that provides me the ranges in ascending order based on the starting index.

Since the range-lists are already sorted by their starting index this operation is simple: it is just a sorted merge. I'm hoping to do it with good computational efficiency, so I'm thinking that one good way to implicitly track the state of my merge is to simply pop the front off of the list of the tuple which has the smallest starting index in its range list.

I can use
min()
to obtain
[0, 1]
which is the first one I want, but how do I get the index of it?

I have this:

[ min (items[i][0]) for i in range(len(items)) ]


which gives me the first item in each list, which I can then
min()
over somehow, but it fails once any of the lists becomes empty, and also it's not clear how to get the index to use
pop()
with without looking it back up in the list.

To summarize: Want to build generator that returns for me:

([0,1], 'zz', '')
([1,3], 'a', 'b')
([2,20], 'zz', '')
([5,29], 'a', 'b')
([50,500], 'a', 'b')


Or even more efficiently, I only need this data:

[0, 1, 0, 1, 1]


(the indices of the tuples i want to take the front item of)

Answer

This works:

by_index = ([sub_index, list_index] for list_index, list_item in
             enumerate(items) for sub_index in list_item[0])
[item[1] for item in sorted(by_index)]

Gives:

[0, 1, 0, 1, 1]

In detail. The generator:

by_index = ([sub_index, list_index] for list_index, list_item in
             enumerate(items) for sub_index in list_item[0])
list(by_index)    
[[[0, 1], 0], [[2, 20], 0], [[1, 3], 1], [[5, 29], 1], [[50, 500], 1]]

So the only thing needed is sorting and getting only the desired index:

[item[1] for item in sorted(by_index)]
Comments