I have a 2D list
a = [[1,2], [3,4] ...]
I want to do something like this:
1+3 and 2+4 and store result in another array
b = [4, 6]
Like 0th element of array at index 0 which is 1, added with 0th element of array at index 1 which is 3, and 2 added with 4, and so on.
How can I do this, without looping or generators as looping over a large list is comparatively slower than sum and zip functions.
Using just sum and zip as you mention, however zip still returns a generator, which is memory efficient, not sure why you think otherwise.
list(map(sum, (zip(*a))))
Related
Short version: Given a list with two elements [i, j], how do I get the i, j -element of a 2d array instead of the i, j rows: arr[[i,j]] to arr[i,j].
I've seen similar cases where *list has been used, but I don't entirely understand how that operator works.
Deeper context:
I have a function that returns a nested list, where each sub-list is a pair of indices to be used in an array:
grid = np.full((3,3), 1)
def path():
...
return [[i_1, j_1], [i_2, j_2], ...]
for i in path():
grid[path()[i]] = 0
But since path()[i] is a list, grid[path()[i]] == 0 sets two rows equal to zero, and not a single element. How do I prevent that?
While not stricly necessary, a faster solution would be preferable as this operation is to be done many times.
The thing that is confusing you is the difference in mathematic notation and indexing 2D (or n-dimensional) lists in Python/programming languages.
If you have a 2D matrix in mathematics, called X, and let's say you'd want to access the element in the first row and first column, you'd write X(1, 1).
If you have a 2D array, it's elements are lists. So, if you want to access the 1st row of an array called X you'd do:
X[0] # 0 because indexation starts at 0
Keep in mind that the previous statement returns a new list. You can index this list as well. Since we need the first column, we do:
X[0][0] # element in 1st row and 1st column of matrix X
Thus the answer is you need to successively index the matrix, i.e. apply chain indexing.
As for your original question, here is my answer. Let's say a is the 2-element list which contains the indices i and j which you want to access in the 2D array. I'll denote the 2D array as b. Then you apply chain indexing, the first index is the first element of a and the second index is the second element of a:
a = [0, 0] # list with 2 elements containing the indices
b = [[1, 2, 3], [4, 5, 6], [7, 8, 9]] # 2D array in which you want to access b[0][0]
i, j = a[0], a[1]
print(b[i][j])
Obviously you don't need to use variables i, j, I just did so for clarity:
print(b[a[0]][a[1]])
Both statements print out the element in the 1st row and 1st column of b:
1
I have an array that I would like to iterate over and modify the array itself, through inserts or deletions.
for idx, ele in enumerate(np.nditer(array)):
if idx + 1 < array.shape[0] and ele > array[idx+1]:
array = np.delete(array, idx+1)
print(ele)
Given [5, 4, 3, 2, 1] I want the loop to print out 5 3 1 because 4 and 2 are smaller than their previous elements. But because python creates an iterator based on the first instance of array so it prints 5 4 3 2 1. I want to know if I can get
Generally speaking I want the iterator to be modified if I modify the array within the body of my loop.
You cannot mutate the length of a numpy array, because numpy assigns the required memory for an array upon its creation.
With
array = np.delete(array, idx+1)
You are creating a new array on the right hand side of the = and reassign the name array.
The return value for enumerate(np.nditer(array)) has already been created at that point and won't recognize that the name array has been rebound.
In principle, you can iterate over a sequence and mutate its length at the same time (generally not a good idea). The object just needs to have methods that let you mutate its length (like lists, for example).
Consider:
>>> l = [5, 4, 3, 2, 1]
>>> for idx, ele in enumerate(l):
...: if ele == 3:
...: l.pop(idx) # mutates l
...: print(ele)
...:
5
4
3
1
>>> l
[5, 4, 2, 1]
Notice that
l is mutated.
The loop does not print 2 because popping an element reduces the indexes of all the remaining elements by one. Now l[2] == 2, but index 2 has already been visited by the iterator, so the next print-call prints l[3] which is 1.
This proves that mutations to l have effect on subsequent iterations.
Instead of looping over an array, you can use where method to find
indices of elements meeting some condition.
Then to delete the selected element (or elements), you can use
delete method, passing the source array, and a list of indices.
Then save the result, e.g. under the same variable.
To add an element, you can use append or insert methods
(for details see Numpy documentation).
I have also found a SO post concerning how to loop and delete over an array.
See Deleting elements from numpy array with iteration
My array looks like this:
a = ([1,2],[2,3],[4,5],[3,8])
I did the following to delete odd indexes :
a = [v for i, v in enumerate(a) if i % 2 == 0]
but it dives me now two different arrays instead of one two dimensional:
a= [array([1, 2]), array([4, 5])]
How can I keep the same format as the beginning? thank you!
That is as simple as
a[::2]
which yields the lines with even index.
Use numpy array indexing, not comprehensions:
c = a[list(range(0,len(a),2)),:]
If you define c as the output of a list comprehension, it will return a list of one-dimensional numpy arrays. Instead, using the proper indexing maintains the result a numpy array.
Note than instead of "deleting" the odd indices, what we do is specify what to keep: take all lines with an even index (the list(range(0,len(a),2)) part) and for each line take all elements (the : part)
I have a Pandas series (which could be a list, this is not very important) of lists which contains (to simplify, but that could also be letters of words) positive and negative number,
such as
0 [12,-13,0,6]
1 [2,-3,8,233]
2 [0,6,8,3]
for each of these, i want to fill a row in a three columns data frame, with a list of all positive values, a list of all negative values, and a list of all values comprised in some interval. Such as:
[[12,6],[-13],[0,6]]
[[2,8,233],[-3],[2,8]]
[[6,8,3],[],[6,8,3]]
What I first thought was using a list comprehension to generate a list of triadic lists of lists, which would be converted using pd.DataFrame to the right form.
This was because i don't want to loop over the list of lists 3 times to apply each time a new choice heuristics, feels slow and dull.
But the problem is that I can't actually generate well the lists of the triad [[positive],[negative], [interval]].
I was using a syntax like
[[[positivelist.extend(number)],[negativelist], [intervalist.extend(number)]]\
for listofnumbers in listoflists for number in listofnumbers\
if number>0 else [positivelist],[negativelist.extend(number)], [intervalist.extend(number)]]
but let be honest, this is unreadable, and anyway it doesn't do what I want since extend yields none.
So how could I go about that without looping three times (I could have many millions elements in the list of lists, and in the sublists, and I might want to apply more complexe formulae to these numbers, too, it is a first approach)?
I thought about using functional programming, map/lambda; but it is unpythonic. The catch is: what in python may help to do it right?
My guess would be something as:
newlistoflist=[]
for list in lists:
positive=[]
negative=[]
interval=[]
for element in list:
positive.extend(element) if element>0
negative.extend(element) if element<0
interval.extend(element) if n<element<m
triad=[positive, negative,interval]
newlistoflist.append(triad)
what do you think?
You can do:
import numpy
l = [[12,-13,0,6], [2,-3,8,233], [0,6,8,3]]
l = numpy.array([x for e in l for x in e])
positive = l[l>0]
negative = l[l<0]
n,m = 1,5
interval = l[((l>n) & (l<m))]
print positive, negative, interval
Output: [ 12 6 2 8 233 6 8 3] [-13 -3] [2 3]
Edit: Triad version:
import numpy
l = numpy.array([[12,-13,0,6], [2,-3,8,233], [0,6,8,3]])
n,m = 1,5
triad = numpy.array([[e[e>0], e[e<0], e[((e>n) & (e<m))]] for e in l])
print triad
Output:
[[array([12, 6]) array([-13]) array([], dtype=int64)]
[array([ 2, 8, 233]) array([-3]) array([2])]
[array([6, 8, 3]) array([], dtype=int64) array([3])]]
The following simple code will generate a list of lists of three elements and the total of the elements in each list on the same line.
import random
for i in xrange(3):
my_randoms1 = [random.randrange(1,6,1) for _ in range (3)]
print my_randoms1,"\t", sum(my_randoms1)
Now the question is: How could I add the vertical corresponding elements of all lists and display the sums in a new list on top of all lists as [T1,T2,T3]? Thanks
[T1,T2,T3]
[1, 1, 2] 4
[5, 3, 4] 12
[5, 1, 5] 11
If you're going to be doing anything else with these lists, you probably want to store them in some sort of data structure, possibly using Numpy to place them in a matrix.
The simplest way to do just this is to have some sort of variable, say col_sums = [0,0,0] (initialized before your loop) and add the values of each random list as it's generated. You can do this with nested loops but if you want to get fancy, you can use something like:
col_sums = map(sum, zip(col_sums, my_randoms))
zip() takes your old sums and your random values and gives you a tuple holding the Nth value of each list stuck together. For example, the first iteration, you'd have col_sums = [0,0,0] and zip(col_sums, my_randoms) would give you [(0,1), (0,1), (0,2)]. mapping sum across that list gives you a new list like [1, 1, 2]. If you put this in every iteration, you'll have a nice sum built up at the end.