there is an array "arr". i copied in another array "xyz". i want to update array "xyz". but getting wrong result.
metrix = [[1, 2, 2], [2, 2, 2], [2, 2, 1]]
n,m = 3,3
def package(n,m,arr):
xyz = arr.copy()
for i in range(n):
for j in range(m):
if arr[i][j] == 1:
xyz[i][j]=0
print("arr",arr)
print("xyz",xyz)
package(n,m,metrix)
o/p:
arr [[0, 2, 2], [2, 2, 2], [2, 2, 0]]
xyz [[0, 2, 2], [2, 2, 2], [2, 2, 0]]
expected o/p:
arr [[1, 2, 2], [2, 2, 2], [2, 2, 1]]
xyz [[0, 2, 2], [2, 2, 2], [2, 2, 0]]
This is because array.copy performs a shallow copy.
Source - https://docs.python.org/3/tutorial/datastructures.html
If you only had an array of simple data types - string, number, etc, a shallow copy would have worked. But in your case, it is an array of arrays.
Use deepcopy instead.
from copy import deepcopy
arr = [ [1,2,3], [1,2,3] ]
arr_copy = deepcopy(arr)
arr_copy[0][0] = 7
print(arr)
print(arr_copy)
Output -
[[1, 2, 3], [1, 2, 3]]
[[7, 2, 3], [1, 2, 3]]
list.copy will return a shallow copy. For nested data structures you must use a deep copy.
from copy import deepcopy
xyz = deepcopy(arr)
metrix = [[1, 2, 2], [2, 2, 2], [2, 2, 1]]
n,m = 3,3
def package(n,m,arr):
xyz = [[row[i] for row in arr] for i in range(n)]
for j in range(n):
for i in range(m):
if arr[i][j] == 1:
xyz[i][j] = 0
print("arr",arr)
print("xyz",xyz)
package(n,m,metrix)
This works
Related
For a given N, I have a list of all numbers from 0 to N-1
A = list(range(0,N));
and I want to find a list of all possible decompositions into lists of sizes two or higher, without repetitions. For example, for N=4 I have
A = [0,1,2,3];
and the output I want is
OUT = [[[0, 1, 2, 3]], [[0, 1], [2, 3]], [[0, 2], [1, 3]], [[0, 3], [1, 2]]];
Up to N=5, the decomposition of the initial list into only two pieces (of length 2 and 3) makes the problem very easy. However, I can't find a way to do it for higher N, since the lists of length four must be further split into two lists of length 2.
Does anyone have any suggestions on how to solve this? I feel there must be a straightforward recursive trick to do this, but I have been trying for a day now, and I am a little stuck!
Thanks!
PS: the results for N smaller than 6 are:
N=1) OUT = [[[0]]];
N=2) OUT = [[[0, 1]]];
N=3) OUT = [[[0, 1, 2]]];
N=4) OUT = [[[0, 1, 2, 3]], [[0, 1], [2, 3]], [[0, 2], [1, 3]], [[0, 3], [1, 2]]];
N=5) OUT = [[[0, 1, 2, 3, 4]], [[0, 1], [2, 3, 4]], [[0, 2], [1, 3, 4]], [[0, 3], [1, 2, 4]], [[0, 4], [1, 2, 3]], [[1, 2], [0, 3, 4]], [[1, 3], [0, 2, 4]], [[1, 4], [0, 2, 3]], [[2, 3], [0, 1, 4]], [[2, 4], [0, 1, 3]], [[3, 4], [0, 1, 2]]];
PPS: I am a physicist and haven't been programming for a while; the code probably looks terrible, and the problem might be very easy... sorry for that!
Consider the last item i.e N-1, suppose we have two sets of combinations. one for list(range(0,N-1)) and one for list(range(0,N-2)). Now, if you want to put the last item in these combinations, you should have a different approach for each one of them, which I've explained below:
Combinations of list(range(0, N-1)): To put the last item in these combinations, you have no choice other than to put it in one of the sets that are already available to understand this better consider that you have all combinations for four and now you want to add 5 to this combination. So you have :
[[[0, 1, 2, 3]], [[0, 1], [2, 3]], [[0, 2], [1, 3]], [[0, 3], [1, 2]]]
Adding last item( i.e 4) to these combination would get us something like bellow:
[[[0, 1, 2, 3, 4]], [[0, 1, 4], [2, 3]], [[0, 1], [2, 3, 4]], [[0, 2, 4], [1, 3]], [[0, 2], [1, 3, 4]], [[0, 3, 4], [1, 2]], [[0, 3], [1, 2, 4]]]
We put 4 in every combination and make new combinations out of them. So for this part, we need a recursive call for N-1. As you can see in this situation, each sets that N-1 is in has at least three items. That's because we expanded our set, which already existed and had at least two items.
Combinations of N-2 items: I've considered this for when N-1 is in a set with only two items. To find these combinations, we need to select one of the rest N-1 items and consider that selected item with item N-1 as one set and find every other combination for the rest of N-2 items. To give you an example again, consider N = 5 so the last item is 4. If we want to pair the last item with 3, we could build all combinations for (0, 1, 2) and put pair of the (3, 4) to the mix. It would be something like this for N=5:
[[[0 , 1 , 2] , [3 , 4]] , [[0 , 1 , 3] , [2 , 4]] , [[0 , 2 , 3] , [1 , 4]] , [[ 1 , 2 , 3] , [0 , 4]]]
I've implemented this using recursive functions in python. I'm not a python developer, so there may be some enhancements in implementations, but the algorithm is working fine:
import copy
def recursive_builder(arr):
if len(arr) == 3:
return [[[arr[0], arr[1], arr[2]]]]
if len(arr) == 4:
return [[[arr[0], arr[1], arr[2], arr[3]]], [[arr[0], arr[1]], [arr[2], arr[3]]], [[arr[0], arr[2]], [arr[1], arr[3]]], [[arr[0], arr[3]], [arr[1], arr[2]]]]
temp_array = arr[0:len(arr)-1]
recursive_builder_one_step_before = recursive_builder(temp_array)
new_from_one_step_before = []
last_item = arr[len(arr)-1]
for item in recursive_builder_one_step_before:
for i in range(0 , len(item)):
temp_item = copy.deepcopy(item)
temp_item[i].append(last_item)
new_from_one_step_before.append(temp_item)
new_from_two_step_before = []
for i in range(0 , len(temp_array)):
new_arr = temp_array[:i] + temp_array[i+1 :]
recursive_builder_two_step_before = recursive_builder(new_arr)
new_from_two_step_before_inner = []
for item in recursive_builder_two_step_before:
new_item = item + [[temp_array[i] , last_item]]
new_from_two_step_before_inner.append(new_item)
new_from_two_step_before = new_from_two_step_before + new_from_two_step_before_inner
return new_from_two_step_before + new_from_one_step_before
N=6
recursive_builder(list(range(0,N)))
You could run this code on Colab
Edit: I've added memorization to improve the performance a little bit, but my build_from_memory is not O(1), so the improvement could be much better if I could improve the performance of that function.
memotization_dict = {3 : [[[0, 1, 2]]] , 4 : [[[0, 1, 2, 3]], [[0, 1], [2, 3]], [[0, 2], [1, 3]], [[0, 3], [1, 2]]] }
def build_from_memory(arr):
memory = memotization_dict[len(arr)]
ret_val = []
for item in memory:
l2 = []
for i in item:
l1 = []
for j in i:
l1.append(arr[j])
l2.append(l1)
ret_val.append(l2)
return ret_val
def recursive_builder(arr):
if len(arr) in memotization_dict:
return build_from_memory(arr)
temp_array = arr[0:len(arr)-1]
recursive_builder_one_step_before = recursive_builder(temp_array)
new_from_one_step_before = []
last_item = arr[len(arr)-1]
for item in recursive_builder_one_step_before:
for i in range(0 , len(item)):
temp_item = copy.deepcopy(item)
temp_item[i].append(last_item)
new_from_one_step_before.append(temp_item)
new_from_two_step_before = []
for i in range(0 , len(temp_array)):
new_arr = temp_array[:i] + temp_array[i+1 :]
recursive_builder_two_step_before = recursive_builder(new_arr)
new_from_two_step_before_inner = []
for item in recursive_builder_two_step_before:
new_item = item + [[temp_array[i] , last_item]]
new_from_two_step_before_inner.append(new_item)
new_from_two_step_before = new_from_two_step_before + new_from_two_step_before_inner
if(arr == list(range(0 , len(arr)))):
memotization_dict[len(arr)] = new_from_two_step_before + new_from_one_step_before
return new_from_two_step_before + new_from_one_step_before
Please could I have help with the following query in Python 3.9.
I have the following sublists:
[0, 1]
[1, 3]
[2, 5]
I would like to make a new list with each of these sublists repeated a different number of times. Required output:
[[0,1],[0,1],[0,1],[1,3],[1,3],[2,5],[2,5],[2,5],[2,5]]
I have tried doing the following:
[[[0,1]]*3,[[1,3]]*2,[[2,5]]*4]
However I get this:
[[[0,1],[0,1],[0,1]],[[1,3],[1,3]],[[2,5],[2,5],[2,5],[2,5]]]
How do I get my desired output? Or alternatively, how do I just flatten it by one level? Thank you
You can just unpack the sublists:
[*[[0,1]]*3, *[[1,3]]*2, *[[2,5]]*4]
# [[0, 1], [0, 1], [0, 1], [1, 3], [1, 3], [2, 5], [2, 5], [2, 5], [2, 5]]
Note however, that the resulting sublists are not independent, but references to the same list objects (changes made to one sublist will be reflected in all the equal others)! Better use generators/comprehensions:
[*([0,1] for _ in range(3)),
*([1,3] for _ in range(2)),
*([2,5] for _ in range(4))]
# [[0, 1], [0, 1], [0, 1], [1, 3], [1, 3], [2, 5], [2, 5], [2, 5], [2, 5]]
The more general question of 1-level flattening has been asked and answered multiple times, but the main options are the nested comprehension:
[x for sub in lst for x in sub]
or itertools.chain:
[*chain(lst)]
You can use list loop:
r1 = [0, 1]
r2 = [1, 3]
r3 = [2, 5]
h = [*(r1 for x in range(3)),
*(r2 for x in range(2)),
*(r3 for x in range(4))]
print(h)
I am trying to create a python program to shuffle an array so that the horizontal and vertical rows never have a repeat number.
Input: [1,2,3,4]
Output:
1 2 3 4
2 3 4 1
3 4 1 2
4 1 2 3
My program calculates the shifting of each element correctly, but when it appends the list to the output list, the output list only has repeat copies of the last item in the list.
def numbers(list_of_numbers):
finalValues = [list_of_numbers]
#print(list_of_numbers)
for i in range(1,len(list_of_numbers)):
print("Last array of final: ", finalValues[-1])
tempArray = finalValues[-1]
print("Temp Array: ",tempArray)
temp = tempArray[0]
for j in range(0,len(list_of_numbers)-1):
tempArray[j] = tempArray[j+1]
tempArray[-1] = temp
finalValues.append(tempArray)
print("Final Values: ",finalValues)
return finalValues
numbers([1,2,3,4])
Program Output
[[4, 1, 2, 3], [4, 1, 2, 3], [4, 1, 2, 3], [4, 1, 2, 3]]
Correct Output
[[1,2,3,4], [2,3,4,1], [3,4,1,2], [4,1,2,3]]
The problem comes from the line:
tempArray = finalValues[-1]
You don't create a copy of the previous list, but only a new name to refer to it. After that, all changes you make to tempArray are actually changes to this list, and when you finally do:
finalValues.append(tempArray)
you just add another reference to this same list in finalValues.
In the end, finalValues contains 4 references to the same list, which you can access with finalValues[0], finalValues[1]...
What you need is to create a new list by copying the previous one. One way to do it is to use a slice:
tempArray = finalValues[-1][:]
You can find other ways to close or copy a list in this question
And so, the complete code gives the expected output:
Last array of final: [1, 2, 3, 4]
Temp Array: [1, 2, 3, 4]
Final Values: [[1, 2, 3, 4], [2, 3, 4, 1]]
Last array of final: [2, 3, 4, 1]
Temp Array: [2, 3, 4, 1]
Final Values: [[1, 2, 3, 4], [2, 3, 4, 1], [3, 4, 1, 2]]
Last array of final: [3, 4, 1, 2]
Temp Array: [3, 4, 1, 2]
Final Values: [[1, 2, 3, 4], [2, 3, 4, 1], [3, 4, 1, 2], [4, 1, 2, 3]]
[[1, 2, 3, 4], [2, 3, 4, 1], [3, 4, 1, 2], [4, 1, 2, 3]]
Thierry has provided a very comprehensive explanation of why your code doesn't work as you expect. As such it is the best answer to your question.I have added my answer just as an example of you you can code this in a less complex way .
create the 2d list with the first index as list of numbers. for each iteration take the last index of temp and slice from index 1 to the end then add on index 0.
then return the list
def numbers(list_of_numbers):
temp = [list_of_numbers]
for _ in range(1, len(list_of_numbers)):
temp.append(temp[-1][1:] + temp[-1][0:1])
return temp
print(numbers([1,2,3,4]))
OUTPUT
[[1, 2, 3, 4], [2, 3, 4, 1], [3, 4, 1, 2], [4, 1, 2, 3]]
The problems is in shallow assignment of arrays. You should make deep copy, to really clone arrays, to make them independent.
I did it in your own code. There are a few changes of your code:
import copy that it have been added to first row.
Three usages of copy.deepcopy function instead of =(simple assignment).
import copy
def numbers(list_of_numbers):
finalValues = copy.deepcopy([list_of_numbers])
#print(list_of_numbers)
for i in range(1,len(list_of_numbers)):
print("Last array of final: ", finalValues[-1])
tempArray = copy.deepcopy(finalValues[-1])
print("Temp Array: ",tempArray)
temp = tempArray[0]
for j in range(0,len(list_of_numbers)-1):
tempArray[j] = tempArray[j+1]
tempArray[-1] = temp
finalValues.append(copy.deepcopy(tempArray))
print("Final Values: ",finalValues)
return finalValues
numbers([1,2,3,4])
Program Output
[[4, 1, 2, 3], [4, 1, 2, 3], [4, 1, 2, 3], [4, 1, 2, 3]]
Program Output
[[1,2,3,4], [2,3,4,1], [3,4,1,2], [4,1,2,3]]
How can i create a new list combing the first values of my old lists and then the second ones etc..
list_1 = [1,2,3,4]
list_2 = [1,2,3,4]
list_3 = [1,2,3,4]
new_list = [[1,1,1],[2,2,2],[3,3,3],[4,4,4]]
Pure python:
You can use zip:
new_list = list(map(list, zip(list_1,list_2,list_3)))
>>> new_list
[[1, 1, 1], [2, 2, 2], [3, 3, 3], [4, 4, 4]]
Alternative:
numpy:
import numpy as np
new_list = np.array([list_1,list_2,list_3]).T.tolist()
>>> new_list
[[1, 1, 1], [2, 2, 2], [3, 3, 3], [4, 4, 4]]
Here's another way to do it using list comprehensions.
new_list = [list(args) for args in zip(list_1, list_2, list_3)]
If we enumerate one list the index from that list to all 3
new_list = [[list_1[i], list_2[i], list_3[i]] for i, _ in enumerate(list_1)]
# [[1, 1, 1], [2, 2, 2], [3, 3, 3], [4, 4, 4]]
This is quite strange, I am quite sure that the code works without the while loop:
target = [[1],]
add = [2,4]
count = 0
while count < 2:
temp = []
for i in target:
temp += [i, i]
target = temp[:]
print('before', target)
idx = 0
while idx < len(target):
target[idx].append(add[idx])
idx += 1
print('after', target)
add += add
count += 1
Here I have target as a nested list that contains number, I have add just as a list of numbers. My idea is to double the target every loop, and add one item from add to one sub-list of target and double the add afterwards.
I am getting the result:
before [[1], [1]]
after [[1, 2, 4], [1, 2, 4]]
before [[1, 2, 4], [1, 2, 4], [1, 2, 4], [1, 2, 4]]
after [[1, 2, 4, 2, 4, 2, 4], [1, 2, 4, 2, 4, 2, 4], [1, 2, 4, 2, 4, 2, 4], [1, 2, 4, 2, 4, 2, 4]]
if you look at the before and after, the whole add was added to each sub-list of target, instead of adding add[0] to target[0], then add[1] to target[1] showed below as my expectation:
before [[1], [1]]
after [[1, 2], [1, 4]]
before [[1, 2], [1, 4], [1, 2], [1, 4]]
after [[1, 2, 2], [1, 4, 4], [1, 2, 2], [1, 4, 4]]
without the outer while loop:
target = [[1],[1]]
add = [2,4]
count = 0
idx = 0
while idx < len(target):
target[idx].append(add[idx])
idx += 1
print(target)
# >>>
[[1, 2], [1, 4]]
Can't really understand why
The problem is in this block of code:
temp = []
for i in target:
temp += [i, i]
target = temp[:]
When it loops over target, it pulls out each item, in this case a list ([1]). This specific list (not copies) is then added twice to the temp list. What you need to do is copy when building temp:
temp = []
for i in target:
temp += [i[:], i[:]]
target = temp