Choose certain items iterating through a list slice python - python

I have a list
[[0, 1], [1, 0], [0, 2], [1, 1], [2, 0], [0, 3], [1, 2], [2, 1], [3, 0]]
I would like to select the indices from the list that meet the following conditions:
1) The sum of the elements is equal to 3
2) The answer to the above sum does not appear in the list
The way I have thought to do this so far : create a new list with the sums of the above list, countersum, and take the indices, idx of those that meet the condition of being equal to 3, and then:
selection=[n for n, x in list[idx[0]:] if sum not in x]
So idx[0] should contain the index of the first element in the original list meeting the sum condition,
However this is giving me error and I have no idea why!
TypeError: argument of type 'int' is not iterable
Any help greatly appreciated!!

Here's a simple list comprehension:
>>> L = [[0, 1], [1, 0], [0, 2], [1, 1], [2, 0], [0, 3], [1, 2], [2, 1], [3, 0]]
>>> [i for i, j in enumerate(L) if sum(j) == 3 and 3 not in j]
[6, 7]
If I understand correctly, what you were trying to do was something like this:
[n for n, x in an_integer] # an_integer being an integer because that is what list[idx[0]:] returned
And you can't iterate through an integer, hence the error.

Related

Looking to iterate through list of lists that skips over specific indices

I'm currently working on a Python 3 project that involves iterating several times through a list of lists, and I want to write a code that skips over specific indices of this list of lists. The specific indices are stored in a separate list of lists. I have written a small list of lists, grid and the values I do not want to iterate over, coordinates:
grid = [[0, 0, 1], [0, 1, 0], [1, 0, 0]]
coordinates = [[0, 2], [1, 1], [2, 0]]
Basically, I wish to skip over each 1 in grid(the 1s are just used to make the corresponding coordinate locations more visible).
I tried the following code to no avail:
for row in grid:
for value in row:
for coordinate in coordinates:
if coordinate[0] != grid.index(row) and coordinate[1] != row.index(value):
row[value] += 4
print(grid)
The expected output is: [[4, 4, 1], [4, 1, 4], [1, 4, 4]]
After executing the code with, I am greeted with ValueError: 1 is not in list.
I have 2 questions:
Why am I being given this error message when each coordinate in coordinates contains a 0th and 1st position?
Is there a better way to solve this problem than using for loops?
There are two issues with your code.
The row contains a list of integers, and value contains values in those rows. The issue is that you need access to the indices of these values, not the values themselves. The way that you've set up your loops don't allow for that.
.index() returns the index of the first instance of the argument passed in; it is not a drop-in replacement for using indexing with brackets.
Here is a code snippet that does what you've described, fixing both of the above issues:
grid = [[0, 0, 1], [0, 1, 0], [1, 0, 0]]
coordinates = [[0, 2], [1, 1], [2, 0]]
for row in range(len(grid)):
for col in range(len(grid[row])):
if [row, col] not in coordinates:
grid[row][col] += 4
print(grid) # -> [[4, 4, 1], [4, 1, 4], [1, 4, 4]]
By the way, if you have a lot of coordinates, you can make it a set of tuples rather than a 2D list so you don't have to iterate over the entire list for each row / column index pair. The set would look like coordinates = {(0, 2), (1, 1), (2, 0)}, and you'd use if (row, col) not in coordinates: as opposed to if [row, col] not in coordinates: if you were using a set instead.
Here is a numpy way to do this, for anyone looking -
import numpy as np
g = np.array(grid)
c = np.array(coordinates)
mask = np.ones(g.shape, bool)
mask[tuple(c.T)] = False
#This mask skips each coordinate in the list
g[mask]+=4
print(g)
[[4 4 1]
[4 1 4]
[1 4 4]]
And a one-liner list comprehension, for those who prefer that -
[[j+4 if [row,col] not in coordinates else j for col,j in enumerate(i)] for row,i in enumerate(grid)]
[[4, 4, 1], [4, 1, 4], [1, 4, 4]]
grid = [
[0, 0, 1],
[0, 1, 0],
[1, 0, 0]]
coordinates = [[0, 2], [1, 1], [2, 0]]
for y, row in enumerate(grid):
for x, value in enumerate(row):
if [x, y] in coordinates or value != 1:
grid[y][x] += 4
print(grid)

How to sort an array based on two conditions in python

