Find min value in array > 0
Asked Answered
G

8

26

I am looking to find the lowest positive value in an array and its position in the list. If a value within the list is duplicated, only the FIRST instance is of interest. This is what I have which does what I want but includes 0.

print "Position:", myArray.index(min(myArray))
print "Value:", min(myArray)

for example, as it stands if,

myArray = [4, 8, 0, 1, 5]

then Position: 2, Value: 0

I want it to present position: 3, value: 1

Garfish answered 15/1, 2015 at 15:21 Comment(4)
Can you get duplicate values in your array? If so, are you only interested in the position of the first instance?Contumely
duplicates are very possible, and yes first instance is what is of interest, thanks for pointing this out, will amend questionGarfish
I'm confused by the problem description: it says 'I am looking to find the minimum value in an array that is greater than 0 and its corresponding position' which to me reads like the task is to find the smallest value which is greater than zero and greater than its corresponding position. I guess that's actually meant is to find the smallest value (and its position) which is greater than zero...Durrace
Be forewarned that, all the solutions given below will fail if the list has no item which is greater than 0.Prendergast
T
49

You can use a generator expression with min. This will set m as the minimum value in a that is greater than 0. It then uses list.index to find the index of the first time this value appears.

a = [4, 8, 0, 1, 5]

m = min(i for i in a if i > 0)

print("Position:", a.index(m))
print("Value:", m)
# Position: 3
# Value: 1
Thoth answered 15/1, 2015 at 15:24 Comment(5)
@Garfish I was confused by the wording in your question and added a comment now to explain my confusion.Durrace
In the worst case this solution requires traversing a twice (if the smallest value is at the end of the list).Durrace
Yeah, honestly if I was accepting I'd accept thefourtheye's answer below (which is why I upvoted it). @Garfish I'd suggest you go with thefourtheye's solution (and won't feel bad if you unaccept me for him :) )Thoth
@Thoth I am new to python and have been advised to avoid lambda expressions until I am more confident in using the language, so thanks for the advice but for now I will be using your answerGarfish
beware that this technique will raise a ValueError if none of the members of list a is more than zeroCottar
P
13

You can use the min function and enumerate function, like this

result = min(enumerate(a), key=lambda x: x[1] if x[1] > 0 else float('inf'))
print("Position : {}, Value : {}".format(*result)
# Position : 3, Value : 1

This makes sure that, if the value is greater than 0, then use that value for the minimum value comparison otherwise use the maximum possible value (float('inf')).

Since we iterate along with the actual index of the items, we don't have to find the actual index with another loop.

Prendergast answered 15/1, 2015 at 15:30 Comment(3)
first time i see using enumerate this way, great hint!Audiovisual
Upvoting this because it's the first to use enumerate (which avoids traversing a twice).Durrace
Upvoting for using the key parameter to the min function - instead of looping through with a generator.Islek
I
4

Here is another way of doing it with a generator expression. Note how the values coming from enumerate (a and b) are swapped in the tuple to sort correctly.

value,position = min(((b,a) for a,b in enumerate(myArray) if b>0), default=(None,None))

The default argument will be returned when the generator expression returns nothing (i.e. there are no items greater than 0). The default can be set to whatever makes sense in the surrounding program logic - here returning None will allow you to test with either if value: or if position:

Islek answered 15/1, 2015 at 15:33 Comment(5)
This should be accepted, it's more Pythonic and faster than other answers.Corin
It would be nice if it could tolerate cases where there is no value >0.Gallegos
@Gallegos - how about that? I tried several clunkier methods before realising min had a default argument.Islek
My version doesn't seem to have a default argument for min. Looks like a good solution, though. Also, I found out that if I form my inputs properly, I don't run into the problem. Imagine that.Gallegos
@Gallegos it seems that it was added in 3.4Islek
A
1

add a filter then :

myArray = [4, 8, 0, 1, 5]
result = min(filter(lambda x: x > 0, myArray))
print result # 1
print myArray.index(result) # 3
Audiovisual answered 15/1, 2015 at 15:25 Comment(1)
That only gives the lowest value; it doesn't give the position in the array.Contumely
H
1
def find_min_position(array):
    plus_array = [elem for elem in array if elem > 0]
    min_elem = min(plus_array)
    return min_elem, array.index(min_elem)

In : find_min_position([4, 8, 0, 1, 5])
Out: (1, 3)
Hilde answered 15/1, 2015 at 15:26 Comment(0)
P
0
import numpy as np

x = np.array([1,2,0,5,10])
x = np.extract(x>0,x)
min_index = np.amin(x)
min_value = np.argmin(x)
Peristome answered 15/1, 2015 at 15:41 Comment(1)
This will return incorrect index because elements smaller than 0 are being deleted.Talipes
P
0

the complicated / algorithmic way:

int min = array[0], i = 1
list smallest //list of indexes of the smallest element 

// find the first element greater than 0
while (min <= 0 and i < array.length) {
    min = array[i]
    i++
}

// find the first instance of the smallest element greater than 0
while (i < array.length) {
    if (array[i] < min and array[i] > 0) {
        clear the list
        min = array[i]
        list.append(i)
    }
    else if (array[i] == min) {
        list.append(i)
    }
    i++;
}

the first instance of the smallest element greater than 0 is now the first element that you added to the list.

edit: you'll also have a list of every index of the smallest value. Some simple checks can tell you if there are no elements in the array greater than 0, or if the list is empty, etc.

Photojournalism answered 15/1, 2015 at 15:56 Comment(2)
I would say that using for is way more pythonic than using while, especially in this situation. Also if you need the index and value, enumerate is the way to go, as pointed on thefourtheye answerTrochophore
True, I will leave the answer the way it is, however. For anyone interested in why this is the case, check out this: #921145Photojournalism
T
0

Here's what I did in NumPy:

the_array = numpy.array([2, -4, 0, 5, -inf, 1, -3)]
the_array[the_array <= 0] = 'inf'

min_number = numpy.amin(the_array) # or numpy.argmin() for getting the index

The idea is to convert all numbers that are <= 0 to a very large number, like inf.

Talipes answered 4/4, 2023 at 9:43 Comment(0)

© 2022 - 2025 — McMap. All rights reserved.