from permutations of array I have an array like this:
[['a', [['b', ['c']], ['c', ['b']]]], ['b', [['a', ['c']], ['c', ['a']]]], ['c', [['a', ['b']], ['b', ['a']]]]]
which means for 'a' I have 'b' and 'c' and for inner 'b' I have 'c' etc.
I am confused how to make a new array which is representing this logic (not only for three variables) and I need it to look like this:
[['a','b','c'],['a','c','b'],['b','a','c'],['b','c','a'],['c','a','b'],['c','b','a']]
Is it somehow possible? Thank you!
You can write a recursive function in order to flatten the list.
def flatten(permutations):
flattens = []
for permutation in permutations:
if len(permutation) == 2:
flattens.extend([[permutation[0], *j] for j in flatten(permutation[1])])
else:
flattens.extend(permutation)
return flattens
if __name__ == '__main__':
permutations = [['a', [['b', ['c']], ['c', ['b']]]], ['b', [['a', ['c']], ['c', ['a']]]], ['c', [['a', ['b']], ['b', ['a']]]]]
print(flatten(permutations))
Output:
[['a', 'b', 'c'], ['a', 'c', 'b'], ['b', 'a', 'c'], ['b', 'c', 'a'], ['c', 'a', 'b'], ['c', 'b', 'a']]
Slightly shorter recursive solution with a generator:
data = [['a', [['b', ['c']], ['c', ['b']]]], ['b', [['a', ['c']], ['c', ['a']]]], ['c', [['a', ['b']], ['b', ['a']]]]]
def full_combos(d, c = []):
if all(not isinstance(j, list) for j in d):
yield from [c+[j] for j in d]
else:
yield from [j for a, b in d for j in full_combos(b, c+[a])]
print(list(full_combos(data)))
Output:
[['a', 'b', 'c'], ['a', 'c', 'b'], ['b', 'a', 'c'], ['b', 'c', 'a'], ['c', 'a', 'b'], ['c', 'b', 'a']]
The answer by vikas soni is great if you start from your first array. But if you start from a list of elements then the task is much simpler:
from itertools import permutations
ls = ["a", "b", "c"]
list(permutations(ls, len(ls)))
[('a', 'b', 'c'), ('a', 'c', 'b'), ('b', 'a', 'c'), ('b', 'c', 'a'), ('c', 'a', 'b'), ('c', 'b', 'a')]
ls2 = ["a", "b", "c", "d", "e"]
len(list(permutations(ls, len(ls))))
120
If i have a list
lst = ['a', 'k', 'b', 'c', 'k', 'd', 'e', 'g']
and I want to split into new list without 'k', and turn it into a tuple. So I get
(['a'],['b', 'c'], ['d', 'e', 'g'])
I am thinking about first splitting them into different list by using a for loop.
new_lst = []
for element in lst:
if element != 'k':
new_ist.append(element)
This does remove all the 'k' but they are all together. I do not know how to split them into different list. To turn a list into a tuple I would need to make a list inside a list
a = [['a'],['b', 'c'], ['d', 'e', 'g']]
tuple(a) == (['a'], ['b', 'c'], ['d', 'e', 'g'])
True
So the question would be how to split the list into a list with sublist.
You are close. You can append to another list called sublist and if you find a k append sublist to new_list:
lst = ['a', 'k', 'b', 'c', 'k', 'd', 'e', 'g']
new_lst = []
sublist = []
for element in lst:
if element != 'k':
sublist.append(element)
else:
new_lst.append(sublist)
sublist = []
if sublist: # add the last sublist
new_lst.append(sublist)
result = tuple(new_lst)
print(result)
# (['a'], ['b', 'c'], ['d', 'e', 'g'])
If you're feeling adventurous, you can also use groupby. The idea is to group elements as "k" or "non-k" and use groupby on that property:
from itertools import groupby
lst = ['a', 'k', 'b', 'c', 'k', 'd', 'e', 'g']
result = tuple(list(gp) for is_k, gp in groupby(lst, "k".__eq__) if not is_k)
print(result)
# (['a'], ['b', 'c'], ['d', 'e', 'g'])
Thanks #YakymPirozhenko for the simpler generator expression
tuple(list(i) for i in ''.join(lst).split('k'))
Output:
(['a'], ['b', 'c'], ['d', 'e', 'g'])
Here's a different approach, using re.split from the re module, and map:
import re
lst = ['a', 'k', 'b', 'c', 'k', 'd', 'e', 'g']
tuple(map(list, re.split('k',''.join(lst))))
(['a'], ['b', 'c'], ['d', 'e', 'g'])
smallerlist = [l.split(',') for l in ','.join(lst).split('k')]
print(smallerlist)
Outputs
[['a', ''], ['', 'b', 'c', ''], ['', 'd', 'e', 'g']]
Then you could check if each sub lists contain ''
smallerlist = [' '.join(l).split() for l in smallerlist]
print(smallerlist)
Outputs
[['a'], ['b', 'c'], ['d', 'e', 'g']]
How about slicing, without appending and joining .
def isplit_list(lst, v):
while True:
try:
end = lst.index(v)
except ValueError:
break
yield lst[:end]
lst = lst[end+1:]
if len(lst):
yield lst
lst = ['a', 'k', 'b', 'c', 'k', 'd', 'e', 'g', 'k']
results = tuple(isplit_list(lst, 'k'))
Try this, works and doesn't need any imports!
>>> l = ['a', 'k', 'b', 'c', 'k', 'd', 'e', 'g']
>>> t = []
>>> for s in ''.join(l).split('k'):
... t.append(list(s))
...
>>> t
[['a'], ['b', 'c'], ['d', 'e', 'g']]
>>> t = tuple(t)
>>> t
(['a'], ['b', 'c'], ['d', 'e', 'g'])
Why don't you make a method which will take a list as an argument and return a tuple like so.
>>> def list_to_tuple(l):
... t = []
... for s in l:
... t.append(list(s))
... return tuple(t)
...
>>> l = ['a', 'k', 'b', 'c', 'k', 'd', 'e', 'g']
>>> l = ''.join(l).split('k')
>>> l = list_to_tuple(l)
>>> l
(['a'], ['b', 'c'], ['d', 'e', 'g'])
Another approach using itertools
import more_itertools
lst = ['a', 'k', 'b', 'c', 'k', 'd', 'e', 'g']
print(tuple(more_itertools.split_at(lst, lambda x: x == 'k')))
gives
(['a'], ['b', 'c'], ['d', 'e', 'g'])
I have a list of characters:
Char_list = ['C', 'A', 'G']
and a list of lists:
List_List = [['A', 'C', 'T'], ['C', 'A', 'T', 'G'], ['A', 'C', 'G']]
I would like to remove each Char_list[i] from the list of corresponding index i in List_List.
Output must be as follows:
[['A','T'], ['C', 'T', 'G'], ['A', 'C']]
what I am trying is:
for i in range(len(Char_list)):
for j in range(len(List_List)):
if Char_list[i] in List_List[j]:
List_List[j].remove(Char_list[i])
print list_list
But from the above code each character is removed from all lists.
How can I remove Char_list[i] only from corresponding list in List_list?
Instead of using explicit indices, zip your two lists together, then apply a list comprehension to filter out the unwanted character for each position.
>>> char_list = ['C', 'A', 'G']
>>> list_list = [['A', 'C', 'T'], ['C','A', 'T', 'G'], ['A', 'C', 'G']]
>>> [[x for x in l if x != y] for l, y in zip(list_list, char_list)]
[['A', 'T'], ['C', 'T', 'G'], ['A', 'C']]
You may use enumerate with nested list comprehension expression as:
>>> char_list = ['C', 'A', 'G']
>>> nested_list = [['A', 'C', 'T'], ['C', 'A', 'T', 'G'], ['A', 'C', 'G']]
>>> [[j for j in i if j!=char_list[n]] for n, i in enumerate(nested_list)]
[['A', 'T'], ['C', 'T', 'G'], ['A', 'C']]
I also suggest you to take a look at PEP 8 - Naming Conventions. You should not be using capitalized first alphabet with the variable name.
Char_list = ['C', 'A', 'G']
List_List = [['A', 'C', 'T'], ['C', 'A', 'T', 'G'], ['A', 'C', 'G']]
for i in range(len(Char_list)):
List_List[i].remove(Char_list[i])
print(List_List)
OUTPUT
[['A', 'T'], ['C', 'T', 'G'], ['A', 'C']]
If the characters repeat in nested lists, Use this
Char_list = ['C', 'A', 'G']
List_List = [['A', 'C','C','C', 'T'], ['C', 'A', 'T', 'G'], ['A', 'C', 'G']]
for i in range(len(Char_list)):
for j in range(List_List[i].count(Char_list[i])):
List_List[i].remove(Char_list[i])
print(List_List)
Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 7 years ago.
Improve this question
there are a lot of questions and answers about combining and merging lists in python but I have not found a way to create a full combination of all elements.
If I had a list of lists like the following:
data_small = [ ['a','b','c'], ['d','e','f'] ]
data_big = [ ['a','b','c'], ['d','e','f'], ['u','v','w'], ['x','y','z'] ]
How can I get a list of lists with all combinations?
For data_small this should be:
[ [a,b,c], [d,b,c], [a,b,f], [a,e,c],
[d,e,c], [d,b,f], [a,e,f], [d,e,f], ... ]
This should also work for an arbitrary number of lists of the same length like data_big.
I am pretty sure there is a fancy itertools solution for this, right?
I think I deciphered the question:
def so_called_combs(data):
for sublist in data:
for sbl in data:
if sbl==sublist:
yield sbl
continue
for i in range(len(sublist)):
c = sublist[:]
c[i] = sbl[i]
yield c
This returns the required list, if I understood it correctly:
For every list in the data, every element is replaced (but only one at a time) with the corresponding element (same position) in each of the other lists.
For data_big, this returns:
[['a', 'b', 'c'], ['d', 'b', 'c'], ['a', 'e', 'c'], ['a', 'b', 'f'],
['u', 'b', 'c'], ['a', 'v', 'c'], ['a', 'b', 'w'], ['x', 'b', 'c'],
['a', 'y', 'c'], ['a', 'b', 'z'], ['a', 'e', 'f'], ['d', 'b', 'f'],
['d', 'e', 'c'], ['d', 'e', 'f'], ['u', 'e', 'f'], ['d', 'v', 'f'],
['d', 'e', 'w'], ['x', 'e', 'f'], ['d', 'y', 'f'], ['d', 'e', 'z'],
['a', 'v', 'w'], ['u', 'b', 'w'], ['u', 'v', 'c'], ['d', 'v', 'w'],
['u', 'e', 'w'], ['u', 'v', 'f'], ['u', 'v', 'w'], ['x', 'v', 'w'],
['u', 'y', 'w'], ['u', 'v', 'z'], ['a', 'y', 'z'], ['x', 'b', 'z'],
['x', 'y', 'c'], ['d', 'y', 'z'], ['x', 'e', 'z'], ['x', 'y', 'f'],
['u', 'y', 'z'], ['x', 'v', 'z'], ['x', 'y', 'w'], ['x', 'y', 'z']]
Here is another way to do using itertools permutations and chain function. You also need to check if the indexes line up and are all the same length, and whether there is more than one element being replaced
from itertools import *
data_small = [ ['a','b','c'], ['d','e','f'] ]
data_big = [ ['a','b','c'], ['d','e','f'], ['u','v','w'], ['x','y','z'] ]
def check(data, sub):
check_for_mul_repl = []
for i in data:
if len(i) != len(data[0]):
return False
for j in i:
if j in sub:
if i.index(j) != sub.index(j):
return False
else:
if i not in check_for_mul_repl:
check_for_mul_repl.append(i)
if len(check_for_mul_repl) <= 2:
return True
print [x for x in list(permutations(chain(*data_big), 3)) if check(data_big, x)]
['a', 'b', 'c'], ['a', 'b', 'f'], ['a', 'b', 'w'], ['a', 'b', 'z'],
['a', 'e', 'c'], ['a', 'e', 'f'], ['a', 'v', 'c'], ['a', 'v', 'w'],
['a', 'y', 'c'], ['a', 'y', 'z'], ['d', 'b', 'c'], ['d', 'b', 'f'],
['d', 'e', 'c'], ['d', 'e', 'f'], ['d', 'e', 'w'], ['d', 'e', 'z'],
['d', 'v', 'f'], ['d', 'v', 'w'], ['d', 'y', 'f'], ['d', 'y', 'z'],
['u', 'b', 'c'], ['u', 'b', 'w'], ['u', 'e', 'f'], ['u', 'e', 'w'],
['u', 'v', 'c'], ['u', 'v', 'f'], ['u', 'v', 'w'], ['u', 'v', 'z'],
['u', 'y', 'w'], ['u', 'y', 'z'], ['x', 'b', 'c'], ['x', 'b', 'z'],
['x', 'e', 'f'], ['x', 'e', 'z'], ['x', 'v', 'w'], ['x', 'v', 'z'],
['x', 'y', 'c'], ['x', 'y', 'f'], ['x', 'y', 'w'], ['x', 'y', 'z']
This doesn't care if there is more than one element being replaced
from itertools import permutations, chain
data_small = [ ['a','b','c'], ['d','e','f'] ]
data_big = [ ['a','b','c'], ['d','e','f'], ['u','v','w'], ['x','y','z'] ]
def check(data, sub):
for i in data:
if len(i) != len(data[0]):
return False
for j in i:
if j in sub:
if i.index(j) != sub.index(j):
return False
return True
#If you really want lists just change the first x to list(x)
print [x for x in list(permutations(chain(*data_big), 3)) if check(data_big, x)]
['a', 'b', 'c'], ['a', 'b', 'f'], ['a', 'b', 'w'], 61 more...
The reason I use permutations instead of combinations is because ('d','b','c') is equal to ('c','b','d') in terms of combinations and not in permutations
If you just want combinations then that's a lot easier. You can just do
def check(data) #Check if all sub lists are same length
for i in data:
if len(i) != len(data[0]):
return False
return True
if check(data_small):
print list(combinations(chain(*data_small), 3))
[('a', 'b', 'c'), ('a', 'b', 'd'), ('a', 'b', 'e'), ('a', 'b', 'f'),
('a', 'c', 'd'), ('a', 'c', 'e'), ('a', 'c', 'f'), ('a', 'd', 'e'),
('a', 'd', 'f'), ('a', 'e', 'f'), ('b', 'c', 'd'), ('b', 'c', 'e'),
('b', 'c', 'f'), ('b', 'd', 'e'), ('b', 'd', 'f'), ('b', 'e', 'f'),
('c', 'd', 'e'), ('c', 'd', 'f'), ('c', 'e', 'f'), ('d', 'e', 'f')]
Sorry for being late to the party, but here is the fancy "one--liner" (split over multiple lines for readability) using itertools and the extremely useful new Python 3.5 unpacking generalizations (which, by the way, is a significantly faster and more readable way of converting between iterable types than, say, calling list explicitly) --- and assuming unique elements:
>>> from itertools import permutations, repeat, chain
>>> next([*map(lambda m: [m[i][i] for i in range(a)],
{*permutations((*chain(*map(
repeat, map(tuple, l), repeat(a - 1))),), a)})]
for l in ([['a', 'b', 'c'], ['d', 'e', 'f'], ['g', 'h', 'i']],)
for a in (len(l[0]),))
[['g', 'h', 'f'], ['g', 'b', 'i'], ['g', 'b', 'f'],
['d', 'b', 'f'], ['d', 'h', 'f'], ['d', 'h', 'i'],
['a', 'e', 'c'], ['g', 'e', 'i'], ['a', 'h', 'i'],
['a', 'e', 'f'], ['g', 'e', 'c'], ['a', 'b', 'i'],
['g', 'b', 'c'], ['g', 'h', 'c'], ['d', 'h', 'c'],
['d', 'b', 'c'], ['d', 'e', 'c'], ['a', 'b', 'f'],
['d', 'b', 'i'], ['a', 'h', 'c'], ['g', 'e', 'f'],
['a', 'e', 'i'], ['d', 'e', 'i'], ['a', 'h', 'f']]
The use of next on the generator and the last two lines are, of course, just unnecessary exploitations of syntax to put the expression into one line, and I hope people will not use this as an example of good coding practice.
EDIT
I just realised that maybe I should give a short explanation. So, the inner part creates a - 1 copies of each sublist (converted to tuples for hashability and uniqueness testing) and chains them together to allow permutations to do its magic, which is to create all permutations of sublists of a sublists length. These are then converted to a set which gets rid of all duplicates which are bound to occur, and then a map pulls out the ith element of the ith sublist within each unique permutation. Finally, a is the length of the first sublist, since all sublists are assumed to have identical lengths.