Sampling nested lists in reverse using comprehension - python

Sorry if this is a duplicate. If I have a list of lists:
j0 = [i for i in range(4)]
j1 = [j0 for j in range(4)]
>>> [[0, 1, 2, 3], [0, 1, 2, 3], [0, 1, 2, 3], [0, 1, 2, 3]]
I can get an element from each list in turn using a list comprehension:
print [j1[k][k] for k in range(0,4)]
>>> [0, 1, 2, 3]
But I want an element from each list starting from the end (so working backwards), so the desired output is:
>>> [3, 2, 1, 0] # One item from each list
I tried this but its obviously wrong because j1[0][0] = 0:
print [j1[k][-k] for k in range(0,4)]
>>>[0, 3, 2, 1]
I can use the following, but is there a nicer way using a list comprehension?
nl = []
l = 0
for i in range(-1, -5, -1):
nl.append(j1[l][i])
l += 1
print nl

This is very similar to what you have tried. You had the right idea with -k, but have to subtract it from the length (along with another -1 since python indices start at 0).
print [j1[k][len(j0) - 1 - k] for k in range(0,4)]
[3, 2, 1, 0]

you can try
print [j1[k][k] for k in range(3, -1, -1)]

Related

After using combinations with replacement, how to remove tuples with combinations that I don't want

I'm trying to get a list of lists (or tuples) which follows a pattern something like this:
[1,1,1,2]
[1,1,2,2]
[1,2,2,2]
[1,2,2,3]
[1,2,3,3]
[1,2,3,4]
Using itertools.combinations_with_replacement I've gotten close, but I end up with lists which jump values for example:
[1,1,1,3]
or
[2,2,2,3]
I don't want this. I always want to start at 1, and increase until the list is filled, and then increase to the next value.
If I'm using itertools, then is there a way to remove the lists that I don't want?
Instead of using combinations, I would generate the pattern directly.
Create a list of 1's with the desired length and iterate backward, changing the list accordingly.
def generate_increment(n):
lst = [1] * n
result = []
for k in range(n-1):
lst[-1] += 1
result.append(lst[:])
for i in range(len(lst)-2, k, -1):
a, b = lst[i], lst[i+1]
if a != b:
lst[i] = b
result.append(lst[:])
return result
>>print(*generate_increment(4), sep='\n')
[1, 1, 1, 2]
[1, 1, 2, 2]
[1, 2, 2, 2]
[1, 2, 2, 3]
[1, 2, 3, 3]
[1, 2, 3, 4]
It feels like validating the results of combinations will be a bigger effort than simply creating those lists you need.
This can be done with a recursive function that adds with each step what value to add to the list until a defined size:
def gen_list(pre, size):
if size == 1:
return [pre]
res = gen_list(pre + [pre[-1]], size - 1)
res.extend(gen_list(pre + [pre[-1]+1], size-1))
return res
for l in gen_list([1], 4):
print(l)
Which prints:
[1, 1, 1, 1]
[1, 1, 1, 2]
[1, 1, 2, 2]
[1, 1, 2, 3]
[1, 2, 2, 2]
[1, 2, 2, 3]
[1, 2, 3, 3]
[1, 2, 3, 4]

Generating Numerical Permutations (Iteration vs Recursion)

