Create product of lists, concatenated, in python - python

import itertools
x = [[0,0],[1,1]]
list(itertools.product(x,x))
produces
[([0, 0], [0, 0]), ([0, 0], [1, 1]), ([1, 1], [0, 0]), ([1, 1], [1, 1])]
But I'm looking for something that produces
[[0, 0, 0, 0], [0, 0, 1, 1], [1, 1, 0, 0], [1, 1, 1, 1]]

itertools.product is giving you that answer, you just have to concatenate the lists
[a + b for a, b in [([0, 0], [0, 0]), ([0, 0], [1, 1]), ([1, 1], [0, 0]), ([1, 1], [1, 1])]]
# [[0, 0, 0, 0], [0, 0, 1, 1], [1, 1, 0, 0], [1, 1, 1, 1]]

In that case, you can easily do without using itertools, using list comprehension:
x = [[0, 0], [1, 1]]
output = [a + b for b in x for a in x]
# [[0, 0, 0, 0], [1, 1, 0, 0], [0, 0, 1, 1], [1, 1, 1, 1]]
the equivalent without list comprehension would be:
output = []
for a in x:
for b in x:
output.append(a + b)
print(output)

You can use np.reshape if you are considering numpy array.
np.reshape(list(itertools.product(x,x)),(4,4))
Out[28]:
array([[0, 0, 0, 0],
[0, 0, 1, 1],
[1, 1, 0, 0],
[1, 1, 1, 1]])

Related

get lines where value does not exist

I'm trying to get from 2D list the lines where value = 2 does not exists:
[[0, 0, 1, 1],
[2, 1, 0, 2],
[2, 2, 2, 2],
[0, 0, 1, 0]]
I've been using:
for i in range(len(list)):
if list[i] in [list]:
# dot stuff
the problem here is that evrytime the code is using the actual line which is list[i] and ignore the the rest even if 2 does not exists on it
hope Iwas clear
Thank you
something like the below
lst = [[0, 0, 1, 1],
[2, 1, 0, 2],
[2, 2, 2, 2],
[0, 0, 1, 0]]
lst = [x for x in lst if 2 not in x]
print(lst)
output
[[0, 0, 1, 1], [0, 0, 1, 0]]
Is this your expected output?
[0, 0, 1, 1]
[0, 0, 1, 0]
This is the working code:
a = [[0, 0, 1, 1],
[2, 1, 0, 2],
[2, 2, 2, 2],
[0, 0, 1, 0]]
for i in range(len(a)):
if 2 not in a[i]:
print(a[i])

Appending a list to a list in a loop (Python)

