Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Understanding python policy for finding the minimum in a list of list

Tags:

python

list

I have the following list of lists of values and I want to find the min value among all the values.

Q = [[8.85008011807927, 4.129896248976861, 5.556804136197901], 
     [8.047707185696948, 7.140707521433818, 7.150610818529693],  
     [7.5326340018228555, 7.065307672838521, 6.862894377422498]]

I was planning to do something like:

min(min(Q))

I tried this approach on a smaller example and it works:

>>>b = [[2,2],[1,9]]
>>>min(b)
[1, 9]
>>>min(min(b))
1

But using this on my original list Q it returns the wrong result:

>>> min(Q)
[7.5326340018228555, 7.065307672838521, 6.862894377422498]
>>> min(min(Q))
6.862894377422498

Why is this approach wrong and why?

like image 717
Alvin Avatar asked Feb 28 '14 15:02

Alvin


2 Answers

Lists are compared using their lexicographical order1 (i.e. first elements compared, then the second, then the third and so on), so just because list_a < list_b doesn't mean that the smallest element in list_a is less than the smallest element in list_b, which is why your approach doesn't work in the general case.

For example, consider this:

>>> l1 = [3, 0]
>>> l2 = [2, 1]
>>> 
>>> min(l1, l2)
[2, 1]

The reason min(l1, l2) is [2, 1] is because the first element of l1 (3) is initially compared with that of l2 (2). Now, 2 < 3, so l2 is returned as the minimum without any further comparisons. However, it is l1 that really contains the smallest number out of both lists (0) which occurs after the initial element. Therefore, taking the min of min(l1, l2) gives us the incorrect result of 1.

A good way to address this would be to find the minimum of the "flattened" list, which can be obtained with a generator:

>>> Q = [[8.85008011807927, 4.129896248976861, 5.556804136197901], 
...      [8.047707185696948, 7.140707521433818, 7.150610818529693],  
...      [7.5326340018228555, 7.065307672838521, 6.862894377422498]]
>>> 
>>> min(a for sub in Q for a in sub)  # <--
4.129896248976861

(+1 to @Ffisegydd for posting a solution along these lines first.)


1 From http://docs.python.org/3/tutorial/datastructures.html#comparing-sequences-and-other-types:

Sequence objects may be compared to other objects with the same sequence type. The comparison uses lexicographical ordering: first the first two items are compared, and if they differ this determines the outcome of the comparison; if they are equal, the next two items are compared, and so on, until either sequence is exhausted. If two items to be compared are themselves sequences of the same type, the lexicographical comparison is carried out recursively. If all items of two sequences compare equal, the sequences are considered equal. If one sequence is an initial sub-sequence of the other, the shorter sequence is the smaller (lesser) one.

like image 98
arshajii Avatar answered Sep 28 '22 06:09

arshajii


Your approach didn't work properly because, that is how Python sequence comparison is done

I want to find the min value among all the values.

If you want to find the minimum of all the values, you can do something like this

print min(map(min, Q))
# 4.12989624898
like image 20
thefourtheye Avatar answered Sep 28 '22 05:09

thefourtheye