Python - Generate list of lists from other list values - python-3.x

I need to generate a list of lists in that special way:
[3, 1, 4] -> [[1, 2, 3], [1], [1, 2, 3, 4]]
That means that every list in a list of lists must be in range of the given list values. I've tried smth like:
L = [3, 1, 4]
q = [i for i in L]
print(list([x] for x in range(y for y in q)))
But it return a TypeError: generator cannot be interpreted as an integer
That all has to be a single generator expression.

Using a list comprehension.
Try:
L = [3, 1, 4]
print([list(range(1, i+1)) for i in L])
Output:
[[1, 2, 3], [1], [1, 2, 3, 4]]

Related

All possible combinations (including all subsets combinations) of two or more lists

I searched the net but couldn't find anything. I am trying to get all possible combinations including all subsets combinations of two lists (ideally n lists). All combinations should include at least one item from each list.
list_1 = [1,2,3]
list_2 = [5,6]
output = [
[1,5], [1,6], [2,5], [2,6], [3,5], [3,6],
[1,2,5], [1,2,6], [1,3,5], [1,3,6], [2,3,5], [2,3,6], [1,5,6], [2,5,6], [3,5,6],
[1,2,3,5], [1,2,3,6],
[1,2,3,5,6]
]
All I can get is pair combinations like [1,5], [1,6], .. by using
combs = list(itertools.combinations(itertools.chain(*ls_filter_columns), cnt))
What is the pythonic way of achieving this?
Here is one way:
from itertools import combinations, product
def non_empties(items):
"""returns nonempty subsets of list items"""
subsets = []
n = len(items)
for i in range(1,n+1):
subsets.extend(combinations(items,i))
return subsets
list_1 = [1,2,3]
list_2 = [5,6]
combs = [list(p) + list(q) for p,q in product(non_empties(list_1),non_empties(list_2))]
print(combs)
Output:
[[1, 5], [1, 6], [1, 5, 6], [2, 5], [2, 6], [2, 5, 6], [3, 5], [3, 6], [3, 5, 6], [1, 2, 5], [1, 2, 6], [1, 2, 5, 6], [1, 3, 5], [1, 3, 6], [1, 3, 5, 6], [2, 3, 5], [2, 3, 6], [2, 3, 5, 6], [1, 2, 3, 5], [1, 2, 3, 6], [1, 2, 3, 5, 6]]
Which has more elements then the output you gave, though I suspect that your intended output is in error. Note that my code might not correctly handle the case in which there is a non-empty intersection of the two lists. Then again, it might -- you didn't specify what the intended output should be in such a case.
Here is another way.
Even though it is not fancy, it cares n_lists easily.
def change_format(X):
output = []
for x in X:
output += list(x)
return output
import itertools
list_1 = [1,2,3]
list_2 = [5,6]
list_3 = [7,8]
lists = [list_1, list_2, list_3]
lengths = list(map(len, lists))
rs_list = itertools.product(*[list(range(1, l+1)) for l in lengths])
output = []
for rs in rs_list:
temp = []
for L, r in zip(lists, rs):
temp.append(list(itertools.combinations(L, r)))
output += list(itertools.product(*temp))
output = list(map(change_format, output))
I have managed to make it work for n-lists with less code, which was a challenge for me.
from itertools import chain, combinations, product
def get_subsets(list_of_lists):
"""
Get all possible combinations of subsets of given lists
:param list_of_lists: consists of any number of lists with any number of elements
:return: list
"""
ls = [chain(*map(lambda x: combinations(e, x), range(1, len(e)+1))) for e in list_of_lists if e]
ls_output = [[i for tpl in ele for i in tpl] for ele in product(*ls)]
return ls_output
list_1 = [1, 2, 3]
list_2 = [5, 6]
list_3 = [7, 8]
ls_filter_columns = [list_1, list_2, list_3]
print(get_subsets(ls_filter_columns))

divides each element of the matrix by 2 if the element is an even number