I have a Python list with values, say:
a = [[0, 0, 0], [1, 0, 1], [1, 1, 0], [0, 1, 1]]
I want to append in a loop a new list 'b' to the list 'a'.
b = [[2, 1, 0], [3, 0, 1], [4, 1, 0], [2, 1, 1]]
The result should look like (when adding 'b' once to 'a'):
[[[0, 0, 0], [1, 0, 1], [1, 1, 0], [0, 1, 1]], [[2, 1, 0], [3, 0, 1], [4, 1, 0], [2, 1, 1]]]
Now, I want to append the list b N times to the list a.
Both a and b have shape (4,3)
The result should then have shape: (N+1,4,3)
How do I do this?
Native Python Lists will not behave the way you expect here as described in a few comments, so if you can use a 3rd party library, consider NumPy, which will behave more like a matrix of values as you expect and can then be converted back into a Python List
Setup
>>> a = [[0, 0, 0], [1, 0, 1], [1, 1, 0], [0, 1, 1]]
>>> b = [[2, 1, 0], [3, 0, 1], [4, 1, 0], [2, 1, 1]]
Replicate b vertically
the second argument to np.tile() describes the replications in each dimension
.reshape() to prepare it as a 3-dimensional array
>>> import numpy as np
>>> b_tiled = np.tile(np.array(b), (4,1)).reshape(4,4,3)
>>> b_tiled
array([[[2, 1, 0],
[3, 0, 1],
[4, 1, 0],
[2, 1, 1]],
[[2, 1, 0],
[3, 0, 1],
[4, 1, 0],
[2, 1, 1]],
[[2, 1, 0],
[3, 0, 1],
[4, 1, 0],
[2, 1, 1]],
[[2, 1, 0],
[3, 0, 1],
[4, 1, 0],
[2, 1, 1]]])
Collect a and b_tiled into the same array
NOTE a should be reshaped or [a] to match the shape of b_tiled
>>> np.vstack((np.array([a]), b_tiled))
array([[[0, 0, 0],
[1, 0, 1],
[1, 1, 0],
[0, 1, 1]],
[[2, 1, 0],
[3, 0, 1],
[4, 1, 0],
[2, 1, 1]],
[[2, 1, 0],
[3, 0, 1],
[4, 1, 0],
[2, 1, 1]],
[[2, 1, 0],
[3, 0, 1],
[4, 1, 0],
[2, 1, 1]],
[[2, 1, 0],
[3, 0, 1],
[4, 1, 0],
[2, 1, 1]]])
.tolist()
You can use .tolist() to make a native Python list again, though it may be more convenient to you as a numpy array
>>> np.vstack((np.array([a]), b_tiled)).tolist()
[[[0, 0, 0], [1, 0, 1], [1, 1, 0], [0, 1, 1]], [[2, 1, 0], [3, 0, 1], [4, 1, 0], [2, 1, 1]], [[2, 1, 0], [3, 0, 1], [4, 1, 0], [2, 1, 1]], [[2, 1, 0], [3, 0, 1], [4, 1, 0], [2, 1, 1]], [[2, 1, 0], [3, 0, 1], [4, 1, 0], [2, 1, 1]]]
Wrapping up my contributions to this discussion into an actual answer, summarizing what I think are the two best solutions:
1 Using NumPy arrays
Start from #Andreas' solution, but follow #ti7's lead and wrap the results into a numpy array, which manages the memory correctly:
result = np.array([a] + [b] * 5)
This solution brings the results into much more usable and versatile NumPy arrays.
2 Using deepcopy
Start from #Andreas' solution, and add a deep copy so the result does not alias parts of the array together:
import copy
result = [a] + [copy.deepcopy(b) for _ in range(5)]
This solution keeps the results as standard Python lists of lists.
Kuddos to #ti7 for noticing that the deep copy had to be done by instance of b rather than over the results, since deepcopy does not break aliasing that is internal to its input; and to #Andreas for assembling this line of code from the comments.
Caveat: since a is not deep copied here, result[0] is an alias for a, and changes to either will change both. Deep copy a too to avoid this.
add the lists and multiply the second list:
l = [a] + [b]*5
[[[0, 0, 0], [1, 0, 1], [1, 1, 0], [0, 1, 1]],
[[2, 1, 0], [3, 0, 1], [4, 1, 0], [2, 1, 1]],
[[2, 1, 0], [3, 0, 1], [4, 1, 0], [2, 1, 1]],
[[2, 1, 0], [3, 0, 1], [4, 1, 0], [2, 1, 1]],
[[2, 1, 0], [3, 0, 1], [4, 1, 0], [2, 1, 1]],
[[2, 1, 0], [3, 0, 1], [4, 1, 0], [2, 1, 1]]]
In case you want to modify the list values later on, be aware that you actually have 5x the SAME list referenced (as mentioned by #ti7), this means if you change one value in list b you change all, like this:
l[1][1][1] = "foo"
[[0, 0, 0], [1, 0, 1], [1, 1, 0], [0, 1, 1]]
[[2, 1, 0], [3, 'foo', 1], [4, 1, 0], [2, 1, 1]]
[[2, 1, 0], [3, 'foo', 1], [4, 1, 0], [2, 1, 1]]
[[2, 1, 0], [3, 'foo', 1], [4, 1, 0], [2, 1, 1]]
[[2, 1, 0], [3, 'foo', 1], [4, 1, 0], [2, 1, 1]]
[[2, 1, 0], [3, 'foo', 1], [4, 1, 0], [2, 1, 1]]
to avoid that use (as mentioned by #joanis):
l = [a] + [copy.deepcopy(b) for _ in range(5)]
[a+b*5] this will create
[[[0, 0, 0], [1, 0, 1], [1, 1, 0], [0, 1, 1], [2, 1, 0], [3, 0, 1], [4, 1, 0], [2, 1, 1], [2, 1, 0], [3, 0, 1], [4, 1, 0], [2, 1, 1], [2, 1, 0], [3, 0, 1], [4, 1, 0], [2, 1, 1], [2, 1, 0], [3, 0, 1], [4, 1, 0], [2, 1, 1], [2, 1, 0], [3, 0, 1], [4, 1, 0], [2, 1, 1]]]

How to create an array of binary digits of given unsigned integer numbers with Numpy?

I have an array of numbers between 0 and 3 and I want to create a 2D array of their binary digits.
in the future may be I need to have array of numbers between 0 and 7 or 0 to 15.
Currently my array is defined like this:
a = np.array([[0], [1], [2], [3]], dtype=np.uint8)
I used numpy unpackbits function:
b = np.unpackbits(a, axis=1)
and the result is this :
array([[0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 1],
[0, 0, 0, 0, 0, 0, 1, 0],
[0, 0, 0, 0, 0, 0, 1, 1]], dtype=uint8)
As you can see it created a 2d array with 8 items in column while I'm looking for 2 columns 2d array.
here is my desired array:
array([[0, 0],
[0, 1],
[1, 0],
[1, 1]])
Is this related to data type uint8 ?
what is your idea?
One way of approaching the problem is to just adapt your b to match your desired output via a simple slicing, similarly to what suggested in #GrzegorzSkibinski answer:
import numpy as np
def gen_bits_by_val(values):
n = int(max(values)).bit_length()
return np.unpackbits(values, axis=1)[:, -n:].copy()
print(gen_bits_by_val(a))
# [[0 0]
# [0 1]
# [1 0]
# [1 1]]
Alternatively, you could create a look-up table, similarly to what suggested in #WarrenWeckesser answer, using the following:
import numpy as np
def gen_bits_by_num(n):
values = np.arange(2 ** n, dtype=np.uint8).reshape(-1, 1)
return np.unpackbits(values, axis=1)[:, -n:].copy()
bits2 = gen_bits_by_num(2)
print(bits2)
# [[0 0]
# [0 1]
# [1 0]
# [1 1]]
which allows for all kind of uses thereby indicated, e.g.:
bits4 = gen_bits_by_num(4)
print(bits4[[1, 3, 12]])
# [[0 0 0 1]
# [0 0 1 1]
# [1 1 0 0]]
EDIT
Considering #PaulPanzer answer the line:
return np.unpackbits(values, axis=1)[:, -n:]
has been replaced with:
return np.unpackbits(values, axis=1)[:, -n:].copy()
which is more memory efficient.
It could have been replaced with:
return np.unpackbits(values << (8 - n), axis=1, count=n)
with similar effects.
You can use the count keyword. It cuts from the right so you also have to shift bits before applying unpackbits.
b = np.unpackbits(a<<6, axis=1, count=2)
b
# array([[0, 0],
# [0, 1],
# [1, 0],
# [1, 1]], dtype=uint8)
This produces a "clean" array:
b.flags
# C_CONTIGUOUS : True
# F_CONTIGUOUS : False
# OWNDATA : True
# WRITEABLE : True
# ALIGNED : True
# WRITEBACKIFCOPY : False
# UPDATEIFCOPY : False
In contrast, slicing the full 8-column output of unpackbits is in a sense a memory leak because the discarded columns will stay in memory as long as the slice lives.
You can truncate b to keep just the columns since the first column with 1:
b=b[:, int(np.argwhere(b.max(axis=0)==1)[0]):]
For such a small number of bits, you can use a lookup table.
For example, here bits2 is an array with shape (4, 2) that holds the bits of the integers 0, 1, 2, and 3. Index bits2 with the values from a to get the bits:
In [43]: bits2 = np.array([[0, 0], [0, 1], [1, 0], [1, 1]])
In [44]: a = np.array([[0], [1], [2], [3]], dtype=np.uint8)
In [45]: bits2[a[:, 0]]
Out[45]:
array([[0, 0],
[0, 1],
[1, 0],
[1, 1]])
This works fine for 3 or 4 bits, too:
In [46]: bits4 = np.array([[0, 0, 0, 0], [0, 0, 0, 1], [0, 0, 1, 0], [0, 0, 1, 1], [0, 1, 0, 0], [
...: 0, 1, 0, 1], [0, 1, 1, 0], [0, 1, 1, 1], [1, 0, 0, 0], [1, 0, 0, 1], [1, 0, 1, 0], [1, 0,
...: 1, 1], [1, 1, 0, 0], [1, 1, 0, 1], [1, 1, 1, 0], [1, 1, 1, 1]])
In [47]: bits4
Out[47]:
array([[0, 0, 0, 0],
[0, 0, 0, 1],
[0, 0, 1, 0],
[0, 0, 1, 1],
[0, 1, 0, 0],
[0, 1, 0, 1],
[0, 1, 1, 0],
[0, 1, 1, 1],
[1, 0, 0, 0],
[1, 0, 0, 1],
[1, 0, 1, 0],
[1, 0, 1, 1],
[1, 1, 0, 0],
[1, 1, 0, 1],
[1, 1, 1, 0],
[1, 1, 1, 1]])
In [48]: x = np.array([0, 1, 5, 14, 9, 8, 15])
In [49]: bits4[x]
Out[49]:
array([[0, 0, 0, 0],
[0, 0, 0, 1],
[0, 1, 0, 1],
[1, 1, 1, 0],
[1, 0, 0, 1],
[1, 0, 0, 0],
[1, 1, 1, 1]])

How to Check if a Matrix is in a List of Matrices Python

This is the list of matrices;
[matrix([[1, 0],
[1, 0],
[1, 0],
[1, 0]]),
matrix([[0, 0, 0, 0],
[1, 1, 1, 1]]),
matrix([[0, 1],
[0, 1],
[0, 1],
[0, 1]]),
matrix([[0, 0, 0, 0],
[1, 1, 1, 1]]),
matrix([[1, 1, 1, 1],
[0, 0, 0, 0]])]
and I want to check if a matrix is already inside the list example;
a = matrix([[0, 0, 0, 1],
[1, 1, 1, 0]])
So if a is in m then print True else print False
I assume you are using NumPy. If this is the case, don't use np.matrix, use np.array. np.matrix exists almost exclusively for legacy reasons and has undesirable features.
You can use any with a generator comprehension and np.array_equal. This will short-circuit to True if the array is found in the input list, otherwise return False.
import numpy as np
L = [np.array([[1, 0], [1, 0], [1, 0], [1, 0]]),
np.array([[0, 0, 0, 0], [1, 1, 1, 1]]),
np.array([[0, 1], [0, 1], [0, 1], [0, 1]]),
np.array([[0, 0, 0, 0], [1, 1, 1, 1]]),
np.array([[1, 1, 1, 1], [0, 0, 0, 0]])]
A = np.array([[0, 0, 0, 1], [1, 1, 1, 0]])
res = any(np.array_equal(A, i) for i in L) # False

Change all positive values in array to 1 (Python)

So I have several 3D arrays that I need to add together. Each array consists of entries with either 0 or 1. All arrays also have the same dimension. Now, when I add these arrays together some of the values overlap (which they do). However, I just need to know how the structure of the total combined array is, which means that I don't need the values 1, 2 or 3 when 2 or 3 arrays have overlapped. This also just need to be one, and of course, wherever there is a zero, the value zero just need to remain zero.
So basically what I have is:
array1 =
[[[1, 0, 0], [0, 0, 0], [0, 0, 0]],
[[0, 1, 0], [0, 0, 0], [0, 0, 0]],
[[0, 0, 1], [1, 1, 1], [0, 0, 0]]]
array2 =
[[[1, 0, 0], [0, 1, 0], [0, 0, 0]],
[[0, 0, 0], [1, 1, 0], [0, 0, 0]],
[[0, 0, 1], [0, 1, 0], [0, 0, 0]]]
So when adding them together I get:
array_total = array1 + array2 =
[[[2, 0, 0], [0, 1, 0], [0, 0, 0]],
[[0, 1, 0], [1, 1, 0], [0, 0, 0]],
[[0, 0, 2], [1, 2, 1], [0, 0, 0]]]
Where I actually want it to give me:
array_total = array1 + array2 =
[[[1, 0, 0], [0, 1, 0], [0, 0, 0]],
[[0, 1, 0], [1, 1, 0], [0, 0, 0]],
[[0, 0, 1], [1, 1, 1], [0, 0, 0]]]
So can anyone give me a hint to how this is done ?
(Assuming those are numpy arrays, or array1 + array2 would behave differently).
If you want to "change all positive values to 1", you can do this
array_total[array_total > 0] = 1
But what you actually want is an array that has a 1 where array1 or array2 has a 1, so just write it directly like that:
array_total = array1 | array2
Example:
>>> array1 = np.array([[[1, 0, 0], [0, 0, 0], [0, 0, 0]],
... [[0, 1, 0], [0, 0, 0], [0, 0, 0]],
... [[0, 0, 1], [1, 1, 1], [0, 0, 0]]])
>>> array2 = np.array([[[1, 0, 0], [0, 1, 0], [0, 0, 0]],
... [[0, 0, 0], [1, 1, 0], [0, 0, 0]],
... [[0, 0, 1], [0, 1, 0], [0, 0, 0]]])
>>> array1 | array2
array([[[1, 0, 0], [0, 1, 0], [0, 0, 0]],
[[0, 1, 0], [1, 1, 0], [0, 0, 0]],
[[0, 0, 1], [1, 1, 1], [0, 0, 0]]])

Categories

Resources