Permutations within and across list of lists [python] - python

There are many questions that are related but none that I could find to do exactly what I am looking for. Essentially, I want to get all permutations of each sub-list put together for all possible combinations but keeping them separate. As such:
input=[[1,2,3],[4],[5,6]]
desired output:
[[1,2,3],[4],[6,5]]
[[2,1,3],[4],[5,6]]
[[2,1,3],[4],[5,6]]
[[3,1,2],[4],[5,6]]
etc...
I believe the following code will work, but I was wondering if there were any more efficient or succinct strategies. Thank you very much.
input=[[1,2,3],[4],[5,6]]
all_lists=[]
for i in xrange(len(input)):
all_lists.append(list(itertools.permutations(input[i])))
all_combinations = list(itertools.product(*all_lists))
## concat them together
combinations_combined = [list(itertools.chain(*a)) for a in all_combinations]

We can first use list comprehension to generate all permutations for each sublist:
perms = [list(map(list,permutations(subl))) for subl in data]
and then we can use product to obtain products.
for data in product(*perms):
print(list(data))
Or in full:
from itertools import permutations, product
def product_perms(data):
perms = [list(map(list,permutations(subl))) for subl in data]
for data in product(*perms):
print(list(data))
This produces:
>>> product_perms(data)
[[1, 2, 3], [4], [5, 6]]
[[1, 2, 3], [4], [6, 5]]
[[1, 3, 2], [4], [5, 6]]
[[1, 3, 2], [4], [6, 5]]
[[2, 1, 3], [4], [5, 6]]
[[2, 1, 3], [4], [6, 5]]
[[2, 3, 1], [4], [5, 6]]
[[2, 3, 1], [4], [6, 5]]
[[3, 1, 2], [4], [5, 6]]
[[3, 1, 2], [4], [6, 5]]
[[3, 2, 1], [4], [5, 6]]
[[3, 2, 1], [4], [6, 5]]
In case you want to return such a list, you can use:
def product_perms(data):
perms = [list(map(list,permutations(subl))) for subl in data]
return [list(data) for data in product(*perms)]