i need to write a function in python that takes a matrix as an argument and divides each element of the matrix by 2 if the element is an even number (otherwise, does nothing).
i also need to use list comprehension for this.
as an example, if i have a matrix like m = [[5, 4], [2, 3], [6, 7]] output: [[5, 2], [1, 3], [3, 7]]
Thanks.
def f(matrix):
return [ [x//2 if x%2==0 else x for x in m ] for m in matrix]
print(f([[5, 4], [2, 3], [6, 7]]))

Two loop with restriction [1,2] and [2,1] not acceptable python

I have two for loop to select items from a list and don't want to repeat [1,2] and [2,1] similar is the case for other elements. Basically I have
for i in range(0,20):
for j in range(0,20):
if (i != j):
function(list[i],list[j])
The output from [1,2] and [2,1] gives the same results and I don't want to repeat that. basically i and j are identical array. I eliminate similar elements using if loop.And I want to eliminate repeated elements.
Simply start your j loop from i.
lis = []
for i in range(0, 5):
for j in range(i + 1, 5):
lis.append([i, j])
This outputs
[[0, 1],
[0, 2],
[0, 3],
[0, 4],
[1, 2],
[1, 3],
[1, 4],
[2, 3],
[2, 4],
[3, 4]]
For a smaller output, I changed 20 to 5.

How to transform a list of lists like [1, [2, 3, 4], 5 ] to a list [[1,2,5], [1,3,5], [1,4,5]] in Python?

I'm just starting with Python and trying to find a general solution to transform a list of lists [1, [2, 3, 4], 5 ] to a list [[1,2,5], [1,3,5], [1,4,5]] in Python.
I've tried creating some dynamic lists but not getting what i want, not even for this simple list in the example. Any help will be greatly appreciated.
inter_l = []
aba = []
v = [1, [2, 3], 4, 5, 6]
g = globals()
for elem in v:
if isinstance(elem, (list,)):
l_ln = len(elem)
indx = v.index(elem)
for i in range(0, l_ln):
g['depth_{0}'.format(i)] = [elem[i]]
inter_l.append(list(g['depth_{0}'.format(i)]))
else:
aba.append(elem)
t = aba.extend(inter_l)
w = aba.extend(inter_l)
print(v)
print(aba)
print(inter_l)
[1, [2, 3], 4, 5, 6]
[1, 4, 5, 6, [2], [3], [2], [3]]
[[2], [3]]
The easiest way would be to leverage itertools.product function, but since it expects iterables as its inputs, the input would have to be transformed a little. One way to achieve this would be something like this:
transformed = [e if isinstance(e, list) else [e] for e in v]
which converts all non-list elements into lists and then pass this transformed input to product:
list(itertools.product(*transformed))
Note, that * in front of transformed expands transformed list into positional arguments, so that instead of a single argument of type list, a list of its elements is passed instead.
The entire pipeline looks something like this:
>>> v = [1, [2, 3, 4], 5]
>>> t = [e if isinstance(e, list) else [e] for e in v]
>>> list(itertools.product(*t))
[(1, 2, 5), (1, 3, 5), (1, 4, 5)]

Reducing time complexity in comparing contiguous subarrays?

So say I have a list sequences such as this.
I want to remove all sequences where its total sum = N and/or it has a contiguous subarray with sum = N.
For example, if N = 4, then (1,1,2) is not valid since its total is 4. (1,1,3) is also not valid since the (1,3) is also 4. (1,3,1) is also not valid for the same reason.
lst = [
(1,1,1), (1,1,2), (1,1,3),
(1,2,1), (1,2,2), (1,2,3),
(1,3,1), (1,3,2), (1,3,3),
(2,1,1), (2,1,2), (2,1,3),
(2,2,1), (2,2,2), (2,2,3),
(2,3,1), (2,3,2), (2,3,3),
(3,1,1), (3,1,2), (3,1,3),
(3,2,1), (3,2,2), (3,2,3),
(3,3,1), (3,3,2), (3,3,3)
]
E.g.
Input: 4 3
Output: 2 1 2
So what I have right now is
lst = [t for t in list(product(range(1,n),repeat=n-1)) if not any((sum(t[l:h+1]) % n == 0) for l, h in combinations(range(len(t)), 2))]
Currently it is in O(n2) if I'm not mistaken. What would be a better way to do this?
If you can use numpy, you can concatenate the total sum of each tuple with the contiguous value sums, then check if any of your resultign elements are equal to 4:
arr = np.array(lst)
arr[~(np.concatenate((np.sum(arr,axis=1).reshape(-1,1),
(arr[:,:-1]+ arr[:,1:])),axis=1) == 4).any(1)]
# or:
arr[(np.concatenate((np.sum(arr,axis=1).reshape(-1,1),
(arr[:,:-1]+ arr[:,1:])),axis=1) != 4).all(1)]
Returning:
array([[1, 1, 1],
[1, 2, 3],
[2, 1, 2],
[2, 3, 2],
[2, 3, 3],
[3, 2, 1],
[3, 2, 3],
[3, 3, 2],
[3, 3, 3]])

Resources