Related
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]]
I am working on a Sudoku Solver in Python, and I need to create functions in it. One of them checks the Sudoku Matrix and returns the number of rows in it that contains a repeating number.
def findRepeatsInColumn(matrix):
numRepeats = 0
for row in matrix:
safeChars=['[', ']', '/']
usedChars=[]
for char in str(row):
if char in usedChars and char not in safeChars:
numRepeats += 1
break
else:
usedChars.append(char)
return numRepeats
If I pass a matrix [[1, 1, 1], [2, 2, 2], [3, 3, 3]] to it, it functions fine and gives me the output 3, but for checking all columns for repeated numbers, I need to convert the rows into columns, which means I would need something like: Input: [[1, 1, 1], [2, 2, 2], [3, 3, 3]]
Output: [[1, 2, 3], [1, 2, 3], [1, 2, 3]]
Any thoughts on how I could do this without NumPy?
One simple way is to make use of zip and *:
>>> ip = [[1, 1, 1], [2, 2, 2], [3, 3, 3]]
>>> print(list(zip(*ip)))
[(1, 2, 3), (1, 2, 3), (1, 2, 3)]
Suppose you have a matrix named m
transposed = zip(*m)
if your input isnumpy.array you may use the transpose:
i = np.array([[1,1,1], [2,2,2], [3,3,3]])
print(i.T)
output:
[[1 2 3]
[1 2 3]
[1 2 3]]
or you could use:
list(map(list, zip(*i)))
I have a multiple 2D arrays with name temp1, temp2, temp3... etc
temp1 = [[7, 2, 4],
[5, 0, 6],
[8, 3, 1]]
temp2 = [[1, 1, 1],
[1, 1, 1],
[1, 1, 1]]
temp3 = [[2, 2, 2],
[2, 2, 2],
[2, 2, 2]]
I want to run a for loop that will return only some of the arrays depending on the range of i. I am thinking of something like
for i in range(1,3):
arrayName = ("temp" + str(i))
print(arrayName)
where print(arrayName) prints out the actual array instead of a string
Any help is appreciated!
You could do this with exec(). Also your range() should have an upper bound of your max value plus one. The upper bound is not inclusive.
for i in range(1, 4):
exec(f'print(temp{str(i)})')
Output:
[[7, 2, 4], [5, 0, 6], [8, 3, 1]]
[[1, 1, 1], [1, 1, 1], [1, 1, 1]]
[[2, 2, 2], [2, 2, 2], [2, 2, 2]]
You can use eval(). It allows you to get a variable by name.
for i in range(1, 4):
current_array = eval(f'temp{i}')
print(current_array)
But, I advise you to set this part of code to the try/except block because you can have NameError exception. And your code will look like:
for i in range(1, 4):
variable_name = f"temp{i}"
try:
current_array = eval(variable_name)
print(current_array)
except NameError:
print(f"Can not get variable with {variable_name} name")
I notice that this is your requirement:
... where print(arrayName) prints out the actual array instead of a string
If so, you could use the following simplified design pattern:
arrays = [array1, array2, array3]
for array in arrays:
print(array)
And, in modification of your code, so that print() will 'print out the actual array instead of a string':
temp1 = [[7, 2, 4],
[5, 0, 6],
[8, 3, 1]]
temp2 = [[1, 1, 1],
[1, 1, 1],
[1, 1, 1]]
temp3 = [[2, 2, 2],
[2, 2, 2],
[2, 2, 2]]
temps = [temp1, temp2, temp3]
for i in temps:
print(i)
Some further thoughts:
I would avoid the eval() or exec() Python methods as suggested by the other commenters. Simpler solutions are possible; you do not have a concrete reason to use dynamic execution.
There is a cleaner way to refactor your code, but I am providing the above answer that mirrors your code structure more directly so as to avoid confusion.
I am learning more about numpy and need help creating an numpy array from multiple lists. Say I have 3 lists,
a = [1, 1, 1]
b = [2, 2, 2]
c = [3, 3, 3]
How can I create a new numpy array with each list as a column? Meaning that the new array would be [[1, 2, 3], [1, 2, 3], [1, 2, 3]]. I know how to do this by looping through the lists but I am not sure if there is an easier way to accomplish this. The numpy concatenate function seems to be close but I couldn't figure out how to get it to do what I'm after.
Thanks
Try with np.column_stack:
d = np.column_stack([a, b, c])
No need to use numpy. Python zip does a nice job:
In [606]: a = [1, 1, 1]
...: b = [2, 2, 2]
...: c = [3, 3, 3]
In [607]: abc = list(zip(a,b,c))
In [608]: abc
Out[608]: [(1, 2, 3), (1, 2, 3), (1, 2, 3)]
But if your heart is set on using numpy, a good way is to make a 2d array, and transpose it:
In [609]: np.array((a,b,c))
Out[609]:
array([[1, 1, 1],
[2, 2, 2],
[3, 3, 3]])
In [610]: np.array((a,b,c)).T
Out[610]:
array([[1, 2, 3],
[1, 2, 3],
[1, 2, 3]])
Others show how to do this with stack and column_stack, but underlying these is a concatenate. In one way or other they turn the lists into 2d arrays that can be joined on axis=1, e.g.
In [616]: np.concatenate([np.array(x)[:,None] for x in [a,b,c]], axis=1)
Out[616]:
array([[1, 2, 3],
[1, 2, 3],
[1, 2, 3]])
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.