Related
N = 14
SIZE = 6
lst = range(N+1)
sum_n_combs = [
list(comb) for comb in it.combinations_with_replacement(lst, SIZE)
if sum(comb) == N
]
print(sum_n_combs)
output [[0, 0, 0, 0, 0, 14], [0, 0, 0, 0, 1, 13], [0, 0, 0, 0, 2, 12], [0, 0, 0, 0, 3, 11], [0, 0, 0, 0, 4, 10], [0, 0, 0, 0, 5, 9], [0, 0, 0, 0, 6, 8], [0, 0, 0, 0, 7, 7], [0, 0, 0, 1, 1, 12], [0, 0, 0, 1, 2, 11], [0, 0, 0, 1, 3, 10], [0, 0, 0, 1, 4, 9], [0, 0, 0, 1, 5, 8], [0, 0, 0, 1, 6, 7], [0, 0, 0, 2, 2, 10], [0, 0, 0, 2, 3, 9], [0, 0, 0, 2, 4, 8], [0, 0, 0, 2, 5, 7], [0, 0, 0, 2, 6, 6], [0, 0, 0, 3, 3, 8], [0, 0, 0, 3, 4, 7], [0, 0, 0, 3, 5, 6], [0, 0, 0, 4, 4, 6], [0, 0, 0, 4, 5, 5], [0, 0, 1, 1, 1, 11], [0, 0, 1, 1, 2, 10], [0, 0, 1, 1, 3, 9], [0, 0, 1, 1, 4, 8], [0, 0, 1, 1, 5, 7], [0, 0, 1, 1, 6, 6], [0, 0, 1, 2, 2, 9], [0, 0, 1, 2, 3, 8], [0, 0, 1, 2, 4, 7], [0, 0, 1, 2, 5, 6], [0, 0, 1, 3, 3, 7], [0, 0, 1, 3, 4, 6], [0, 0, 1, 3, 5, 5], [0, 0, 1, 4, 4, 5], [0, 0, 2, 2, 2, 8], [0, 0, 2, 2, 3, 7], [0, 0, 2, 2, 4, 6], [0, 0, 2, 2, 5, 5], [0, 0, 2, 3, 3, 6], [0, 0, 2, 3, 4, 5], [0, 0, 2, 4, 4, 4], [0, 0, 3, 3, 3, 5], [0, 0, 3, 3, 4, 4], [0, 1, 1, 1, 1, 10], [0, 1, 1, 1, 2, 9], [0, 1, 1, 1, 3, 8], [0, 1, 1, 1, 4, 7], [0, 1, 1, 1, 5, 6], [0, 1, 1, 2, 2, 8], [0, 1, 1, 2, 3, 7], [0, 1, 1, 2, 4, 6], [0, 1, 1, 2, 5, 5], [0, 1, 1, 3, 3, 6], [0, 1, 1, 3, 4, 5], [0, 1, 1, 4, 4, 4], [0, 1, 2, 2, 2, 7], [0, 1, 2, 2, 3, 6], [0, 1, 2, 2, 4, 5], [0, 1, 2, 3, 3, 5], [0, 1, 2, 3, 4, 4], [0, 1, 3, 3, 3, 4], [0, 2, 2, 2, 2, 6], [0, 2, 2, 2, 3, 5], [0, 2, 2, 2, 4, 4], [0, 2, 2, 3, 3, 4], [0, 2, 3, 3, 3, 3], [1, 1, 1, 1, 1, 9], [1, 1, 1, 1, 2, 8], [1, 1, 1, 1, 3, 7], [1, 1, 1, 1, 4, 6], [1, 1, 1, 1, 5, 5], [1, 1, 1, 2, 2, 7], [1, 1, 1, 2, 3, 6], [1, 1, 1, 2, 4, 5], [1, 1, 1, 3, 3, 5], [1, 1, 1, 3, 4, 4], [1, 1, 2, 2, 2, 6], [1, 1, 2, 2, 3, 5], [1, 1, 2, 2, 4, 4], [1, 1, 2, 3, 3, 4], [1, 1, 3, 3, 3, 3], [1, 2, 2, 2, 2, 5], [1, 2, 2, 2, 3, 4], [1, 2, 2, 3, 3, 3], [2, 2, 2, 2, 2, 4], [2, 2, 2, 2, 3, 3]]
As "combinations with replacement" does, this function only produces the combination. I want permutation of each combination without repetition.
For example
[[0, 0, 0, 0, 0, 14], [0, 0, 0, 0, 14, 0] ... [3, 2, 3, 2, 2, 2], [3, 3, 2, 2, 2]]
When I tried to do this by
ret=[]
for i in range(90):
ret.extend(it.permutations(sum_n_combs[i], SIZE))
Time complexity was exponential, and made repititions
When I tested with one list sum_n_combs[0], which is [0, 0, 0, 0, 0, 14] produced 720 permutations when I only want 6 of them(14 at each different place).
How can I make permutation without repetition for each combination in an efficient way?
You could separate this in two steps:
generate partitions of the targeted sum
generate distinct permutations of each partition
Recursive generators will allow you to get the results efficiently without trial/error filtering and without storing everything in memory:
def partitions(N,size):
if size == 1 :
yield (N,) # base case, only 1 part
return
for a in range(N//size+1): # smaller part followed by
for p in partitions(N-a*size,size-1): # equal or larger ones
yield (a, *(n+a for n in p)) # recursing on delta only
def permuteDistinct(A):
if len(A) == 1:
yield tuple(A) # single value
return
used = set() # track starting value
for i,n in enumerate(A): # for each starting value
if n in used: continue # not yet used
used.add(n)
for p in permuteDistinct(A[:i]+A[i+1:]):
yield (n,*p) # starting value & rest
output:
N = 14
SIZE = 6
PARTITIONS...
for part in partitions(N,SIZE):
print(part)
(0, 0, 0, 0, 0, 14)
(0, 0, 0, 0, 1, 13)
(0, 0, 0, 0, 2, 12)
(0, 0, 0, 0, 3, 11)
(0, 0, 0, 0, 4, 10)
(0, 0, 0, 0, 5, 9)
(0, 0, 0, 0, 6, 8)
(0, 0, 0, 0, 7, 7)
(0, 0, 0, 1, 1, 12)
(0, 0, 0, 1, 2, 11)
(0, 0, 0, 1, 3, 10)
(0, 0, 0, 1, 4, 9)
(0, 0, 0, 1, 5, 8)
(0, 0, 0, 1, 6, 7)
(0, 0, 0, 2, 2, 10)
(0, 0, 0, 2, 3, 9)
(0, 0, 0, 2, 4, 8)
(0, 0, 0, 2, 5, 7)
(0, 0, 0, 2, 6, 6)
(0, 0, 0, 3, 3, 8)
(0, 0, 0, 3, 4, 7)
(0, 0, 0, 3, 5, 6)
(0, 0, 0, 4, 4, 6)
(0, 0, 0, 4, 5, 5)
...
PERMUTED PARTITIONS (DISTINCT):
for part in partitions(N,SIZE):
for permutedPart in permuteDistinct(part):
print(permutedPart)
(0, 0, 0, 0, 0, 14)
(0, 0, 0, 0, 14, 0)
(0, 0, 0, 14, 0, 0)
(0, 0, 14, 0, 0, 0)
(0, 14, 0, 0, 0, 0)
(14, 0, 0, 0, 0, 0)
(0, 0, 0, 0, 1, 13)
(0, 0, 0, 0, 13, 1)
(0, 0, 0, 1, 0, 13)
(0, 0, 0, 1, 13, 0)
(0, 0, 0, 13, 0, 1)
(0, 0, 0, 13, 1, 0)
(0, 0, 1, 0, 0, 13)
(0, 0, 1, 0, 13, 0)
(0, 0, 1, 13, 0, 0)
(0, 0, 13, 0, 0, 1)
(0, 0, 13, 0, 1, 0)
(0, 0, 13, 1, 0, 0)
...
num1 = [1,2,3,4,5]
num2 = [1,2,3,4,5]
arr1 = [[0]*(len(num2)+1)]*(len(num1)+1)
arr2 = [[0 for _ in range(len(num2)+1)] for _ in range(len(num1)+1)]
I get a different answer when I define arr1 and arr2.
Aren't arr1 and arr2 create the same 2D array?
They are not the same. arr1 is a list with (len(nums1)+1) references to the same list [0]*(len(nums2)+1). So when you modify an element in one of them, all references will see this change as well.
For example,
>>> arr1[0][0] += 1
>>> print(arr1)
[[1, 0, 0, 0, 0, 0],
[1, 0, 0, 0, 0, 0],
[1, 0, 0, 0, 0, 0],
[1, 0, 0, 0, 0, 0],
[1, 0, 0, 0, 0, 0],
[1, 0, 0, 0, 0, 0]]
arr2 doesn't suffer from this problem because it has len(nums1)+1 distinct lists:
>>> arr2[0][0] += 1
>>> print(arr2)
[[1, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0]]
A better way to see the difference is to use a random number to fill the entries.
from random import randrange
num1 = [1,2,3,4,5]
num2 = [1,2,3,4,5]
arr1 = [[randrange(10)]*(len(nums2)+1)]*(len(nums1)+1)
arr2 = [[randrange(10) for _ in range(len(nums2)+1)] for _ in range(len(nums1)+1)]
print(arr1)
print(arr2)
The output is:
[[5, 5, 5, 5, 5, 5], [5, 5, 5, 5, 5, 5], [5, 5, 5, 5, 5, 5], [5, 5, 5, 5, 5, 5], [5, 5, 5, 5, 5, 5], [5, 5, 5, 5, 5, 5]]
[[7, 4, 2, 4, 0, 3], [7, 5, 1, 0, 1, 7], [4, 4, 1, 0, 2, 1], [2, 3, 6, 2, 6, 7], [6, 6, 6, 0, 3, 3], [0, 4, 5, 0, 6, 6]]
You can see that for the arr1, it populates every entry with the same number; while for arr2, the entries are all truly random. This is because arr1 is constructed by expanding a list of just one number, which is [5] here.
Say I had a list:
lis = [0, 0, 0, 0, 0, 0, 0, 0, 0 ,0, 0, 0, 0, 0, 0, 0]
Would there be any way too take out the first 4 values of the list, make them :
[4, 2, 2, 4]
and the put them back in the list so the list now looks like
[4, 2, 2, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
and do all of this without making the list
[[0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0]]
at the start.
Also if possible, can you make a loop to do this for all the 4 values available.
So that the list now looks like:
[4, 2, 2, 4, 4, 2, 2, 4, 4, 2, 2, 4, 4, 2, 2, 4]
lis = [0, 0, 0, 0, 0, 0, 0, 0, 0 ,0, 0, 0, 0, 0, 0, 0]
fill = [4, 2, 2, 4]
for i in range(0, len(lis), len(fill)):
lis[i : i + len(fill)] = fill
print(lis)
This outputs:
[4, 2, 2, 4, 4, 2, 2, 4, 4, 2, 2, 4, 4, 2, 2, 4]
Just do like this:
lis1 = [0, 0, 0, 0, 0, 0, 0, 0, 0 ,0, 0, 0, 0, 0, 0, 0]
# change first 4 index
lis1[:4] = 4,2,2,4
print(lis1)
# [4, 2, 2, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
lis2 = [0, 0, 0, 0, 0, 0, 0, 0, 0 ,0, 0, 0, 0, 0, 0, 0]
# change every 4 index in loop
for i in range(0,len(lis2),4):
lis2[i:i+4] = 4,2,2,4
print(lis2)
# [4, 2, 2, 4, 4, 2, 2, 4, 4, 2, 2, 4, 4, 2, 2, 4]
Use itertools.cycle and itertools.islice:
from itertools import cycle, islice
lis = [0, 0, 0, 0, 0, 0, 0, 0, 0 ,0, 0, 0, 0, 0, 0, 0]
out = list(map(int, islice(cycle('4224'), len(lis))))
print(out)
# [4, 2, 2, 4, 4, 2, 2, 4, 4, 2, 2, 4, 4, 2, 2, 4]
Or a simpler way (without any imports):
lis = [0, 0, 0, 0, 0, 0, 0, 0, 0 ,0, 0, 0, 0, 0, 0, 0]
out = list(map(int, '4224' * (len(lis) // 4)))
print(out)
# [4, 2, 2, 4, 4, 2, 2, 4, 4, 2, 2, 4, 4, 2, 2, 4]
def list_function(original_list, list_of_value_to_subst):
original_list[:len(list_of_value_to_subst)]=list_of_value_to_subst
print (original_list)
subst_list = list(map(int, list_of_value_to_subst * (len(original_list) // len(list_of_value_to_subst))))
print (subst_list)
lis = [0, 0, 0, 0, 0, 0, 0, 0, 0 ,0, 0, 0, 0, 0, 0, 0]
list_of_value_to_subst=[4, 2, 2, 4]
list_function(lis, list_of_value_to_subst)
output:
[4, 2, 2, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
[4, 2, 2, 4, 4, 2, 2, 4, 4, 2, 2, 4, 4, 2, 2, 4]
Another solution, would be to do the following:
For your first question:
lis = [0, 0, 0, 0, 0, 0, 0, 0, 0 ,0, 0, 0, 0, 0, 0, 0]
ins = [4, 2, 2, 4]
lis[:len(ins)] = ins
print(lis)
Output:
[4, 2, 2, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
For your second question:
lis = [0, 0, 0, 0, 0, 0, 0, 0, 0 ,0, 0, 0, 0, 0, 0, 0]
lis = ins * int(len(lis) / len(ins))
print(lis)
Output:
[4, 2, 2, 4, 4, 2, 2, 4, 4, 2, 2, 4, 4, 2, 2, 4]
Given the list of numbers you want to replace the first part of lis with:
replace_lis = [4, 2, 2, 4]
You can iterate over the length of replace_lis, and fill in the index spots in lis accordingly:
for i in range(len(replace_lis)):
if i < len(lis):
lis[i] = replace_lis[i]
The i < len(lis) is if replace_lis could be bigger than lis. If there is no chance of that, you can safely omit that if statement.
Here is your original list:
lis = [0, 0, 0, 0, 0, 0, 0, 0, 0 ,0, 0, 0, 0, 0, 0, 0]
and you'd like to replace the first 4 items with:
[4, 2, 2, 4]
Let's assign the new values a new variable. Let's call it update. So:
update = [4, 2, 2, 4]
Here is your code:
lis = [0, 0, 0, 0, 0, 0, 0, 0, 0 ,0, 0, 0, 0, 0, 0, 0]
update = [4, 2, 2, 4]
for i in range(0, len(update)):
lis[i] = update[i]
print(lis)
I have a 2D array. I have to initialize the array by marking the number of 1's in the rectangle from the top left point to all points.
Original 2D array:
[0, 1, 0, 0, 0, 1, 0]
[1, 1, 0, 0, 1, 0, 1]
[0, 1, 1, 0, 1, 0, 0]
[0, 0, 0, 0, 0, 0, 1]
1st step (sum vertical elements with the previous one):
[0, 1, 1, 1, 1, 2, 2]
[1, 2, 2, 2, 3, 3, 4]
[0, 1, 2, 2, 3, 3, 3]
[0, 0, 0, 0, 0, 0, 1]
2nd step (sum horizontal elements with the previous one):
[0, 1, 1, 1, 1, 2, 2]
[1, 3, 3, 3, 4, 5, 6]
[1, 4, 5, 5, 7, 8, 9]
[1, 4, 5, 5, 7, 8, 10]
Both of these operations are O(n2). Is there a quicker way to initialize the list?
You cannot avoid quadratic time, but there is no need in two steps
(OK, code with correct answer looks longer a bit :))
lst=[[0, 1, 0, 0, 0, 1, 0]]
lst.append([1, 1, 0, 0, 1, 0, 1])
lst.append([0, 1, 1, 0, 1, 0, 0])
lst.append([0, 0, 0, 0, 0, 0, 1])
for i in range(1.len(lst)):
for j in range(len(lst[0])):
if (i>0):
lst[i][j] += lst[i-1][j]
if (j>0):
lst[i][j] += lst[i][j-1]
if (i>0) & (j>0):
lst[i][j] -= lst[i-1][j-1]
print(lst)
>>>[[0, 1, 1, 1, 1, 2, 2],
[1, 3, 3, 3, 4, 5, 6],
[1, 4, 5, 5, 7, 8, 9],
[1, 4, 5, 5, 7, 8, 10]]
or without if's:
for j in range(1,len(lst[0])):
lst[0][j] += lst[0][j-1]
for i in range(1,len(lst)):
lst[i][0] += lst[i-1][0]
for i in range(1,len(lst)):
for j in range(1,len(lst[0])):
lst[i][j] = lst[i][j] + lst[i-1][j] + lst[i][j-1] - lst[i-1][j-1]
list = [[1, 2, 3, 0, 0], [0, 0, 3, 2, 1], [1, 0, 0, 3, 2],
[2, 3, 1, 0, 0], [3, 0, 1, 2, 0], [2, 0, 1, 3, 0]]
I would like to check if the number 1 is in the third column of all the nested lists, if it is than it should replace the 1 with a 0 and the 2 in that list with a 1.
Thanks in advance
Try the following:
nested_lists = [[1, 2, 3, 0, 0], [0, 0, 3, 2, 1], [1, 0, 0, 3, 2],
[2, 3, 1, 0, 0], [3, 0, 1, 2, 0], [2, 0, 1, 3, 0]]
for list_ in nested_lists:
if list_[2] == 1:
list_[2] = 0
list_ = [1 if n == 2 else n for n in list_]
After execution, nested_lists goes from the given
[[1, 2, 3, 0, 0], [0, 0, 3, 2, 1], [1, 0, 0, 3, 2],
[2, 3, 1, 0, 0], [3, 0, 1, 2, 0], [2, 0, 1, 3, 0]]
To
[[1, 2, 3, 0, 0], [0, 0, 3, 2, 1], [1, 0, 0, 3, 2]
[1, 3, 0, 0, 0], [3, 0, 0, 1, 0], [1, 0, 0, 3, 0]]