How to write a lot of nested 'for' loops (Recursively) - python

word = "word"
# Splitting word into its characters
newword = []
for char in word:
newword.append(char)
print newword
#getting all permutations
test= []
for i in newword:
for j in newword:
if i != j:
for k in newword:
if j != k and i!= k:
for l in newword:
if i != l and j != l and k != l:
test.append(i+j+k+l)
print test
print type(test)
print len(test)
These 4 nested loops work nicely for 'word' because it has exactly 4 letters in it.
If I wanted as many 'for' loops as there are letters in any given word, how can I do this?
Any nice tricks?

In [10]: import itertools
In [11]: word = "word"
In [12]: test = [''.join(perm) for perm in itertools.permutations(word)]
In [13]: test
Out[13]:
['word',
'wodr',
'wrod',
'wrdo',
'wdor',
'wdro',
'owrd',
'owdr',
'orwd',
'ordw',
'odwr',
'odrw',
'rwod',
'rwdo',
'rowd',
'rodw',
'rdwo',
'rdow',
'dwor',
'dwro',
'dowr',
'dorw',
'drwo',
'drow']

This is a general recursive problem you are trying to solve. itertools already contains functions for practically all implementations you could possible need. However, if you want something to learn about, this is one way of doing it. I will permute a list of numbers. In this case, Ill find permutations for:
[0,1,2, ... ,N-1]
Note that once you have the permutations for the above, you can simply use these as the indices for permuting anything. So what is the general way of doing this?
Let us first look at the result for a specific case. For the case of say [0,1,2,3]. The result we are looking for is the list of lists:
[[0, 1, 2, 3], [0, 1, 3, 2], [0, 2, 1, 3], [0, 2, 3, 1], [0, 3, 1, 2],
[0, 3, 2, 1], [1, 0, 2, 3], [1, 0, 3, 2], [1, 2, 0, 3], [1, 2, 3, 0],
[1, 3, 0, 2], [1, 3, 2, 0], [2, 0, 1, 3], [2, 0, 3, 1], [2, 1, 0, 3],
[2, 1, 3, 0], [2, 3, 0, 1], [2, 3, 1, 0], [3, 0, 1, 2], [3, 0, 2, 1],
[3, 1, 0, 2], [3, 1, 2, 0], [3, 2, 0, 1], [3, 2, 1, 0]]
The idea is to write a function that takes a single list of lists, and increment it. Consider the simple function:
def permNums(inp, N=4):
newInp = []
for i in inp:
for j in range(N):
if j not in i: newInp.append( i+[j] )
return newInp
Now execute this funciton with an empty list of lists ...
In [22]: permNums([[]])
Out[22]: [[0], [1], [2], [3]]
What happens when you run it again with its output?
In [23]: permNums(_)
Out[23]:
[[0, 1],
[0, 2],
[0, 3],
[1, 0],
[1, 2],
[1, 3],
[2, 0],
[2, 1],
[2, 3],
[3, 0],
[3, 1],
[3, 2]]
and repeat it again?
In [24]: permNums(_)
Out[24]:
[[0, 1, 2],
[0, 1, 3],
[0, 2, 1],
[0, 2, 3],
[0, 3, 1],
[0, 3, 2],
[1, 0, 2],
[1, 0, 3],
[1, 2, 0],
[1, 2, 3],
[1, 3, 0],
[1, 3, 2],
[2, 0, 1],
[2, 0, 3],
[2, 1, 0],
[2, 1, 3],
[2, 3, 0],
[2, 3, 1],
[3, 0, 1],
[3, 0, 2],
[3, 1, 0],
[3, 1, 2],
[3, 2, 0],
[3, 2, 1]]
Do it another time, and you will get the result you want.
Now you can consider the simple implementation:
result = [[]]
for i in range(N): result = permNums(_)
This will solve your problem (you just need to map the indices to your string, and join the result). However, this is not classical recursion. For recursion, there are two additional steps you need the perform.
Call the function within itself
Figure out when this calling-itself business is going to stop ...
Calling the function within itself is simple. Just replace
return newInp
with
return permNums(newInp, N)
This step should not be surprising because this is exactly what you did manually on the iPython console. However, you will need to stop at some point. In this specific case, the stopping criterion should be simple. If the number of elements in one of the inner lists == N, then stop.
So the modified program has two simple additions:
def permNums(inp, N=4):
if len(inp[0]) == N: return inp # stopping criterion
newInp = []
for i in inp:
for j in range(N):
if j not in i: newInp.append( i+[j] )
return permNums(newInp, N) # keep calling itself
print permNums([[]])
Hope this helps ...

Related

How to calculate all the combinations of lists