I have the following array:
[[8, 1], [1, 1], [3, 1], [8, 1], [4, 0], [2, 0]]
How to sort the array based on the first value of the element and if second element equal to 1.
I tried the following way,
sorted(x,key=lambda x:(x[0] and x[1]==1))
But I got this result:
[[10, 0], [5, 0], [5, 1], [2, 1], [1, 1], [8, 1]]
x[0] and x[1] == 1
This is a logical expression which will either evaluate either as True (if x[0] != 0 and x[1] == 1) or False. So your sort key can only take two possible values.
By my understanding, what you want is:
all cases where x[1] == 1 to appear after all the cases where x[1] != 1
subject to above, outputs to be sorted by x[0]
You can't do this easily with a one-dimensional key. To understand why, think about the range of possible inputs in between [-Inf,0] and [Inf,0] and the range between [-Inf,1] and [Inf,1].
Each of these ranges is infinitely large in both directions. If you want to sort them with a one-dimensional key, you somehow need to map two double-endedly infinite ranges onto one number line.
This isn't impossible - if you really had to do it that way, there are tricks you could use to make that happen. But it's a very roundabout way to solve the problem.
It's much easier just to use a two-dimensional key. The sort function checks the zero'th position of a tuple first, and only goes to the first position as a tiebreaker. So, because the value of x[1] takes priority in the sort order you want, the zeroth entry of the tuple is based on x[1] and the first is based on x[0], like this:
x=[[8, 1], [1, 1], [3, 1], [8, 1], [4, 0], [2, 0]]
sorted(x,key=lambda x:(x[1]==1,x[0]))
Output:
[[2, 0], [4, 0], [1, 1], [3, 1], [8, 1], [8, 1]]

Matching the number of occurrences of a 3D list with a reference list

