Найти минимальный элемент и его положение в списке с Nones - PullRequest
0 голосов
/ 12 июня 2018

У меня есть список чисел и None s, таких как:

l = [2., None, 3., 1., None, 2., None, 5.]

Я хочу получить минимальное число и его индекс, тогда как None s следует просто игнорировать.Для данного примера результат будет таким:

(1., 3)

Конечно, написать функцию, которая делает то, что я хочу, просто, но я бы предпочел какую-то эффективную встроенную или хотя бы высокоуровневуюподход.Мне особенно интересны решения для Python 3, где min -функция не принимает None в качестве аргумента.

Ответы [ 9 ]

0 голосов
/ 12 июня 2018

Вы можете избежать использования key, например, так:

>>> import operator as op
>>> import itertools as it
>>> min(it.filterfalse(op.methodcaller('__contains__', None), zip(l, it.count())))
(1.0, 3)
0 голосов
/ 12 июня 2018

Самым сложным было заменить в списке, я думаю:

        import numpy as np

        l = [2., None, 3., 1., None, 2., None, 5.]

        #### function to replace in a list 
        def replaced(sequence, old, new):
            return (new if x == old else x for x in sequence)

        l=list(replaced(l,None,np.nan))

        #### numpy specific function
        position = np.nanargmin(l)
        value = l[position]

        print(position, value)
0 голосов
/ 12 июня 2018

почему результаты должны быть (1., 3), после 1, 2 следует

l = [2., None, 3., 1., None, 2., None, 5.]

bar = map(float, [e for e in l if isinstance(e, float)])
print (min(float(i) for i in bar))
0 голосов
/ 12 июня 2018
min((v,i) for i,v in enumerate(l) if v is not None)
(1.0, 3) # (value, index)
0 голосов
/ 12 июня 2018

Вы можете определить функцию преобразования и использовать ее с min:

lst = [2., None, 3., 1., None, 2., None, 5.]

def converter(x):
    return x[1] if x[1] is not None else float('inf')

res = min(enumerate(lst), key=converter)[::-1]

(1.0, 3)

Если вы довольны использованием сторонней библиотеки, эквивалент в NumPy:

arr = np.array(lst).astype(float)
arr[np.isnan(arr)] = np.inf

res = arr.min(), arr.argmin()

Или, более эффективно, вы можете использовать np.nanargmin:

arg = np.nanargmin(arr)
minval = arr[arg]

res = minval, arg
0 голосов
/ 12 июня 2018

Я бы, вероятно, разделил его на две части:

m = min(x for x in l if x is not None)
s = (m, l.index(m)) # this will grab the first index

Если вы хотите составить список за один проход + одно линейное решение:

midx, mval = min(enumerate(x if x is not None else float('inf') for x in l), key=lambda i: i[1])

Произведение enumerate()итерация, подобная следующей:

0 2.0
1 inf
2 3.0
3 1.0
4 inf
5 2.0
6 inf
7 5.0

Затем вызывается min() и использует возврат enumerate() с lambda для проверки значений в индексе i[1] (например, 2.0, inf, ..., 5.0).Таким образом, окончательный кортеж возвращается только с одной итерацией с использованием генератора из исходного списка для «фильтрации и замены» индексов NoneType.

0 голосов
/ 12 июня 2018

value = min(l, key=lambda x: float('inf') if x is None else x) index = l.index(value)

Может включать проверку того, что значение не является inf, если это вызывает озабоченность (т. Е. Случай, когда в l нет чисел)

Этот метод позволяет избежать построенияновый массив внутри, просто изменив способ сравнения значений min.

0 голосов
/ 12 июня 2018

Это один подход.

Демонстрация:

l = [2., None, 3., 1., None, 2., None, 5.]
l = [(v, i) for i, v in enumerate(l) if v is not None]
print( sorted(l, key=lambda x: x[0])[0] )

Вывод:

(1.0, 3)
0 голосов
/ 12 июня 2018
l = [2., None, 3., 1., None, 2., None, 5.]

idx = l.index(min(x for x in l if x is not None))

print(l[idx], idx) # get value, and idx

Выход

1.0 3
...