Extract indices of specified elements in a list - python

I have a list. Each element is a real-value integer, and I want to extract the indices of specified element. For example:
import numpy as np
idx = np.where(A==1) #A is a list of [1,1,2,3,4,5....]
But np.where seems not to work for a list.
My next task is to obtain a new list from another list, B, based on the obtained indices:
C = B[idx]

Convert the list A to an ndarray and it should work
idx = np.where(np.array(A)==1)
C = [B[i] for i in idx[0]]

There is no need of numpy IMO. You can create B simply by using something like:
B = [ele for ele in A if ele == 1]

If A is a vanilla list (a default list in Python), then Python will interpret:
A == 1
as checking whether the list is equal to 1. Which is of course not true.
You should turn A into an array:
Aa = np.array(A) # construct a numpy array
idx = np.where(Aa == 1) # obtain the indices
B = Aa[idx] # make a copy (again on the numpy array)

Related

Iterating over numpy array and access the values

I want to iterate over a numpy array and do some calculations on the values. However, things are not as expected. To show what I mean, I simply wrote this code to read values from a numpy array and move them to another list.
a = array([1,2,1]).reshape(-1, 1)
u = []
for i in np.nditer(a):
print(i)
u.append(i)
print(u)
According to tutorial, nditer points to elements and as print(i) shows, i is the value. However, when I append that i to an array, the array doesn't store the value. The expected output is u = [1, 2, 1] but the output of the code is
1
2
1
[array(1), array(2), array(1)]
What does array(1) mean exactly and how can I fix that?
P.S: I know that with .tolist() I can convert a numpy array to a standard array. However, in that code, I want to iterate over numpy elements.
As already explained in your previous question, numpy.nditer yields numpy arrays. What is shown by print is only the representation of the object, not the content or type of the object (e.g., 1 and '1' have the same representation, not the same type).
import numpy as np
a = np.array([1,2,1]).reshape(-1, 1)
type(next(np.nditer(a)))
# numpy.ndarray
You just have a zero-dimensional array:
np.array(1).shape
# ()
There is no need to use numpy.nditer here. If you really want to iterate over the rows of your array with single column (and not use tolist), use:
u = []
for i in a[:,0]:
u.append(i)
u
# [1, 2, 1]
numpy.nditer actually returns a numpy array. If you want the actual value of this item, you can use the built in item() function:
a = array([1,2,1]).reshape(-1, 1)
u = []
for i in np.nditer(a):
u.append(i.item())
print(u)
A pure python equivalent of what's happening with your append is:
In [75]: alist = []
...: x = [0]
...: for i in range(3):
...: x[0] = i
...: print(x)
...: alist.append(x)
[0]
[1]
[2]
In [76]: alist
Out[76]: [[2], [2], [2]]
In [77]: x
Out[77]: [2]
x is modified in each loop, but only a reference is saved. The result is that all elements of the list are the same object, and display its last value.

Deleting the indices in Array

I have the following code for deleting the indices inside the array, but it seems not to work
import numpy as np
length=4
indices=np.arange(length)
for num in (indices):
np.delete(indices, num)
print("checking", indices, num)
What seems to be the issue? does np.delete not work on arrays?
It's better not iterating a container while changing its length. Try working with indexed instead :
import numpy as np
length=4
indices=np.arange(length)
for i in reversed(range(len(indices))):
indices = np.delete(indices, i)
print("checking", indices, i)
If you're looking for deletion by element you could find the element index before using delete :
import numpy as np
length=4
elements=np.array([1, 3, 2, 4])
for i in elements:
idx = np.where(elements == i)
elements = np.delete(elements, idx)
print("checking", elements, i)
Numpy array is immutable. So you cannot delete an item from it. However, you can construct a new array without the values you don't want, like this:
new_indices = np.delete(indices, [0,1,2])
In your code, you can try to get new array after deleting the element, by assigning it to a variable as below:
new_indices = np.delete(indices, num)
print(new_indices, indices) # prints [1,2,3],[0,1,2,3]
Now if you print new_indices it will not have the element at index num
numpy.delete returns a copy of given array, it doesn't modify existing one.

Finding the indices of distinct elements in a vectorized manner