I think I am trying to do something quite fundamental and quite simple. For this reason, I was sure Stack Overflow would already have a post regarding this task but I guess not? Maybe it is an inconsequential concept? Apologies if a post for this already exists. I couldn't find it.
Here is what I want to accomplish: Given a list length n and a maximum element value m, generate all of the permutations of the list with each element varying between 0 and m.
QUESTIONS: 1. Is there a way to do this recursively? 2. Is recursion optimal (in terms of computational resources, O time, etc.) for this concept or is iteration better? 3. Is there a better way (less complicated) to achieve this using iteration (see my code below)?
more information found below
I have edited my code and the two examples to produce and exhibit complete solutions
Here are two examples:
Example 1: n = 3, m = 2
Output:
[0, 0, 0]
[0, 0, 1]
[0, 0, 2]
[0, 1, 0]
[0, 1, 1]
[0, 1, 2]
[0, 2, 0]
[0, 2, 1]
[0, 2, 2]
[1, 0, 0]
[1, 0, 1]
[1, 0, 2]
[1, 1, 0]
[1, 1, 1]
[1, 1, 2]
[1, 2, 0]
[1, 2, 1]
[1, 2, 2]
[2, 0, 0]
[2, 0, 1]
[2, 0, 2]
[2, 1, 0]
[2, 1, 1]
[2, 1, 2]
[2, 2, 0]
[2, 2, 1]
[2, 2, 2]
Example 1: n = 2, m = 4
Output:
[0, 0]
[0, 1]
[0, 2]
[0, 3]
[0, 4]
[1, 0]
[1, 1]
[1, 2]
[1, 3]
[1, 4]
[2, 0]
[2, 1]
[2, 2]
[2, 3]
[2, 4]
[3, 0]
[3, 1]
[3, 2]
[3, 3]
[3, 4]
[4, 0]
[4, 1]
[4, 2]
[4, 3]
[4, 4]
My intuition tells me this can be done recursively but I can't think of how to do it (I'm a beginner programmer). Currently, I have a solution to achieve this iteratively:
def permute(curr_permute,max_num,reset_flgs,reset_ind):
'''
Increment Logic Structure
'''
perm_ind = 0
max_val_flgs = [0]*len(curr_permute)
for c_i in range(len(curr_permute)):
if ((curr_permute[c_i] == max_num) and (c_i < (len(curr_permute)-1))):
if ((reset_ind == c_i) and (reset_flgs[c_i] == 1)):
reset_ind += 1
reset_flgs[c_i] = 0
max_val_flgs[c_i] = 1
continue
else:
perm_ind += 1
max_val_flgs[c_i] = 1
elif (c_i == (len(curr_permute)-1)):
if (curr_permute[c_i] == max_num):
perm_ind = c_i
max_val_flgs[c_i] = 1
else:
perm_ind = c_i
elif (curr_permute[c_i] < max_num):
perm_ind += 1
'''
Reverse the lists
'''
max_val_flgs.reverse()
curr_permute.reverse()
reset_flgs.reverse()
'''
Reset Logic Structure
'''
for n_i in range(len(curr_permute)):
if (max_val_flgs[n_i] == 0):
break
elif ((max_val_flgs[n_i] == 1) and (reset_flgs[n_i] == 1)):
curr_permute[n_i] = 0
perm_ind += -1
'''
Reverse the lists
'''
curr_permute.reverse()
reset_flgs.reverse()
'''
Apply the permutation increment
'''
curr_permute[perm_ind] += 1
return(curr_permute,reset_flgs,reset_ind)
def Permutation_Generation():
n = 2
m = 4
curr_permute = [0]*n
reset_flgs = [1]*n
reset_ind = 0
All_Permutations = [list(curr_permute)]
while (sum(curr_permute) < (n*m)):
print(curr_permute)
[curr_permute,reset_flgs,reset_ind] = permute(curr_permute,m,reset_flgs,reset_ind)
All_Permutations.append(list(curr_permute))
print(curr_permute)
return(All_Permutations)
Apologies for the garbage code. Once I came up with a way to do it successfully, I didn't make much effort to clean it up or make it more efficient. My guess is this code is too complicated for the concept I am attempting to address.
I don't think your output with n and m are 3, 2, respectively, really make sense. After 6th row [0, 2, 0], shouldn't it be followed by [0, 2, 1] instead of [1, 0, 0]? Same also happened after 13th row.
Anyway here is an recursive alterantive:
n = 3
m = 2
def permutation(n, m):
if n <= 0:
yield []
else:
for i in range(m+1):
for j in permutation(n-1, m):
yield [i] + j
# or even shorter
def permutation(n, m):
return [[i] + j for i in range(m + 1) for j in permutation(n - 1, m)] if n > 0 else []
for i in permutation(n, m):
print(i)
Output:
[0, 0, 0], [0, 0, 1], [0, 0, 2], [0, 1, 0], [0, 1, 1], ..., [2, 1, 0], [2, 1, 1], [2, 1, 2], [2, 2, 0], [2, 2, 1], [2, 2, 2]]
3. You want to get all permutations. The number of permutations given n and m is (m+1)^n.
Because you actually want to print all of them the time complexity is also O((m+1)^n), which is what you get when doing it iteratively.
1+2. I don't think you should use recursion to do it, O((m+1)^n) is the optimal time you can do it and it's what you get when using iterations. recursion will also take more memory for it's memory stack.
The question seems to be answered, but I want to contribute an alternative for the permutation by iteration that is a bit simpler. Here I use list comprehensions, formatted string literals (the f'string' strings) and the eval built-in method. Hope this perspective is helpful to you (somehow?).
def get_permutations_list(array_size, max_value):
'''Returns a list of arrays that represent all permutations between zero
and max_value'''
array_member =''
for_loops=''
#Does a loop iteration for each member of the permutation list template
for i in range(array_size):
#adds a new member in each permutation
array_member += f'x{i}, '
#adds a new corresponding for loop
for_loops+=" for x{i} in range({value})".format(i=i,
value=max_value)
output = f'[[{array_member}] {for_loops}]' #combines it all together
return eval(output)
a = get_permutations_list(array_size=2, max_value=2)
print(a)
#Result: [[0,0],[0,1],[1,0],[1,1]]