I'm working on a problem, but I hit a roadblock and I was hoping you can help me, so basically I have a 3D list of coordinates and I'm comparing to another 3D list of coordinates that I use for reference. What I'm trying to do is count the number of occurrences of the coordinates and match the occurrences with the reference list. For that, I transform the coordinates list to tuples and then I use Counter to count the number of occurrences, what I need is match the key found in Count with coordinates in the reference list and stored the values in a list of lists. Maybe the code will explain better than me. Here is my code
from collections import Counter
reference = [[[2, 3], [3, 2], [3, 4], [4, 3]],
[[2, 3], [2, 4], [3, 2], [4, 2]], #3D References list with all the coordinates.
[[2, 3], [2, 4], [3, 2], [4, 2]]]
coordinates = [[[3, 2]], [[3, 2], [2, 4], [2, 4]], [[2, 4]]] #List to match the reference list
newlist = [[tuple(j) for j in i] for i in coordinates] #Transform the coordinates list to tuple to use Counter
aux = []
for i in newlist:
aux.append(Counter(i)) #Count the number of occurrences.
print(aux)
#aux = [Counter({(3, 2): 1}), Counter({(2, 4): 2, (3, 2): 1}), Counter({(2, 4): 1})
a = [list(i.values()) for i in aux] #Getting only the values of occurrence.
print(a) #a = [[1], [1, 2], [1]]
The first Counter in the aux list have only the key (3, 2) with 1 occurrence so I need to match the key with the coordinates on the first list of the reference list, as you can see in the first Counter there are some missing keys (coordinates) comparing to the other list, so I need those missing coordinates have the value of zero. The Second Counter have two keys (2, 4), (3, 2) with the corresponding values of 2 and 1, comparing to the second list of the reference list there is also some missing coordinates, so they will have the value of zero and so on. This is my desired output:
#Output
a = [[0, 1, 0, 0], [0, 2, 1, 0], [0, 1, 0, 0]
There is some way I can do this? "Fill" the missing coordinates with a value of zero? If you can point me to the right direction that would be great and sorry for my terrible english!. Thank you so much!
Just navigate through each coordinate from reference and check the number of counts of that coordinate in corresponding counter in aux
aux = [Counter(tuple(j) for j in i) for i in coordinates]
a = [[cntr[tuple(j)] for j in i] for i,cntr in zip(reference,aux)]
print (a)
# [[0, 1, 0, 0], [0, 2, 1, 0], [0, 1, 0, 0]]

How to find missing combinations/sequences in a 2D array with finite element values

In the case of the set np.array([1, 2, 3]), there are only 9 possible combinations/sequences of its constituent elements: [1, 1], [1, 2], [1, 3], [2, 1], [2, 2], [2, 3], [3, 1], [3, 2], [3, 3].
If we have the following array:
np.array([1, 1],
[1, 2],
[1, 3],
[2, 2],
[2, 3],
[3, 1],
[3, 2])
What is the best way, with NumPy/SciPy, to determine that [2, 1] and [3, 3] are missing? Put another way, how do we find the inverse list of sequences (when we know all of the possible element values)? Manually doing this with a couple of for loops is easy to figure out, but that would negate whatever speed gains we get from using NumPy over native Python (especially with larger datasets).
Your can generate a list of all possible pairs using itertools.product and collect all of them which are not in your array:
from itertools import product
pairs = [ [1, 1], [1, 2], [1, 3], [2, 2], [2, 3], [3, 1], [3, 2] ]
allPairs = list(map(list, product([1, 2, 3], repeat=2)))
missingPairs = [ pair for pair in allPairs if pair not in pairs ]
print(missingPairs)
Result:
[[2, 1], [3, 3]]
Note that map(list, ...) is needed to convert your list of list to a list of tuples that can be compared to the list of tuples returned by product. This can be simplified if your input array already was a list of tuples.
This is one way using itertools.product and set.
The trick here is to note that sets may only contain immutable types such as tuples.
import numpy as np
from itertools import product
x = np.array([1, 2, 3])
y = np.array([[1, 1], [1, 2], [1, 3], [2, 2],
[2, 3], [3, 1], [3, 2]])
set(product(x, repeat=2)) - set(map(tuple, y))
{(2, 1), (3, 3)}
If you want to stay in numpy instead of going back to raw python sets, you can do it using void views (based on #Jaime's answer here) and numpy's built in set methods like in1d
def vview(a):
return np.ascontiguousarray(a).view(np.dtype((np.void, a.dtype.itemsize * a.shape[1])))
x = np.array([1, 2, 3])
y = np.array([[1, 1], [1, 2], [1, 3], [2, 2],
[2, 3], [3, 1], [3, 2]])
xx = np.array([i.ravel() for i in np.meshgrid(x, x)]).T
xx[~np.in1d(vview(xx), vview(y))]
array([[2, 1],
[3, 3]])
a = np.array([1, 2, 3])
b = np.array([[1, 1],
[1, 2],
[1, 3],
[2, 2],
[2, 3],
[3, 1],
[3, 2]])
c = np.array(list(itertools.product(a, repeat=2)))
If you want to use numpy methods, try this...
Compare the array being tested against the product using broadcasting
d = b == c[:,None,:]
#d.shape is (9,7,2)
Check if both elements of a pair matched
e = np.all(d, -1)
#e.shape is (9,7)
Check if any of the test items match an item of the product.
f = np.any(e, 1)
#f.shape is (9,)
Use f as a boolean index into the product to see what is missing.
>>> print(c[np.logical_not(f)])
[[2 1]
[3 3]]
>>>
Every combination corresponds to the number in range 0..L^2-1 where L=len(array). For example, [2, 2]=>3*(2-1)+(2-1)=4. Off by -1 arises because elements start from 1, not from zero. Such mapping might be considered as natural perfect hashing for this data type.
If operations on integer sets in NumPy are faster than operations on pairs - for example, integer set of known size might be represented by bit sequence (integer sequence) - then it is worth to traverse pair list, mark corresponding bits in integer set, then look for unset ones and retrieve corresponding pairs.

Unexpected behavior in nested for loop in python

Very simple code nested example:
All the code does is create a list of lists that is initialized to zero.
It iterates through the list rows and columns and each position is given a value.
For some reason the last row of the 2D list is duplicated for each row when the final vector is printed.
Number_of_channels=2
Coefficients_per_channel=3
coefficient_array=[[0]*Coefficients_per_channel]*Number_of_channels
print coefficient_array
for channel in range(Number_of_channels):
for coeff in range(Coefficients_per_channel):
coefficient_array[channel][coeff]=coeff*channel
print coefficient_array[channel][coeff]
print coefficient_array
Output:
[[0, 0, 0], [0, 0, 0]]
0
0
0
0
1
2
[[0, 1, 2], [0, 1, 2]]
I actually expect:
[[0, 0, 0], [0, 1, 2]]
Anyone have any idea how come this is happening?
You only duplicate the outer list, but the values of that list are left untouched. Thus, all (both) outer lists contain references to the same inner, mutable list.
>>> example = [[1, 2, 3]]
>>> example *= 2
>>> example
[[1, 2, 3], [1, 2, 3]]
>>> example[0][0] = 5
[[5, 2, 3], [5, 2, 3]]
>>> example[0] is example[1]
True
Better create the inner lists in a loop:
coefficient_array=[[0]*Coefficients_per_channel for i in xrange(Number_of_channels)]
or, illustrated with the python prompt again:
>>> example = [[i, i, i] for i in xrange(2)]
>>> example
[[0, 0, 0], [1, 1, 1]]
>>> example[0][0] = 5
>>> example
[[5, 0, 0], [1, 1, 1]]
>>> example[0] is example[1]
False
With
coefficient_array=[[0]*Coefficients_per_channel]*Number_of_channels
you do a duplication of references to the same object:
coefficient_array[0] is coefficient_array[1]
evaluates to True.
Instead, build your array with
[[coeff*channel for coeff in range(Coefficients_per_channel)] for channel in range(Number_of_channels)]
Try this instead:
coefficient_array=[0]*Number_of_channels
print coefficient_array
for channel in range(Number_of_channels):
coefficient_array[channel] = [0] * Coefficients_per_channel
for coeff in range(Coefficients_per_channel):
coefficient_array[channel][coeff]=coeff*channel
print (channel, coeff)
print coefficient_array[channel][coeff]
print coefficient_array

Categories

Resources