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
Related
This question already has answers here:
How to get the cartesian product of multiple lists
(17 answers)
Closed 2 years ago.
I have two lists:
lst1 = ['a', 'b']
lst2 = ['c', 'd', 'e']
I want to make combinations like this:
[['a', 'c'], ['a', 'd'], ['a', 'e'], ['b', 'c'], ['b', 'd'], ['b', 'e']]
Kindly help me with this. Thanks
>>> import itertools
>>> lst1 = ['a', 'b']
>>> lst2 = ['c', 'd', 'e']
>>> itertools.product(lst1, lst2)
<itertools.product object at 0x7f3571488280>
>>> list(itertools.product(lst1, lst2))
[('a', 'c'), ('a', 'd'), ('a', 'e'), ('b', 'c'), ('b', 'd'), ('b', 'e')]
>>> x = list(itertools.product(lst1, lst2))
>>> [list(y) for y in x]
[['a', 'c'], ['a', 'd'], ['a', 'e'], ['b', 'c'], ['b', 'd'], ['b', 'e']]
>>>
I leave you an example without using libraries too.
Script:
lst1 = ['a', 'b']
lst2 = ['c', 'd', 'e']
lst3 = []
for item_lst1 in lst1:
for item_lst2 in lst2:
lst3.append([item_lst1, item_lst2])
print(lst3)
Output:
[['a', 'c'], ['a', 'd'], ['a', 'e'], ['b', 'c'], ['b', 'd'], ['b', 'e']]
This might do the job for you.
list1 = ['a', 'b']
list2 = ['c', 'd', 'e']
req_list = [[x, y] for x in list1 for y in list2]
This type of combining is called cartesian product or cross product.
The issues stems from the output.append(a) on the third line. This program would ideally output 6 unique permutations of the input string, but instead returns 6 of the first result in the recursive loop. I realize exiting the recursion may have something to do with the array being modified, but how can I circumvent this issue to be able to return an array of solutions?
def permute(a, l, r, output):
if l==r:
output.append(a)
else:
for i in range(l,r+1):
a[l], a[i] = a[i], a[l]
permute(a, l+1, r,output)
a[l], a[i] = a[i], a[l] # backtrack
Driver program to test the above function
string = "ABC"
output = []
n = len(string)
a = list(string)
permute(a, 0, n-1,output)
print(output)
For reference, this is what the output looks like:
[['A', 'C', 'B']]
[['B', 'A', 'C'], ['B', 'A', 'C']]
[['B', 'C', 'A'], ['B', 'C', 'A'], ['B', 'C', 'A']]
[['C', 'B', 'A'], ['C', 'B', 'A'], ['C', 'B', 'A'], ['C', 'B', 'A']]
[['C', 'A', 'B'], ['C', 'A', 'B'], ['C', 'A', 'B'], ['C', 'A', 'B'], ['C', 'A', 'B']]
[['A', 'B', 'C'], ['A', 'B', 'C'], ['A', 'B', 'C'], ['A', 'B', 'C'], ['A', 'B', 'C'], ['A', 'B', 'C']]
When the output should be:
['A', 'B', 'C']
['A', 'C', 'B']
['B', 'A', 'C']
['B', 'C', 'A']
['C', 'B', 'A']
['C', 'A', 'B']
The problem is in the line
output.append(a)
it looks fine, but later on the list a changes, and when you append it to output again, the previous a (that you already appended) changes.
To solve the problem, you can simply use shallow copy. Write this instead:
output.append(a[:])
Do you know there is an excisting function in python?
import itertools
listA = ["A", "B", "C"]
perm = itertools.permutations(listA)
for i in list(perm):
print(i)
Result:
('A', 'B', 'C')
('A', 'C', 'B')
('B', 'A', 'C')
('B', 'C', 'A')
('C', 'A', 'B')
('C', 'B', 'A')
I have an array like this: ['a', ['e', 'r', 't'], 'c'].
I want to use some sort of processing to make the array neat:
[['a', 'e', 'c'], ['a', 'r', 'c'], ['a', 't', 'c']].
If the array is: ['a', ['e', 'r', 't'], ['c', 'd']].
The result is:
[['a', 'e', 'c'], ['a', 'e', 'd'], ['a', 'r', 'c'], ['a', 'r', 'd'], ['a', 't', 'c'], ['a', 't', 'd']].
And the length of the array is not fixed to 3, other examples:
['a', 'b'] = > ['a', 'b']
['a', ['b', 'c']] => [['a', 'b'], ['a', 'c']]
['ab', ['b', 'c']] => [['ab', 'b'], ['ab', 'c']]
[[1, 2], 3, 4] => [[1, 3, 4], [2, 3, 4]]
So what should I do? Is there a solution in Numpy?
Unless I misunderstand the question, you just want the product of the sub-lists, although you have to wrap any single elements into lists first.
>>> from itertools import product
>>> arr = ['a', ['e', 'r', 't'], ['c', 'd']]
>>> listified = [x if isinstance(x, list) else [x] for x in arr]
>>> listified
[['a'], ['e', 'r', 't'], ['c', 'd']]
>>> list(product(*listified))
[('a', 'e', 'c'),
('a', 'e', 'd'),
('a', 'r', 'c'),
('a', 'r', 'd'),
('a', 't', 'c'),
('a', 't', 'd')]
I have a recursive solution:
inlist1 = ['ab', ['e', 'r', 't'], ['c', 'd']]
inlist2 = [['a', 'b'], ['e', 'r', 't'], ['c', 'd']]
inlist3 = [['a', 'b'], 'e', ['c', 'd']]
def jagged(inlist):
a = [None] * len(inlist)
def _jagged(index):
if index == 0:
print(a)
return
v = inlist[index - 1]
if isinstance(v, list):
for i in v:
a[index - 1] = i
_jagged(index - 1, )
else:
a[index - 1] = v
_jagged(index - 1)
_jagged(len(inlist))
jagged(inlist3)
I'm trying to count the number of occurrences of elements within a list, if such elements are also lists. The order is also important.
[PSEUDOCODE]
lst = [ ['a', 'b', 'c'], ['d', 'e', 'f'], ['a', 'b', 'c'], ['c', 'b', 'a'] ]
print( count(lst) )
> { ['a', 'b', 'c'] : 2, ['d', 'e', 'f']: 1, ['c', 'b', 'a']: 1 }
One important factor is that ['a', 'b', 'c'] != ['c', 'b', 'a']
I have tried:
from collections import counter
print( Counter([tuple(x) for x in lst]) )
print( [[x, list.count(x)] for x in set(lst)] )
Which both resulted in ['a', 'b', 'c'] = ['c', 'b', 'a'], one thing i didn't want
I also tried:
from collections import counter
print( Counter( lst ) )
Which only resulted in error; since lists can't be used as keys in dicts.
Is there a way to do this?
You can't have list as a key to the dict because dictionaries only allows immutable objects as it's key. Hence you need to firstly convert your objects to tuple. Then you may use collection.Counter to get the count of each tuple as:
>>> from collections import Counter
>>> my_list = [ ['a', 'b', 'c'], ['d', 'e', 'f'], ['a', 'b', 'c'], ['c', 'b', 'a'] ]
# v to type-cast each sub-list to tuple
>>> Counter(tuple(item) for item in my_list)
Counter({('a', 'b', 'c'): 2, ('d', 'e', 'f'): 1, ('c', 'b', 'a'): 1})
just use collections.Counter on some equivalent type but hashable: the tuple:
import collections
lst = [ ['a', 'b', 'c'], ['d', 'e', 'f'], ['a', 'b', 'c'], ['c', 'b', 'a'] ]
c = collections.Counter(tuple(x) for x in lst)
print(c)
result:
Counter({('a', 'b', 'c'): 2, ('d', 'e', 'f'): 1, ('c', 'b', 'a'): 1})
Lists are not hashable, but you can use tuples as a workaround:
l = [ ['a', 'b', 'c'], ['d', 'e', 'f'], ['a', 'b', 'c'], ['c', 'b', 'a'] ]
new_l = list(map(tuple, l))
final_l = {a:new_l.count(a) for a in new_l}
Output:
{('a', 'b', 'c'): 2, ('d', 'e', 'f'): 1, ('c', 'b', 'a'): 1}
Or, if you really want to use lists, you can create a custom class to mimic the functionality of a dictionary hashing lists:
class List_Count:
def __init__(self, data):
new_data = list(map(tuple, data))
self.__data = {i:new_data.count(i) for i in new_data}
def __getitem__(self, val):
newval = [b for a, b in self.__data.items() if list(a) == val]
if not newval:
raise KeyError("{} not found".format(val))
return newval[0]
def __repr__(self):
return "{"+"{}".format(', '.join("{}:{}".format(list(a), b) for a, b in self.__data.items()))+"}"
l = List_Count([ ['a', 'b', 'c'], ['d', 'e', 'f'], ['a', 'b', 'c'], ['c', 'b', 'a'] ])
print(l)
print(l[['a', 'b', 'c']])
Output:
{['a', 'b', 'c']:2, ['d', 'e', 'f']:1, ['c', 'b', 'a']:1}
2
Another implementation with lists
l1 = [["a", "b", "c"], ["b", "c", "d"], ["a", "b", "c"], ["c", "b", "a"]]
def unique(l1):
l2 = []
for element in l1:
if element not in l2:
l2.append(element)
return l2
l2 = unique(l1)
for element in l2:
print(element, l1.count(element))
and if you want an dictionary from that you can just change the last part to
output = {element:l1.count(element) for element in unique(l1)}
Don't Use list as variable name.
You can try this approach if you don't want to use any module :
list_1 = [ ['a', 'b', 'c'], ['d', 'e', 'f'], ['a', 'b', 'c'], ['c', 'b', 'a'] ]
track={}
for i in list_1:
if tuple(i) not in track:
track[tuple(i)]=1
else:
track[tuple(i)]+=1
print(track)
outoput:
{('a', 'b', 'c'): 2, ('d', 'e', 'f'): 1, ('c', 'b', 'a'): 1}
You can also use default dict:
list_1 = [ ['a', 'b', 'c'], ['d', 'e', 'f'], ['a', 'b', 'c'], ['c', 'b', 'a'] ]
track={}
import collections
d=collections.defaultdict(list)
for j,i in enumerate(list_1):
d[tuple(i)].append(j)
print(list(map(lambda x:{x:len(d[x])},d.keys())))
Well
I have a unique combination of elements (A B C D E F)
from itertools import combinations
data = ['A', 'B', 'C', 'D', 'E', 'F'];
comb = combinations(data, 2);
d = [];
for i in comb:
d.append([i[0], i[1]]);
print d
This returns to me:
[['A', 'B'],
['A', 'C'],
['A', 'D'],
['A', 'E'],
['A', 'F'],
['B', 'C'],
['B', 'D'],
['B', 'E'],
['B', 'F'],
['C', 'D'],
['C', 'E'],
['C', 'F'],
['D', 'E'],
['D', 'F'],
['E', 'F']]
The question is, how to sort this in a way that the line N do not repeat element [0] or element [1] of line (N-1)...in a simpler way:
AB (This line can have any element)
CD (This line can't have A or B)
EF (This line can't have C or D)
AC (This line can't have E or F)
...
mylist= [['A', 'B'],
['A', 'C'],
['A', 'D'],
['A', 'E'],
['A', 'F'],
['B', 'C'],
['B', 'D'],
['B', 'E'],
['B', 'F'],
['C', 'D'],
['C', 'E'],
['C', 'F'],
['D', 'E'],
['D', 'F'],
['E', 'F']]
a=mylist[:] #this used to assign all elements to a so u have ur mylist safe
b=[]
b.append(a[0]) #this appends the first list in the list
del a[0] #now deleting appended list
while len(a)>0:
for val,i in enumerate(a):# enumerte gives index and value of list
if len(set(b[len(b)-1]).intersection(set(i)))==0: # this checks intersection so that both list should not have same elements
b.append(a[val])
del a[val]
print b
#output [['A', 'B'], ['C', 'D'], ['E', 'F'], ['A', 'C'], ['B', 'D'], ['C', 'E'], ['D', 'F'], ['A', 'E'], ['B', 'C'], ['D', 'E'], ['A', 'F'], ['B', 'E'], ['C', 'F'], ['A', 'D'], ['B', 'F']]
Using the neighborhood generator from this answer you can get the previous, current and next element in your loop, so that you can compare them. Then you can do something like this
from itertools import combinations
# Credit to Markus Jarderot for this function
def neighborhood(iterable):
iterator = iter(iterable)
prev = None
item = iterator.next() # throws StopIteration if empty.
for next in iterator:
yield (prev,item,next)
prev = item
item = next
# this can be written like this also prev,item=item,next
yield (prev,item,None)
data = ['A', 'B', 'C', 'D', 'E', 'F'];
comb = combinations(data, 2);
d = [];
for prev, item, next in neighborhood(comb):
# If prev and item both exist and neither are in the last element in d
if prev and item and not any(x in d[-1] for x in item):
d.append([item[0], item[1]])
elif item and not prev: # For the first element
d.append([item[0], item[1]])
print d
This prints
[['A', 'B'],
['C', 'D'],
['E', 'F']]
I'm aware this is probably not 100% what you need, but it should be able to get you where you want