I am blocked on a Python problem and hope someone could help me.
The problem is prety simple actually.
Im trying to build lists with all combination possible but the elements of the list have not the same range.
here is my code, I tried to do something with for loop but it doesnt work.
for j in range(0,size):
for k, val in enumerate(self.Algo.Inputs[j].Values):
self.Commandlist[j] = k
self.Commandlist is a list with fix range, and fill with zero at first.
self.Commandlist = [0,0,0]
self.Algo.Inputs[j].Values gives me the size of each elements, for example, if self.Algo.Inputs[0].Values = 4
self.Algo.Inputs[1].Values = 1
self.Algo.Inputs[2].Values = 2
i want all the combinations, [0,0,0],[1,0,0],[2,0,0],[3,0,0],[4,0,0],[0,1,0],[1,1,0],[2,1,0],[3,1,0],[4,1,0] etc..
I think I forgot a loop but i cant figure out. I tried some stuff with itertools module as well, but i cant make it work.
Thans for your help.
As mentioned you can use itertools, for example like that:
import itertools
a = b = c = range(3) # you can specify different range for each one
[list(x) for x in list(itertools.product(a, b, c))]
Result:
[[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]]

Adding elements of list to list not working

I have a list which contains lists,
testList = [[1, 0, 1], [1, 1, 1], [0, 0, 0], ...]
What I want to do is that add the list in groups of n, so if n is 2, the first two lists will be added together and the second two lists will be added together, it will be like [1, 0, 1] + [1, 1, 1] = [2, 1, 2].
I tried the following code,
group_len = 3
sumResultList = [[sum(x) for x in zip(*testList)] for group in [testList[i:i+group_len] for i in range(0, len(testList), group_len)]]
But the above code does not work, how do I solve this?
l = [[1, 0, 1], [1, 1, 1],
[0, 0, 0], [1, 0, 1],
[1, 1, 1], [1, 0, 1],
[1, 1, 1], [1, 1, 1]]
n = 2
print [[sum(x) for x in zip(*l[a:a+n])] for a in range(0,len(l),n)]
Output:
[[2, 1, 2], [1, 0, 1], [2, 1, 2], [2, 2, 2]]
Try this:
testList = [[1, 0, 1], [1, 1, 1], [0, 0, 0], [2,3,4], [2,3,4], [2,3,4]]
group_len = 2
res = [list(map(sum, zip(*testList[k:k+group_len]))) for k in range(0, len(testList), group_len)]
print(res)
output:
[[2, 1, 2], [2, 3, 4], [4, 6, 8]]

Is there a way to compose two matrix of numbers in one matrix of text?

I would like to compose two matrix of numbers into one matrix of formated text in python.
Is there a easy way?
I could use for, but I just want this because is better for work.
As a simple example:
array([[0, 1, 2],
[0, 1, 2],
[0, 1, 2],
[0, 1, 2],
[0, 1, 2]])
array([[0, 0, 0],
[1, 1, 1],
[2, 2, 2],
[3, 3, 3],
[4, 4, 4]])
to
array([['0:0', '1:0', '2:0'],
['0:1', '1:1', '2:1'],
['0:2', '1:2', '2:2'],
['0:3', '1:3', '2:3'],
['0:4', '1:4', '2:4']])
You can use np.dstack to combine both the arrays and use string manipulation with comprehension to manipulate each cell of the combined array
>>> arr = np.dstack((arr1, arr2))
>>> np.array([np.array([':'.join(map(str,cell)) for cell in row ]) for row in arr])
array([['0:0', '1:0', '2:0'],
['0:1', '1:1', '2:1'],
['0:2', '1:2', '2:2'],
['0:3', '1:3', '2:3'],
['0:4', '1:4', '2:4']],
dtype='|S3')
You could use nditer to iterate over the arrays, and make strings as needed: e.g.
import numpy as np
a1 = np.array([[0, 1, 2],
[0, 1, 2],
[0, 1, 2],
[0, 1, 2],
[0, 1, 2]])
a2 = np.array([[0, 0, 0],
[1, 1, 1],
[2, 2, 2],
[3, 3, 3],
[4, 4, 4]])
out=np.empty(a1.shape, dtype='S5')
for x,y,o in np.nditer([a1, a2, out], op_flags=['readwrite']):
o[...] = "{}:{}".format(x,y)
print(out)
Result:
[['0:0' '1:0' '2:0']
['0:1' '1:1' '2:1']
['0:2' '1:2' '2:2']
['0:3' '1:3' '2:3']
['0:4' '1:4' '2:4']]
Use list comprehensions and zip() to form a new array:
from numpy import array
ar1 = array([[0, 1, 2],
[0, 1, 2],
[0, 1, 2],
[0, 1, 2],
[0, 1, 2]])
ar2 = array([[0, 0, 0],
[1, 1, 1],
[2, 2, 2],
[3, 3, 3],
[4, 4, 4]])
res = array([['%s:%s' % (j1, j2) for j1, j2 in zip(i1, i2)] for i1, i2 in zip(ar1, ar2)])
print(res)
Result:
[['0:0' '1:0' '2:0']
['0:1' '1:1' '2:1']
['0:2' '1:2' '2:2']
['0:3' '1:3' '2:3']
['0:4' '1:4' '2:4']]
This solution will also fit usual Python two-dimensional lists (just remove the 'array' functions).

Python combination and permuation code

