Find the indices of elements greater than x
Asked Answered
I

7

37

Given the following vector,

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

I need to identify the indices of "a" whose elements are >= than 4, like this:

idx = [3, 4, 5, 6, 7, 8] 

The info in "idx" will be used to delete the elements from another list X (X has the same number of elements that "a"):

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

I heard that numpy might help. Any ideas? Thanks!

Irredentist answered 5/12, 2012 at 6:21 Comment(5)
loops are a good place to start.Crista
Your idx example is wrong, there are only 9 elements in the list, and therefore 9 indices, 0-8.Joanajoane
Your question is slightly contradicting with itself. Looks like you might have confused indices with elements(Your idx in fact is list of elements and you are asking list of indices). Also please tell what have you tried on your own before asking?Delight
@Delight I think he/she just type the pesudo code here .Stockbroker
Thanks for all the answers. Actually I failed to mention that I need to use idx as an index to remove the elements from another list, other than a...Irredentist
S
19

OK, I understand what you mean and a Single line of Python will be enough:

using list comprehension

[ 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 function will return a list of tuples

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

List comprehension is a shortcut to loop an element over list which after "in", and evaluate the element with expression, then return the result to a list, also you can add condition on which result you want to return

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

This code does nothing but return all pairs that zipped up.

>>> [(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')]

What we do is to add a condition on it by specify "if" follow by a boolean expression

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

using 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

Use itertools.compress with single line in Python to finish close this task

>>> 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']

Explanation for itertools.compress, I think this will be clear for your understanding:

>>> [ _ for _ in itertools.compress([1,2,3,4,5],[False,True,True,False,True]) ]
[2, 3, 5]
Stockbroker answered 5/12, 2012 at 15:57 Comment(2)
@OliverAmundsen this will be my final solutionStockbroker
that worked! Thanks @ShawnZhang. Could briefly explain the logic of the "using list comprehension"? thxIrredentist
J
47
>>> [i for i,v in enumerate(a) if v > 4]
[4, 5, 6, 7, 8]

enumerate returns the index and value of each item in an array. So if the value v is greater than 4, include the index i in the new array.

Or you can just modify your list in place and exclude all values above 4.

>>> a[:] = [x for x in a if x<=4]
>>> a 
[1, 2, 3, 4]
Joanajoane answered 5/12, 2012 at 6:23 Comment(0)
S
19

OK, I understand what you mean and a Single line of Python will be enough:

using list comprehension

[ 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 function will return a list of tuples

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

List comprehension is a shortcut to loop an element over list which after "in", and evaluate the element with expression, then return the result to a list, also you can add condition on which result you want to return

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

This code does nothing but return all pairs that zipped up.

>>> [(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')]

What we do is to add a condition on it by specify "if" follow by a boolean expression

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

using 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

Use itertools.compress with single line in Python to finish close this task

>>> 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']

Explanation for itertools.compress, I think this will be clear for your understanding:

>>> [ _ for _ in itertools.compress([1,2,3,4,5],[False,True,True,False,True]) ]
[2, 3, 5]
Stockbroker answered 5/12, 2012 at 15:57 Comment(2)
@OliverAmundsen this will be my final solutionStockbroker
that worked! Thanks @ShawnZhang. Could briefly explain the logic of the "using list comprehension"? thxIrredentist
B
9

The simplest in my eyes would be to use numpy

X[np.array(a)>4]#X needs to be np.array as well

Explanation: np.array converts a to an array.

np.array(a)>4 gives a bool array with all the elements that should be kept

And X is filtered by the bool array so only the elements where a is greater than 4 are selected (and the rest discarded)

Blais answered 14/3, 2017 at 9:11 Comment(0)
R
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])
Remission answered 5/12, 2012 at 6:24 Comment(0)
A
8

I guess I came here a bit late (while things got easier using 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]
Aeroplane answered 23/9, 2019 at 11:47 Comment(0)
S
1

using filter built-in function is fine

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

Explanation

filter(FUN, Iterable)

this expression will iterate all element from Iterable and supply to FUN function as argument, if return is True ,then the arugment will be append to a internal list

lambda x: x > 4

this means a anonymous function that will take a argument and test it if bigger than 4, and return True of False value

Your solution

if you are try to delete all elements larger than 4 ,then try blow

>>> a = [1, 2, 3, 4, 5, 6, 7, 8, 9]
>>> filter(lambda x: x<4 ,a)
[1, 2, 3]
Stockbroker answered 5/12, 2012 at 6:25 Comment(7)
And what happens when you call del a[9]?Joanajoane
-1. You are returning list elements, not the indices. Although this works for the given list but it's not a correct answer.Delight
@Joanajoane length of a here is 9, a[9] means the 10th element of list.if del a[9], python will throw an index errorStockbroker
@Delight hi,nice for your rigourism. but as context from the question , index return will be used to delete element in the list . I think what I written will be helpful and show pythonic way to close the ticket.Stockbroker
@ShawnZhang: True. I think the question needs correction. Please edit your answer to reflect difference between what you think the questioner needs and what he is asking for so that I will cancel my -1 :).Delight
@OliverAmundsen , I understand what you need and post another answer below ,using itertools.compress function .Stockbroker
@OliverAmundsen I've finalize my solution with list comprehension and itertools , you can just pick whichever you like .Stockbroker
S
0

looping is slow, using divide and conquer method. code in 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;
    }
}
Syllabub answered 7/3, 2022 at 6:47 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.