Can't figure out this simple recursion with Python - python

Maybe it's not so simple, but I am trying to essentially find all the permutations of a list of letters.
[[a,b],[c,d],[e,f]] for simplicity as it can be longer than just 3 lists of 2 (ie 6 lists of 3 letters, etc.).
I want my program to find all 8 combinations for above example while maintaining order of the main list (is that permutation?).
ace
acf
ade
adf
bce
bcf
bde
bdf
Currently I think the solution below will iterate recursively through the combinations I want; however, I cannot figure out how to store them in order because when it reaches the base condition for the first row it will simply go to the next letter in the last index of the list.
I don't believe I was able to find something that would work for me in itertools
def find_comb(mylist):
for curr_index in range(0,len(mylist)):
for letter in mylist[curr_index]:
if (curr_index+1<=len(mylist)):
next_letter=find_comb(mylist[curr_index+1:])
return 1 #wrote 1 for now because I am stumped

I think what you want is itertools.product
from itertools import product
x = [['a','b'], ['c','d'], ['e','f']]
for _ in product(*x):
print _
Prints
('a', 'c', 'e')
('a', 'c', 'f')
('a', 'd', 'e')
('a', 'd', 'f')
('b', 'c', 'e')
('b', 'c', 'f')
('b', 'd', 'e')
('b', 'd', 'f')
Regarding your comment:
product takes a bunch of iterables and generates their product, however, in your case you were sending it a single iterable (that consisted of more iterables). So instead of passing in l1, l2, l3 you were passing in[l1, l2, l3].
To actually pass in the three iterables, we have to unpack the list using the asterisk, which will turn that single list into three arguments. For more on that, see What does ** (double star) and * (star) do for parameters?

Related

Combinations of a list of items in efficient way

I am trying to find if there is a more efficient way of finding these combinations using some Python scientific library.
I am trying to avoid native for loops and list append preferring to use some NumPy or similar functionality that in theory should be more efficient given it's using C code under the hood. I am struggling to find one, but to me this is quite a common problem to make these operations in an efficient way rather than using slow Python native structures.
I am wondering if I am looking in the wrong places? E.g. this does not seem to help here: https://docs.scipy.org/doc/numpy-1.15.0/reference/generated/numpy.random.binomial.html
See here I am taking the binomial coefficients of a list of length 5 starting from a lower bound of 2 and finding out all the possible combinations. Meanwhile I append to a global list so I then have a nice list of "taken items" from the original input list.
import itertools
input_list = ['a', 'b', 'c', 'd', 'e']
minimum_amount = 2
comb_list = []
for i in range(minimum_amount, len(input_list)):
curr_list = input_list[:i+1]
print(f"the current index is: {i}, the lists are: {curr_list}")
curr_comb_list = list(itertools.combinations(curr_list, i))
comb_list = comb_list + curr_comb_list
print(f"found {len(comb_list)} combinations (check on set length: {len(set(comb_list))})")
print(comb_list)
Gives:
found 12 combinations (check on set length: 12)
[('a', 'b'), ('a', 'c'), ('b', 'c'), ('a', 'b', 'c'), ('a', 'b', 'd'),
('a', 'c', 'd'), ('b', 'c', 'd'), ('a', 'b', 'c', 'd'), ('a', 'b', 'c', 'e'),
('a', 'b', 'd', 'e'), ('a', 'c', 'd', 'e'), ('b', 'c', 'd', 'e')]
Is it possible to do this avoiding the for loop and using some scientific libraries to do this quicker?
How can I do this in a quicker way?
The final list contains all combinations of any length from 1 to len(input_list), which is actually the Power Set.
Look at How to get all possible combinations of a list’s elements?.
You want all combinations from input_list of length 2 or more.
To get them, you can run:
comb_lst = list(itertools.chain.from_iterable(
[ itertools.combinations(input_list, i)
for i in range(2, len(input_list)) ]))
Something similiar to powerset in examples in the itertools web site,
but not exactly the same (the length starts from 2, not from 1).
Note also that curr_list in your code is actually used only for printing.

Apriori create 3 set of word from 2 set

I'm doing implement on Apriori algorithm at the moment I am stuck to create 3 set of word
Suppose I have list of 2 words like this
FI2 = [('a','b'),('a','c'),('a','d'),('b','d'),('b','e'),('e','f')];
First approach I did with by distinct all element into 1 word and using itertools.combinations of 3 which is the compute expesive and not right approach since the result should be subset from C2
It should be like this result
C3 = [('a','b','c'),('a','b','d'),('a','c','d'),('b','d','e')]
I am having a problem how to approach this problem. I would be appreciate how to give me some guideline how to do this one
any chance C3 is missing some values? ('b','e','f'), ('a','b','e')
im sure it's not the best way but its a start:
from itertools import combinations
FI2 = [('a','b'),('a','c'),('a','d'),('b','d'),('b','e'),('e','f')]
# check if two tuples have at least one var in common
check_intersection = (lambda c: len(set(c[0]).intersection(set(c[1]))) > 0)
# run on all FI2 pairs combinations
# if two tuples have at least one var in common, a merged tuple is added
# remove the duplicates tuples from the new list
C3 = list(set([tuple(sorted(set(c[0] + c[1])))for c in combinations(FI2,2) if check_intersection(c)]))
print(C3)
#=> [('b', 'd', 'e'), ('a', 'b', 'e'), ('b', 'e', 'f'), ('a', 'b', 'd'), ('a','c','d'), ('a', 'b', 'c')]

