查找大于 x 的元素的索引

36

给定以下向量,

a = [1, 2, 3, 4, 5, 6, 7, 8, 9]

我需要确定元素大于等于4的“a”的索引,如下所示:
idx = [3, 4, 5, 6, 7, 8] 

"idx" 中的信息将用于从另一个列表 X 中删除元素(X 具有与 "a" 相同数量的元素):

del X[idx] #idx is used to delete these elements in X. But so far isn't working.

我听说numpy可能会有帮助。有什么想法吗? 谢谢!


循环是一个很好的起点。 - monkut
你的 idx 示例是错误的,该列表中只有9个元素,因此只有9个索引,0-8 - Aesthete
你的问题有些自相矛盾。看起来你可能把索引和元素混淆了(实际上,你的 idx 是元素列表,而你正在询问索引列表)。另外,请告诉我们在提问前你自己尝试了什么? - 0xc0de
@0xc0de 我认为他/她只是在这里输入了伪代码。 - Shawn Zhang
1
感谢所有的回答。实际上我没有提到我需要使用idx作为另一个列表中要删除元素的索引,而不是一个单独的列表。 - Oliver Amundsen
7个回答

46
>>> [i for i,v in enumerate(a) if v > 4]
[4, 5, 6, 7, 8]

enumerate 返回数组中每个项目的索引和值。如果值 v 大于 4,则将索引 i 包括在新数组中。

或者您可以直接修改原始列表并排除所有大于 4 的值。

>>> a[:] = [x for x in a if x<=4]
>>> a 
[1, 2, 3, 4]

19

好的,我理解了你的意思,一行Python代码就足够了:

使用列表推导式

[ j for (i,j) in zip(a,x) if i >= 4 ]
# a will be the list compare to 4
# x another list with same length

Explanation:
>>> a
[1, 2, 3, 4, 5, 6, 7, 8, 9]
>>> x
['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'j']

Zip函数将返回一个元组列表

>>> zip(a,x)
[(1, 'a'), (2, 'b'), (3, 'c'), (4, 'd'), (5, 'e'), (6, 'f'), (7, 'g'), (8, 'h'), (9, 'j')]

列表推导式是一种快捷方式,可以在列表中使用“in”循环元素,并使用表达式对元素进行评估,然后将结果返回到列表中,您还可以添加条件来确定要返回的结果

>>> [expression(element) for **element** in **list** if condition ]

这段代码只是返回将所有配对压缩在一起的结果,没有其他作用。

>>> [(i,j) for (i,j) in zip(a,x)]
[(1, 'a'), (2, 'b'), (3, 'c'), (4, 'd'), (5, 'e'), (6, 'f'), (7, 'g'), (8, 'h'), (9, 'j')]

我们所做的是在其中添加一个条件,通过指定“if”后跟一个布尔表达式来实现。

>>> [(i,j) for (i,j) in zip(a,x) if i >= 4]
[(4, 'd'), (5, 'e'), (6, 'f'), (7, 'g'), (8, 'h'), (9, 'j')]

使用Itertools

>>> [ _ for _ in itertools.compress(d, map(lambda x: x>=4,a)) ]
# a will be the list compare to 4
# d another list with same length

使用Python中的itertools.compress和单行代码来完成此任务

>>> a = [1, 2, 3, 4, 5, 6, 7, 8, 9]
>>> d = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'j'] # another list with same length
>>> map(lambda x: x>=4, a)  # this will return a boolean list 
[False, False, False, True, True, True, True, True, True]


>>> import itertools
>>> itertools.compress(d, map(lambda x: x>4, a)) # magic here !
<itertools.compress object at 0xa1a764c>     # compress will match pair from list a and the boolean list, if item in boolean list is true, then item in list a will be remain ,else will be dropped
#below single line is enough to solve your problem
>>> [ _ for _ in itertools.compress(d, map(lambda x: x>=4,a)) ] # iterate the result.
['d', 'e', 'f', 'g', 'h', 'j']

itertools.compress的解释,我认为这将对你理解清晰:

>>> [ _ for _ in itertools.compress([1,2,3,4,5],[False,True,True,False,True]) ]
[2, 3, 5]

1
@OliverAmundsen 这将是我的最终解决方案。 - Shawn Zhang
成功了!谢谢@ShawnZhang。能简单解释一下“使用列表推导”的逻辑吗?谢谢。 - Oliver Amundsen

9
我认为最简单的方法是使用numpy。
X[np.array(a)>4]#X needs to be np.array as well

说明:

np.array将a转换为数组。

np.array(a)>4 生成一个布尔数组,其中包含所有应该保留的元素。

X通过布尔数组进行过滤,因此只选择a大于4的元素(其余元素被丢弃)。


8
>>> import numpy as np
>>> a = np.array(range(1,10))
>>> indices = [i for i,v in enumerate(a >= 4) if v]
>>> indices
[3, 4, 5, 6, 7, 8]

>>> mask = a >= 4
>>> mask
array([False, False, False,  True,  True,  True,  True,  True,  True], dtype=boo
l)
>>> a[mask]
array([4, 5, 6, 7, 8, 9])
>>> np.setdiff1d(a,a[mask])
array([1, 2, 3])

7

我想我来晚了一些(尽管使用Numpy使事情变得更容易)...

import numpy as np

# Create your array
a = np.arange(1, 10)
# a = array([1, 2, 3, 4, 5, 6, 7, 8, 9])

# Get the indexes/indices of elements greater than 4 
idx = np.where(a > 4)[0]
# idx = array([4, 5, 6, 7, 8])

# Get the elements of the array that are greater than 4
elts = a[a > 4]
# elts = array([5, 6, 7, 8, 9])

# Convert idx(or elts) to a list
idx = list(idx)
#idx = [4, 5, 6, 7, 8]

1

使用内置的过滤器函数是可以的

>>>a = [1, 2, 3, 4, 5, 6, 7, 8, 9]
>>>filter(lambda x : x < 4, a)
[1, 2, 3]

解释

filter(FUN, Iterable)

这个表达式会遍历可迭代对象的所有元素,并将其作为参数传递给FUN函数,如果返回值为True,则该参数将被附加到内部列表中

lambda x: x > 4

这意味着一个匿名函数,它将接受一个参数并测试它是否大于4,并返回True或False值

你的解决方案

如果您想删除所有大于4的元素,则尝试以下操作

>>> a = [1, 2, 3, 4, 5, 6, 7, 8, 9]
>>> filter(lambda x: x<4 ,a)
[1, 2, 3]

当您调用del a[9]时会发生什么? - Aesthete
1
你返回的是列表元素,而不是索引。虽然这对于给定的列表有效,但它并不是正确的答案。 - 0xc0de
@爱美者 这里的a的长度是9,a[9]表示列表中的第10个元素。如果执行del a[9],Python会抛出索引错误。 - Shawn Zhang
@0xc0de 你好,感谢你的严谨态度。但是根据问题的背景,索引返回将被用于删除列表中的元素。我认为我所写的内容将会有所帮助,并展示出关闭该问题的Pythonic方式。 - Shawn Zhang
@OliverAmundsen 我用列表推导式和itertools完成了我的解决方案,你可以选择任何一个。 - Shawn Zhang
显示剩余2条评论

0
循环速度较慢,使用分治法。C++ 代码
// find index whose value is equal to or greater than "key" in an ordered vector.
// note: index may be equal to indices.size()
size_t StartIndex(const std::vector<int>& indices, int key)
{
    if (indices.empty() || key <= indices[0])
        return 0;

    if (key > indices.back())
        return indices.size();

    size_t st = 0;
    size_t end = indices.size() - 1;

    while (true)
    {
        if ((end - st) < 2)
            return (indices[st] < key) ? end : st;

        size_t mid = ((st + end) >> 1);  // (st + end) / 2

        if (indices[mid] == key)
            return mid;

        (indices[mid] < key ? st : end) = mid;
    }
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接