【问题标题】:Find minimum element and its position in list with Nones使用无查找最小元素及其在列表中的位置
【发布时间】:2018-11-22 04:45:27
【问题描述】:

我有一个数字列表和Nones,如下所示:

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

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

(1., 3)

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

【问题讨论】:

  • 1. == 1.0?
  • @pstatix 是的,确实如此。
  • 想要找到 first 索引?意思是,1. 可以存在多次吗?
  • 返回第一个索引可以很好地解决歧义。

标签: python python-3.x list min


【解决方案1】:
min((v,i) for i,v in enumerate(l) if v is not None)
(1.0, 3) # (value, index)

【讨论】:

  • 这可能是最快的。
【解决方案2】:

我可能会分成两部分:

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 索引,只需一次迭代即可返回最终元组。

【讨论】:

  • @vaultah 不确定其他原生解决方案。它总计 O(N) + O(N) = O(N)
  • 在我的回答中,我认为min + enumerate 应该提供一次性解决方案。
【解决方案3】:

您可以定义一个转换函数并将其与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 中的第 3 方库:

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

【讨论】:

  • 如果您看到我的帖子,也可以这样做,而无需向命名空间添加函数。
  • @pstatix,当然,我赞成你的,它有效。但我觉得给命名空间加一个函数更易读。
  • 很公平,尽管就个人而言,除非这个列表很庞大,否则我最初提出的 O(N) 解决方案(以及您和我的更新也是如此)通过将其分解为非常可读的解决方案就可以了两个班轮。您迭代列表两次的事实没有任何区别,因为它是 O(N) 无论如何讨论here
  • @pstatix,是的,我明白了你的 O(n) 点。我认为 vaultah 和我的意思是单程方法也适用于生成器(不是list-特定),而这对于 2 程是不可能的(除非你复制你的生成器并用尽它两次,这很贵)。
【解决方案4】:
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

【讨论】:

  • 抱歉我改了1.0 3
【解决方案5】:

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

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

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

【讨论】:

    【解决方案6】:

    这是一种方法。

    演示:

    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)
    

    【讨论】:

    • 哦好的...抱歉没有测试
    • @vaultah l = [(v, i) for i, v in enumerate(l) if v is not None] ?
    【解决方案7】:

    你可以避免像这样使用key

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

    【讨论】:

      【解决方案8】:

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

              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)
      

      【讨论】:

        【解决方案9】:

        虽然我更喜欢接受的答案。 可以使用 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)
        

        【讨论】:

          【解决方案10】:

          为什么结果应该是 (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))
          

          【讨论】:

            猜你喜欢
            • 2023-03-26
            • 1970-01-01
            • 2017-12-08
            • 1970-01-01
            • 1970-01-01
            • 2023-04-11
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多