I have a list of ints, a, between 0 and 3000. len(a) = 3000. I have a for loop that is iterating through this list, searching for the indices of each elemenent in a larger array.
import numpy as np
a = [i for i in range(3000)]
array = np.random.randint(0, 3000, size(12, 1000, 1000))
newlist = []
for i in range(0, len(a)):
coord = np.where(array == list[i])
newlist.append(coord)
As you can see, coord will be 3 arrays of the coordinates x, y, z for the values in the 3D matrix that equal the value in the list.
Is there a way to do this in a vectorized manner without the for loop?
The output should be a list of tuples, one for each element in a:
# each coord looks like this:
print(coord)
(array[1, ..., 1000], array[2, ..., 1000], array[2, ..., 12])
# combined over all the iterations:
print(newlist)
[coord1, coord2, ..., coord3000]
There is actually a fully vectorized solution to this, despite the fact that the resulting arrays are all of different sizes. The idea is this:
Sort all the elements of the array along with their coordinates. argsort is ideal for this sort of thing.
Find the cut-points in the sorted data, so you know where to split the array, e.g. with diff and flatnonzero.
split the coordinate array along the indices you found. If you have missing elements, you may need to generate a key based on the first element of each run.
Here is an example to walk you through it. Let's say you have an d-dimensional array with size n. Your coordinates will be a (d, n) array:
d = arr.ndim
n = arr.size
You can generate the coordinate arrays with np.indices directly:
coords = np.indices(arr.shape)
Now ravel/reshape the data and the coordinates into an (n,) and (d, n) array, respectively:
arr = arr.ravel() # Ravel guarantees C-order no matter the source of the data
coords = coords.reshape(d, n) # C-order by default as a result of `indices` too
Now sort the data:
order = np.argsort(arr)
arr = arr[order]
coords = coords[:, order]
Find the locations where the data changes values. You want the indices of the new values, so we can make a fake first element that is 1 less than the actual first element.
change = np.diff(arr, prepend=arr[0] - 1)
The indices of the locations give the break-points in the array:
locs = np.flatnonzero(change)
You can now split the data at those locations:
result = np.split(coords, locs[1:], axis=1)
And you can create the key of values actually found:
key = arr[locs]
If you are very confident that all the values are present in the array, then you don't need the key. Instead, you can compute locs as just np.diff(arr) and result as just np.split(coords, inds, axis=1).
Each element in result is already consistent with the indexing used by where/nonzero, but as a numpy array. If specifically want a tuple, you can map it to a tuple:
result = [tuple(inds) for inds in result]
TL;DR
Combining all this into a function:
def find_locations(arr):
coords = np.indices(arr.shape).reshape(arr.ndim, arr.size)
arr = arr.ravel()
order = np.argsort(arr)
arr = arr[order]
coords = coords[:, order]
locs = np.flatnonzero(np.diff(arr, prepend=arr[0] - 1))
return arr[locs], np.split(coords, locs[1:], axis=1)
You can return a list of index arrays with empty arrays for missing elements by replacing the last line with
result = [np.empty(0, dtype=int)] * 3000 # Empty array, so OK to use same reference
for i, j in enumerate(arr[locs]):
result[j] = coords[i]
return result
You can optionally filter for values that are in the specific range you want (e.g. 0-2999).
You can use logical OR in numpy to pass all those equality conditions at once instead of one by one.
import numpy as np
conditions = False
for i in list:
conditions = np.logical_or(conditions,array3d == i)
newlist = np.where(conditions)
This allows numpy to do filtering once instead of n passes for each condition separately.
Another way to do it more compactly
np.where(np.isin(array3d, list))

Enumerate list to make a new list of indices?

I'm trying to make a new list of indices by enumerated a previous list. Basically, what I want is:
To enumerate a list of elements to obtain indices for each element. I coded this:
board = ["O","O","O","O","O"]
for index,y in enumerate(board):
print(index,end=" ")
which gives:
0 1 2 3 4
I now want to make those numbers into a new list, but have no clue how to do that.
Thanks! Sorry for the question, I'm still a beginner and am just trying to get the hang of things.
You should probably just make a range of the right length:
board = ["O","O","O","O","O"]
indices = list(range(len(board)))
print(indices)
> [0, 1, 2, 3, 4]
Use list comprehension:
indices = [index for index, y in enumerate(board)]
If board is always a object, which implements the __len__-method, you can also use range:
indices = list(range(len(board)))
If you just want all the numbers you can use this:
indices = list(range(len(board)))
If you pass one number to range it will return an iterator with the numbers 0 up to the passed number (excluding). After this we turn it into a list with the list function.
You can use list comprehension to do that:
result = [index for index,y in enumerate(board)]
Alternatively you can use the range function:
result = range(len(board))
I would just use numpy arange, which creates an array that looks like the one you are looking for:
Numpy Arange
import numpy as np
enumerated = np.arange(len(board))
The straightforward way is:
board = ["O","O","O","O","O"]
newlist = []
for index,y in enumerate(board):
newlist.append(index)
A more advanced way using list comprehensions would be:
newlist = [index for index, value in enumerate(board)]