find product in nested list python of non zeros

How can I get product of nested list :
[[-1, 3, 1],[6, 1, 2],[4, 3, 1],[0, 1, 1]]
to:
[-3,12,12,1]
where eg : -1 * 3 * 1 = -3 and so on.
This is my current solution :
for i in range(len(array2)):
for j in range(len(array2[i])):
prod = array2[i][j] * array2[i][j + 1] * array2[i][j + 2]
print(prod)
I'm getting the following error :
IndexError: list index out of range
You might look at operator.mul combined with functools.reduce for this to make it short and very clear and totally avoid indexing (which is often the source of small errors):
from operator import mul
from functools import reduce
l = [[-1, 3, 1],[6, 1, 2],[4, 3, 1],[0, 1, 1]]
[reduce(mul, s) for s in l]
# [-3, 12, 12, 0]
Edit based on comment
If you want to ignore zeros, you can simply filter them out (this assumes that you don't have rows of all zeros, in which case it's not clear what the answer would be):
[reduce(mul, filter(None, s)) for s in l]
# [-3, 12, 12, 1]
Your index is out of bounds when you get j+1 and j+2, the correct way is to stop at len-2
array2 = [[-1, 3, 1],
[6, 1, 2],
[4, 3, 1],
[0, 1, 1]]
for i in range(len(array2)):
for j in range(len(array2[i])-2): # Check here the range
prod = array2[i][j] * array2[i][j + 1] * array2[i][j + 2]
print(prod)
Try the following function:
input_list = [[-1, 3, 1], [6, 1, 2], [4, 3, 1], [0, 1, 1]]
def compute_multiplication(nested_list):
for l in nested_list:
res = 1
for element in l:
res *= element
print(res)
With the final line being:
compute_multiplication(input_list)
This provides the following output:
-3
12
12
0
my_list = [[-1,3,1],[6,1,2],[4,3,1],[0,1,1]]
products = []
for sub_list in my_list:
partial_prod = 1
for item in sub_list:
partial_prod = partial_prod * item
products.append(partial_prod)
A solution using numpy.prod() :
import numpy
matrix = [
[-1, 3, 1],
[6, 1, 2],
[4, 3, 1],
[0, 1, 1]
]
for row in matrix:
prod = numpy.prod(row)
print(prod)
Assumption is that there are only three entries per row : a list comprehension should suffice. Multiply each item by the other in each row :
matrix = [
[-1, 3, 1],
[6, 1, 2],
[4, 3, 1],
[0, 1, 1]
]
first, make a condition to change zero values to 1 (this is based on the condition, that 0 be ignored and only the result of non zeros be returned)
filtered = [[ent if ent!= 0 else 1 for ent in row ] for row in matrix]
multiply each entry by the other
res = [start*middle*end for start,middle,end in filtered]
#[-3, 12, 12, 1]
if the number of entries is more than three, then #mark meyer's solution is apt for this