I have following code to generate the set of combination, append the combination in the list, and return list.
def make_combination():
import itertools
max_range = 5
indexes = combinations_plus = []
for i in range(0, max_range):
indexes.append(i)
for i in xrange(2, max_range):
each_combination = [list(x) for x in itertools.combinations(indexes, i)]
combinations_plus.append(each_combination)
retrun combinations_plus
It generates so many combinations that I don't want (hard to display). But, I want the following combination:
1) [[0, 1], [0, 2], [0, 3], [0, 4], [1, 2], [1, 3], [1, 4], [2, 3], [2, 4], [3, 4]]
2) [[0, 1, 2], [0, 1, 3], [0, 1, 4], [0, 2, 3], [0, 2, 4], [0, 3, 4], [1, 2, 3], [1, 2, 4], [1, 3, 4], [2, 3, 4]]
3) [[0, 1, 2, 3], [0, 1, 2, 4], [0, 1, 3, 4], [0, 2, 3, 4], [1, 2, 3, 4]]
I think problem in the following line but I don't know what it is. Any idea about what the mistake is.
combinations_plus.append(each_combination)
An easier way of doing what you want is the following:
list(list(itertools.combinations(list(range(5)), i)) for i in range(2, 5))
To fix your original code, there were two problems:
indexes = combinations_plus = []
The above creates two names for the exact same list. Appending to either appends to both which is not what you want.
The two for statements shouldn't be nested, or the list of indexes is incomplete:
for i in range(0, max_range):
indexes.append(i)
for i in xrange(2, max_range):
each_combination = [list(x) for x in itertools.combinations(indexes, i)]
combinations_plus.append(each_combination)
In fact, initialize indexes with range and skip the first for loop:
indexes = range(max_range) # becomes [0,1,2,3,4]
combinations_plus = []
With these fixes (and fixing the spelling of return, you have:
def make_combination():
import itertools
max_range = 5
indexes = range(max_range)
combinations_plus = []
for i in xrange(2, max_range):
each_combination = [list(x) for x in itertools.combinations(indexes, i)]
combinations_plus.append(each_combination)
return combinations_plus
Which returns (newlines added for readability):
[[[0, 1], [0, 2], [0, 3], [0, 4], [1, 2], [1, 3], [1, 4], [2, 3], [2, 4], [3, 4]],
[[0, 1, 2], [0, 1, 3], [0, 1, 4], [0, 2, 3], [0, 2, 4], [0, 3, 4], [1, 2, 3], [1, 2, 4], [1, 3, 4], [2, 3, 4]],
[[0, 1, 2, 3], [0, 1, 2, 4], [0, 1, 3, 4], [0, 2, 3, 4], [1, 2, 3, 4]]]

How to shuffle a list 6 times?

I want to shuffle a list 6 times but I keep getting the same result for all the 6 occasions. Can somebody help me find where the fault is?
Here is the code I used
import random
lis1=[0,1,2,3]
lis2=[]
for i in range(6):
random.shuffle(lis1)
lis2.append(lis1)
print lis2
And here is a sample result I got
[[1,3,2,0],[1,3,2,0],[1,3,2,0],[1,3,2,0],[1,3,2,0],[1,3,2,0]]
If I get jumbled lists, how can I sort them in ascending order? As in,I want to get this -
[[0,1,2,3],[2,3,1,0],[2,1,3,0],[1,0,3,2]]
into this-
[[0,1,2,3],[1,0,3,2],[2,1,3,0],[2,3,1,0]]
First, your code repeatedly inserts a lis1 reference into lis2. Since lis1 stays the same all this time, all of lis2 elements end up pointing to the same object. To fix this, you need to change the append() line to make a copy of the list each time:
lis2.append(lis1[:])
Now, to sort the result simply call sort() after the loop:
lis2.sort()
Try something simpler:
>>> first = [0,1,2,3]
>>> jumbled = [random.sample(first, len(first)) for i in range(6)]
>>> ordered = sorted(jumbled)
>>> jumbled
[[0, 3, 2, 1], [1, 0, 2, 3], [0, 2, 1, 3], [0, 1, 2, 3], [0, 2, 3, 1], [0, 3, 2, 1]]
>>> ordered
[[0, 1, 2, 3], [0, 2, 1, 3], [0, 2, 3, 1], [0, 3, 2, 1], [0, 3, 2, 1], [1, 0, 2, 3]]
Store copy of lis1 not actual lis1
do this:
lis2.append(lis1[:])
Then code will be:
import random
lis1=[0,1,2,3]
lis2=[]
for i in range(6):
random.shuffle(lis1)
lis2.append(lis1[:])
print lis2
Output:
[[2, 3, 1, 0], [0, 3, 2, 1], [3, 0, 1, 2], [1, 2, 0, 3], [3, 0, 2, 1], [1, 0, 3, 2]]
import random
lis1=[0,1,2,3]
lis2=[]
for i in range(6):
r = random.randint(0,len(lis1))
#print(r)
lis2.append(lis1[r:]+lis1[:r])
print(lis2)
print(sorted(lis2))

Categories