Two dimensional array in python

I want to know how to declare a two dimensional array in Python.
arr = [[]]
arr[0].append("aa1")
arr[0].append("aa2")
arr[1].append("bb1")
arr[1].append("bb2")
arr[1].append("bb3")
The first two assignments work fine. But when I try to do, arr[1].append("bb1"), I get the following error:
IndexError: list index out of range.
Am I doing anything silly in trying to declare the 2-D array?
Edit:
but I do not know the number of elements in the array (both rows and columns).
You do not "declare" arrays or anything else in python. You simply assign to a (new) variable. If you want a multidimensional array, simply add a new array as an array element.
arr = []
arr.append([])
arr[0].append('aa1')
arr[0].append('aa2')
or
arr = []
arr.append(['aa1', 'aa2'])
There aren't multidimensional arrays as such in Python, what you have is a list containing other lists.
>>> arr = [[]]
>>> len(arr)
1
What you have done is declare a list containing a single list. So arr[0] contains a list but arr[1] is not defined.
You can define a list containing two lists as follows:
arr = [[],[]]
Or to define a longer list you could use:
>>> arr = [[] for _ in range(5)]
>>> arr
[[], [], [], [], []]
What you shouldn't do is this:
arr = [[]] * 3
As this puts the same list in all three places in the container list:
>>> arr[0].append('test')
>>> arr
[['test'], ['test'], ['test']]
What you're using here are not arrays, but lists (of lists).
If you want multidimensional arrays in Python, you can use Numpy arrays. You'd need to know the shape in advance.
For example:
import numpy as np
arr = np.empty((3, 2), dtype=object)
arr[0, 1] = 'abc'
You try to append to second element in array, but it does not exist.
Create it.
arr = [[]]
arr[0].append("aa1")
arr[0].append("aa2")
arr.append([])
arr[1].append("bb1")
arr[1].append("bb2")
arr[1].append("bb3")
We can create multidimensional array dynamically as follows,
Create 2 variables to read x and y from standard input:
print("Enter the value of x: ")
x=int(input())
print("Enter the value of y: ")
y=int(input())
Create an array of list with initial values filled with 0 or anything using the following code
z=[[0 for row in range(0,x)] for col in range(0,y)]
creates number of rows and columns for your array data.
Read data from standard input:
for i in range(x):
for j in range(y):
z[i][j]=input()
Display the Result:
for i in range(x):
for j in range(y):
print(z[i][j],end=' ')
print("\n")
or use another way to display above dynamically created array is,
for row in z:
print(row)
When constructing multi-dimensional lists in Python I usually use something similar to ThiefMaster's solution, but rather than appending items to index 0, then appending items to index 1, etc., I always use index -1 which is automatically the index of the last item in the array.
i.e.
arr = []
arr.append([])
arr[-1].append("aa1")
arr[-1].append("aa2")
arr.append([])
arr[-1].append("bb1")
arr[-1].append("bb2")
arr[-1].append("bb3")
will produce the 2D-array (actually a list of lists) you're after.
You can first append elements to the initialized array and then for convenience, you can convert it into a numpy array.
import numpy as np
a = [] # declare null array
a.append(['aa1']) # append elements
a.append(['aa2'])
a.append(['aa3'])
print(a)
a_np = np.asarray(a) # convert to numpy array
print(a_np)
a = [[] for index in range(1, n)]
For compititve programming
1) For input the value in an 2D-Array
row=input()
main_list=[]
for i in range(0,row):
temp_list=map(int,raw_input().split(" "))
main_list.append(temp_list)
2) For displaying 2D Array
for i in range(0,row):
for j in range(0,len(main_list[0]):
print main_list[i][j],
print
the above method did not work for me for a for loop, where I wanted to transfer data from a 2D array to a new array under an if the condition. This method would work
a_2d_list = [[1, 2], [3, 4]]
a_2d_list.append([5, 6])
print(a_2d_list)
OUTPUT - [[1, 2], [3, 4], [5, 6]]
x=3#rows
y=3#columns
a=[]#create an empty list first
for i in range(x):
a.append([0]*y)#And again append empty lists to original list
for j in range(y):
a[i][j]=input("Enter the value")
In my case I had to do this:
for index, user in enumerate(users):
table_body.append([])
table_body[index].append(user.user.id)
table_body[index].append(user.user.username)
Output:
[[1, 'john'], [2, 'bill']]

Categories

Resources