使用 Nones 查找最小元素及其在列表中的位置

Find minimum element and its position in list with Nones

我有一个数字列表和 None 是这样的:

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

我想获得最小数字及其索引,而 None 应该被忽略。对于给定的示例,结果将是:

(1., 3)

当然,编写一个函数来执行我想要的操作很简单,但我更喜欢一些高效的内置方法或至少是高级方法。 我对 Python 3 的解决方案特别感兴趣,其中 min 函数不接受 None 作为参数。

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

这是一种方法。

演示:

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)

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

如果这是一个问题(即 l 中没有数字的情况),可能包括检查值是否为 inf

该方法通过简单地改变 min 比较值的方式避免了在内部构造新数组。

我可能会把它分成两部分:

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

如果你想把list做成single pass + one liner的方案:

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() return 和 lambda 检查 i[1] 索引中的值(例如 2.0, inf, ..., 5.0).因此,最终的元组是 returned,仅使用一个生成器从原始列表到 "filter and replace" NoneType 索引进行一次迭代。

您可以定义一个转换函数并将其与 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)

如果您喜欢使用第 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

为什么结果应该是(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))
min((v,i) for i,v in enumerate(l) if v is not None)
(1.0, 3) # (value, index)

您可以避免像这样使用 key

>>> import operator as op
>>> import itertools as it
>>> min(it.filterfalse(op.methodcaller('__contains__', None), zip(l, it.count())))
(1.0, 3)

最复杂的是在列表中替换,我认为:

        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)

虽然我更喜欢接受的答案。 您可以在其中使用 NoneType 的演示代码:

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


    
def converter(x):
    NoneType = type(None)
    return x[1] if not isinstance(x[1], NoneType) else float('inf')
       
      
res = min(enumerate(lst), key=converter)[::-1]

print(res)

给予

(1.0, 3)