Repeating each element of a vector by a number of times provided by another counts vector [duplicate]

Say I have an array with longitudes, lonPorts
lonPort =np.loadtxt('LongPorts.txt',delimiter=',')
for example:
lonPort=[0,1,2,3,...]
And I want to repeat each element a different amount of times. How do I do this? This is what I tried:
Repeat =[5, 3, 2, 3,...]
lonPort1=[]
for i in range (0,len(lenDates)):
lonPort1[sum(Repeat[0:i])]=np.tile(lonPort[i],Repeat[i])
So the result would be:
lonPort1=[0,0,0,0,0,1,1,1,2,2,3,3,3,...]
The error I get is:
list assignment index out of range
How do I get rid of the error and make my array?
Thank you!
You can use np.repeat():
np.repeat(a, [5,3,2,3])
Example:
In [3]: a = np.array([0,1,2,3])
In [4]: np.repeat(a, [5,3,2,3])
Out[4]: array([0, 0, 0, 0, 0, 1, 1, 1, 2, 2, 3, 3, 3])
Without relying on numpy, you can create a generator that will consume your items one by one, and repeat them the desired amount of time.
x = [0, 1, 2, 3]
repeat = [4, 3, 2, 1]
def repeat_items(x, repeat):
for item, r in zip(x, repeat):
while r > 0:
yield item
r -= 1
for value in repeat_items(x, repeat):
print(value, end=' ')
displays 0 0 0 0 1 1 1 2 2 3.
Providing a numpy-free solution for future readers that might want to use lists.
>>> lst = [0,1,2,3]
>>> repeat = [5, 3, 2, 3]
>>> [x for sub in ([x]*y for x,y in zip(lst, repeat)) for x in sub]
[0, 0, 0, 0, 0, 1, 1, 1, 2, 2, 3, 3, 3]
If lst contains mutable objects, be aware of the pitfalls of sequence multiplication for sequences holding mutable elements.

Subtracting each element of list from every elements on its right in the same list

I need to manipulate list to get subtraction (subtracting each number from every number on its right).
I have tried using below code which is working with 2 for loops, is there anyway I can do it in only 1 for loop or in a better way then I did.
list=[3,2,5,4,3]
output_list = [0]
for element in list:
for i in range(0, length(list)):
new_element = [ (list[i] - element) if i > index(element) else 0]
if new_element > 0:
output_list.append( new_element )
example:
input [3,2,5,4,3]
subtract like [2-3, 5-3, 4-3, 3-3, 5-2, 4-2, 3-2, 4-5, 3-5, 3-4] = [-1, 2, 1, 0, 3, 2, 1, -1, -2, 1]
output with values > 0, first 0 is from initialization [0, 2, 1, 3, 2, 1, 1]
This should generate the correct output:
values = [3,2,5,4,3]
print([j-i for k,i in enumerate(values[:-1]) for j in values[k+1:] if j-i > 0])
Try this, you can use itertools.combinations
>>> from itertools import combinations
>>> from operator import sub
>>> l = [3,2,5,4,3]
>>> [0]+[sub(c[1],c[0]) for c in combinations(l,2) if sub(c[1],c[0]) > 0]
[0, 2, 1, 3, 2, 1]
using list comprehension
a=[3,2,5,4,3]
b= [j-a[i] for i,v in enumerate(a) for j in a[i+1:] if j-a[i]>0]
print(b)
output
[2, 1, 3, 2, 1]

Categories