And_the_case [[3, 1, 2], [4], [5, 6, [7,8[9,10,11]]? If it's nested list?

Related

Merging multiple lists into one in Python

I have a list X. I want to append elements of X[0][0],X[1][0],X[2][0], X[1][0],X[1][1],X[2][1] and so on. I present the current and expected outputs.
X=[[[1], [2], [3], [4], [5]], [[8], [4], [6], [2], [3]],[[9], [1], [2], [5], [1]]]
X1=[]
for i in range(0,len(X)):
for j in range(0,len(X[0])):
X1=X[i][j]
X1.append(X)
The current output is
[1,
[[[1, [...]], [2, [...]], [3, [...]], [4, [...]], [5, [...]]],
[[8, [...]], [4, [...]], [6, [...]], [2, [...]], [3, [...]]],
[[9, [...]], [1, [...]], [2, [...]], [5, [...]], [...]]]]
The expected output is
[[1,8,9], [2,4,1], [3,6,2], [4,2,5], [5,3,1]]
Iterate over the sublists using zip, then add each inner lists, you can use list-comprehension for it:
>>> [x+y+z for (x,y,z) in zip(X[0], X[1], X[2])]
[[1, 8, 9], [2, 4, 1], [3, 6, 2], [4, 2, 5], [5, 3, 1]]
Or you can use reduce from functools and pass unpacked list to zip if you are not sure how many sublists are there
>>> from functools import reduce
>>> [reduce(lambda x,y: x+y, v) for v in zip(*X)]
[[1, 8, 9], [2, 4, 1], [3, 6, 2], [4, 2, 5], [5, 3, 1]]
Another approach is to call sum iterating the unpacked list passed to zip as suggested by #Mad Physicist in the comment:
>>> [sum(x, start=[]) for x in zip(*X)]
[[1, 8, 9], [2, 4, 1], [3, 6, 2], [4, 2, 5], [5, 3, 1]]
You can use numpy instead of dealing with loops
import numpy as np
array = np.array([[[1], [2], [3], [4], [5]], [[8], [4], [6], [2], [3]],[[9], [1], [2], [5], [1]]])
// reshape and transpose
array = array.reshape(3,5).T
array will be
array([[1, 8, 9],
[2, 4, 1],
[3, 6, 2],
[4, 2, 5],
[5, 3, 1]])
Numpy can help a lot here. First when get rid of the inner-most single-item lists, turning the three list[list[int]] into three list[int]. Then, those can be used to create a np.ndarray. We then transpose this array to get the desired result.
import numpy as np
X = [[[1], [2], [3], [4], [5]],
[[8], [4], [6], [2], [3]],
[[9], [1], [2], [5], [1]]]
a = [[item[0] for item in sublist] for sublist in X]
# [[1, 2, 3, 4, 5], [8, 4, 6, 2, 3], [9, 1, 2, 5, 1]]
a = np.array(a).T
# array([[1, 8, 9],
# [2, 4, 1],
# [3, 6, 2],
# [4, 2, 5],
# [5, 3, 1]])
If there are fewer and more than 3 elements:
import numpy as np
x=[[[1], [2], [3], [4], [5]], [[8], [4], [6], [2], [3]],[[9], [1], [2], [5], [1]]]
x = np.asarray(x)
x = x.reshape(x.shape[0],x.shape[1]).T
x
Output for(3,5,1):
array([[1, 8, 9],
[2, 4, 1],
[3, 6, 2],
[4, 2, 5],
[5, 3, 1]])
Output for (4,5,1):
array([[1, 8, 9, 9],
[2, 4, 1, 1],
[3, 6, 2, 2],
[4, 2, 5, 5],
[5, 3, 1, 1]])
As your list (X) contains a few lists with the same size, it's number of elements can be just indexes_per_list = len(X[0]).
We can then search for the index in every sub-list, and append the correct index.
In order to remove the square brackets, we just use explode (*):
output = []
indexes_per_list = len(X[0])
for i in range(indexes_per_list):
item = []
for l in X:
item.append(*l[i])
output.append(item)
print(output)

How can I sort the lists in the list?

I'd like to know how to sort the lists in the list. However, I don't want to align by key. I'd like to change it according to the following method.
arr = [[2, 3], [5, 1], [4, 1], [5, 3], [4, 2]]
# solution...
I_want_arr = [[2, 3], [1, 5], [1, 4], [3, 5], [2, 4]]
i tried it
for i in arr:
i.sort()
but, it didn't work
using list comprehenstion:
arr = [[2, 3], [5, 1], [4, 1], [5, 3], [4, 2]]
sorted_output = [sorted(l) for l in arr]
using map():
sorted_output = list(map(sorted, arr))
#Gabip's solution includes this and a more time efficient one, check that out first!
How about
arr = [[2, 3], [5, 1], [4, 1], [5, 3], [4, 2]]
I_want_arr = [sorted(x) for x in arr]
This outputs
[[2, 3], [1, 5], [1, 4], [3, 5], [2, 4]]

Python - remove duplicate of dict that contains list of lists

suppose training_data is a dict that contains a list of lists
such as {1: [[1, 2], [1, 3], [1, 2, 5]], 2: [[1], [5], [1, 6]], 3: [[7], [5]]}
I want to merge each value in training_data and then flatten it once to a list so that it will become [[1,2,3,5],[1,5,6],[7,5]].
you can achieve the same result with a one-line comprehension, chaining and using a set + sort
import itertools
d = {1: [[1, 2], [1, 3], [1, 2, 5]], 2: [[1], [5], [1, 6]], 3: [[7], [5]]}
result = [sorted(set(itertools.chain.from_iterable(v))) for v in d.values()]
print(result)
outputs:
[[1, 2, 3, 5], [1, 5, 6], [5, 7]]
If you only need unique elements from the list without maintaining the order of elements in initial list, then you may use set here with itertools.chain.from_iterable. You may use these with list comprehension to achieve your desired list as:
>>> from itertools import chain
>>> my_dict = {1: [[1, 2], [1, 3], [1, 2, 5]], 2: [[1], [5], [1, 6]], 3: [[7], [5]]}
>>> [list(set(chain.from_iterable(v))) for v in my_dict.values()]
[[1, 2, 3, 5], [1, 5, 6], [5, 7]]
Note: since dictionaries are unordered in Python <3.6, the order of sub-lists in the resultant lists might differ.
For preserving the order of elements in the sublist while merging, take a look at: Pythonic way to merge two overlapping lists, preserving order
I found a possible solution, but could anyone tell me if there's a simpler way?
training_data = list(chain.from_iterable([transaction for _, transaction in training_data.items()]))
new_training_data = []
for transaction in training_data:
t = set()
for i in transaction:
t = t.union(i)
new_training_data.append(list(t))
You can use set with list comprehension:
training_data = {1: [[1, 2], [1, 3], [1, 2, 5]], 2: [[1], [5], [1, 6]], 3: [[7], [5]]}
resultList = [sorted(set(elem for subList in training_data[key] for elem in subList)) for key in training_data.keys()]
print(resultList)
Output:
[[1, 2, 3, 5], [1, 5, 6], [5, 7]]

Generator for splitting list (sequence) in N chunks in Python

for i in generate_chunks([1, 2, 3, 4, 5], 2):
print(i)
# [[1], [2, 3, 4, 5]]
# [[1, 2], [3, 4, 5]]
# [[1, 2, 3], [4, 5]]
# [[1, 2, 3, 4], [5]]
for i in generate_chunks([1, 2, 3, 4, 5], 3):
print(i)
# [[1], [2], [3, 4, 5]]
# [[1, 2], [3], [4, 5]]
# [[1, 2, 3], [4], [5]]
# [[1, 2], [3, 4], [5]]
# ...
How can I implement generate_chunks(list, n)?
Essentially what generate_chunks does is splitting list in n chunks and yield a list of these chunks.
For clarification, n refers to the number of chunks, not the length of the chunks.
The order in which those lists of chunks are yielded is irrelevant, however the order of the elements in the initial list is important, so that for a given list [1, 2, 3] the result [[1], [2, 3]] would be valid whereas [[1], [3, 2] would be invalid.
(Preferably without using a 3rd-party library)
Here is an itertools based approach:
import itertools
def chunks(items, cutpoints):
return [items[i:j] for i,j in zip([0] + cutpoints, cutpoints + [len(items)])]
def generate_chunks(items, n):
indices = range(1,len(items))
for cutpoints in itertools.combinations(indices,n-1):
yield chunks(items,list(cutpoints))
For example:
>>> for c in generate_chunks([1,2,3,4,5],4): print(c)
[[1], [2], [3], [4, 5]]
[[1], [2], [3, 4], [5]]
[[1], [2, 3], [4], [5]]
[[1, 2], [3], [4], [5]]

extract list pattern from list of list in python

I have a list of the form -
a_list = [[1, [2, 3, 4]], [2, [3, 4]], [3, [4]]]
I want to convert it to the form -
b_list = [[1,2],[1,3],[1,4],[2,3],[2,4],[3,4]]
Using the list comprehension, I have tried with below code
for lst in tup:
for lst1 in tup[1]:
tup2 = [lst[0],lst1]
and getting (which is wrong)-
tup2 = [3, [3, 4]]
Please help, Thanks in advance
Simple to do with a list comprehension:
a_list = [[1, [2, 3, 4]], [2, [3, 4]], [3, [4]]]
b_list = [[x,y] for [x,b] in a_list for y in b]
print(b_list)
result:
[[1, 2], [1, 3], [1, 4], [2, 3], [2, 4], [3, 4]]
using [x,b] unpacks the items into x as number and b as your list. Loop through elements of b and build the couples, flat-style.
You could try something like this , no matter how many int are there :
for sub_list in b:
for items in sub_list:
if isinstance(items, list):
track = sub_list.index(items)
first = sub_list[:track]
second = sub_list[track:][0]
import itertools
print([list(k) for k in itertools.product(first, second)])
test case:
b = [[1, [2, 3, 4]], [2, [3, 4]], [3, [4]]]
output:
[[1, 2], [1, 3], [1, 4]]
[[2, 3], [2, 4]]
[[3, 4]]
test case 2:
b=[[1,2,[2, 3, 4]], [2,3,5,6 ,[3, 4]], [3, [4]]]
output:
[[1, 2], [1, 3], [1, 4], [2, 2], [2, 3], [2, 4]]
[[2, 3], [2, 4], [3, 3], [3, 4], [5, 3], [5, 4], [6, 3], [6, 4]]
[[3, 4]]

Categories

Resources