Python: Munging data with '.join' (TypeError: sequence item 0: expected string, tuple found)

I have data in following format:
[('A', 'B', 'C'),
('B', 'C', 'A'),
('C', 'B', 'B')]
I'm looking to get this:
ABC
BCA
CBB
I'm able to convert one tuple at the time:
>> "".join(data[0])
.. 'ABC'
However when I'm trying to conver the whole list Python gives me an error:
>> "".join(data[:])
.. TypeError: sequence item 0: expected string, tuple found
Any advice how I'll be able to convert the whole list?
Thank you!
.join expects a sequence of strings, but you're giving it a sequence of tuples.
To get the result you posted, you'll need to join each element in each tuple, and then join each tuple together:
print('\n'.join(''.join(elems) for elems in data))
This works because .join will accept a generator expression, allowing you to iterate over data (your list of tuples).
We therefore have two joins going on: the inner join builds a string of the three letters (eg, 'ABC'), and the outer join places newline characters ('\n') between them.
lst=[('A', 'B', 'C'),
('B', 'C', 'A'),
('C', 'B', 'B')]
for x in lst:
print ("".join(x))
Output is;
>>>
ABC
BCA
CBB
>>>
One-liner;
print ("\n".join(["".join(x) for x in lst]))
You have to reach each element in the list first.
a = [('A', 'B', 'C'), ('B', 'C', 'A'), ('C', 'B', 'B')]
print ["".join(line) for line in a]

Python backtracking strings lenght n from alphabet {a,b,c} with #a=#b

i want to make an algoritm that finds for a given n the strings made on the alphabet {a,b,c} in which the number 'a' appears the same times of 'b'
i came out with this
n=3 #length String
h=-1 #length prefix
L=['a','b','c'] #alphabet
S=['','','',''] #solution
par=0 # it's zero if a and b have same occurence
def P(n,h,par,L,S):
if h==n:
if par==0:
print(S)
else:
for i in L:
if i=='a':
par+=1
if i=='b':
par-=1
S[h+1]=i
P(n,h+1,par,L,S)
#Update the stack after recursion
if S[h+1]=='a':
par-=1
if S[h+1]=='b':
par+=1
P(n,h,par,L,S)
i apologize for the poor string implementation but it works and it's only for studying purpose, the question is: there are ways to avoid some work for the algorithm? because it only checks #a and #b in the end after have generate all n-length strings for this alphabet.
my goal is to achieve O(n*(number of strings to print))
Is this what you're trying to do:
from itertools import combinations_with_replacement
alphabet = "abc"
def combs(alphabet, r):
for comb in combinations_with_replacement(alphabet, r):
if comb.count('a') == comb.count('b'):
yield comb
For this,
list(combs(alphabet, 3)) == [('a', 'b', 'c'), ('c', 'c', 'c')]
and
list(combs(alphabet, 4)) == [('a', 'a', 'b', 'b'),
('a', 'b', 'c', 'c'),
('c', 'c', 'c', 'c')]
This will produce all combinations and reject some; according to the docs for combinations_with_replacement:
The number of items returned is (n+r-1)! / r! / (n-1)! when n > 0.
where n == len(alphabet).
You can cut out the wasted work by changing the following:
if i=='a':
par+=1
if i=='b':
par-=1
to
oldpar = par
if i=='a':
par+=1
if i=='b':
par-=1
# there are n-h-1 characters left to place
# and we need to place at least abs(par) characters to reach par=0
if abs(par)>n-h-1:
par = oldpar
continue

Converting the output of itertools.permutations from list of tuples to list of strings

Having some issues with a list after using the itertools permutations function.
from itertools import permutations
def longestWord(letters):
combinations = list(permutations(letters))
for s in combinations:
''.join(s)
print(combinations)
longestWord("aah")
The output looks like this:
[('a', 'a', 'h'), ('a', 'h', 'a'), ('a', 'a', 'h'), ('a', 'h', 'a'),
('h', 'a', 'a'), ('h', 'a', 'a')]
I would like this to be a simple list, but it seems to be coming out as a list of tuples(?). Can anyone help me format this so it comes out as the following:
['aah', 'aha', 'aah', 'aha', 'haa', 'haa']
from itertools import permutations
def longestWord(letters):
return [''.join(i) for i in permutations(letters)]
print(longestWord("aah"))
Result:
['aah', 'aha', 'aah', 'aha', 'haa', 'haa']
A few suggestions:
Don't print inside the function, return instead and print the returned value.
Your naming of variable combination is not good, as combination is different from permutation
Your join wasn't doing anything, join doesn't change value inline, it returns the string
The function name does not represent what it does. longest word?
Permutations returns an iterator yielding tuples so you need to join them. A map is a nice way to do it instead of your for-loop.
from itertools import permutations
def longestWord(letters):
combinations = list(map("".join, permutations(letters)))
print(combinations)
longestWord("aah")
The way you were doing it, you were joining the letters in each tuple into a single string but you weren't altering the combinations list.
one liner
[''.join(h) for h in [list(k) for k in longestWord("aah")]]
Try this instead:
combinations = permutations(letters)
print [''.join(x) for x in combinations]
(Your join wasn't really doing anything useful--after the join was performed its return value wasn't saved.)

Categories