Create combinations from a list and 3 ranges using itertools - python

I have the following:
a_list = [A,B,C]
r1 = range(1,5)
r2 = range(1,5)
r3 = range(1,5)
I would like to be able to find the various combinations of the elements in this list against the ranges. For example:
combi1 = [A, B, C, C, C]
combi2 = [A, A, B, C, C]
combi3 = [A, A, A, B, C]
combi4 = [A, B, B, C, C]
Etc.
I am able to do so if there were only 2 range, but I'm not sure how to fit 3 range in.
inc = range(1, 5)
desc = range(5, 1, -1)
combis = [list(itertools.chain(*(itertools.repeat(elem, n) for elem, n in zip(list, [i,j])))) for i,j in zip(inc,desc)]
SOLUTION:
def all_exist(avalue, bvalue):
return all(any(x in y for y in bvalue) for x in avalue)
combins = itertools.combinations_with_replacement(a_list, 5)
combins_list = [list(i) for i in combins]
for c in combins_list:
if all_exist(a_list, c) == True:
print c
output:
['A', 'A', 'A', 'B', 'C']
['A', 'A', 'B', 'B', 'C']
['A', 'A', 'B', 'C', 'C']
['A', 'B', 'B', 'B', 'C']
['A', 'B', 'B', 'C', 'C']
['A', 'B', 'C', 'C', 'C']

#doyz. I think this is may be what you are looking for :
From a list abc = ['A','B','C'], you want to obtain its various combinations with replacement. Python has built-in itertools to do this.
import itertools
abc = ['A', 'B', 'C'];
combins = itertools.combinations_with_replacement(abc, 5);
combins_list = [list(i) for i in combins];
print(combins_list[0:10]);
This is the first 10 combinations with replacement :
[['A', 'A', 'A', 'A', 'A'], ['A', 'A', 'A', 'A', 'B'], ['A', 'A', 'A', 'A', 'C'], \
['A', 'A', 'A', 'B', 'B'], ['A', 'A', 'A', 'B', 'C'], ['A', 'A', 'A', 'C', 'C'], \
['A', 'A', 'B', 'B', 'B'], ['A', 'A', 'B', 'B', 'C'], ['A', 'A', 'B', 'C', 'C'], ['A', 'A', 'C', 'C', 'C']]
If you want to include all elements in abc, here is one way, that also includes the permutations :
import itertools
abc = ['A', 'B', 'C'];
combins = itertools.combinations_with_replacement(abc, 5);
combins_list = list(combins);
combins_all =[];
for i in combins_list:
if len(set(i))==len(abc):
combins_all.append(i);
print(combins_all);
include_permutations=[];
for i in combins_all:
permut = list(itertools.permutations(i));
include_permutations.append(permut);
print(include_permutations);
Is this okay?
*Note : itertools.combinations_woth_replacement and itertools.permutations do not result in a list, or tuple, but a different object itself, so you can't treat it as those.

Related

Iterating over two lists A and B

I am trying to iterate over two lists A and B. Where the B is equal to A - A[i], where i = 1:
For E.g. listA = ['A', 'B', 'C', 'D'].
For first Item, 'A' in List A, I
want the List B to have ['B', 'C', 'D'] For second Item 'B' in List A,
I want the List B to have ['A', 'C', 'D']
What I have tried until now.
listA = ['A', 'B', 'C', 'D']
for term in listA:
listA.remove(term)
for item in listA:
print(listA)
If all you want is to print the sublists, it will be like:
for i in range(len(listA)):
print(listA[:i]+listA[i+1:])
Or,
for i in listA:
print(list(set(listA) - set(i)))
Try this,
>>> la = ['A', 'B', 'C', 'D']
>>> for i in la:
_temp = la.copy()
_temp.remove(i)
print(_temp)
Output:
['B', 'C', 'D']
['A', 'C', 'D']
['A', 'B', 'D']
['A', 'B', 'C']
*If you want to assign the print output to new variables, use a dictionary where the key will the name of list and value is printted output.
Is this what you want?
listA = ['A', 'B', 'C', 'D']
Bs = \
[listA[:idx] + listA[idx + 1:]
for idx
in range(len(listA))]
for B in Bs:
print(B)
Taking the above solutions a step further, you can store a reference to each of the resulting list in the corresponding variable using a dictionary comprehension:
keys_map = {x: [item for item in listA if item != x] for x in listA}
print(keys_map)
Output
{
'A': ['B', 'C', 'D'],
'B': ['A', 'C', 'D'],
'C': ['A', 'B', 'D'],
'D': ['A', 'B', 'C']
}
and access the desired key like so
keys_map.get('A')
# returns
['B', 'C', 'D']

How to restrict the longest sequence of the same letter using python

How can I determine the longest sequence of the same letter using python?
For example I use the following code to print a shuffled list with 3 conditions A,B and C
from random import shuffle
condition = ["A"]*20
condition_B = ["B"]*20
condition_C = ["C"]*20
condition.extend(condition_B)
condition.extend(condition_C)
shuffle(condition)
print(condition)
Now i want to make sure that the same condition does not happen more than three times in a row.
E.g., allowed: [A, B, C, A, B, B, C, C, C, A, B….]
Not allowed: [A, A, B, B, B, B, C, A, B...] (because of four B’s in a row)
How can I solve this problem?
Thank you in advance.
Maybe you should build the list sequentially, rather than shuffling:
result = []
for i in range(60): # for each item in original list
start = true # we haven't found a suitable one yet
if start or i>2: # don't do checking unless 3 items in list
while start or (
c==shuf[-1] and # is the chosen value
c==shuf[-2] and # the same as any of
c==shuf[-3] ): # the last 3 items?
idx = random.randint(0,len(condition)) # chose a new one
c = condition[idx]
start = false
result.append(c) # add to result
del condition[i] # remove from list
Warning! not tested - just conceptual...
# Validate with this function it return false if more than three consecutive characters are same else True.
def isValidShuffle( test_condition):
for i in range(len(test_condition)-4):
if len(set(test_condition[ i:i+4])) == 1:
# set size will be 1 all four consecutive chars are same
return False
return True
Simplest way to create shuffled sequence of A,B,C for which isValidShuffle will return True.
from random import shuffle
# condition list contains 20 A's 20 B's 20 C's
seq = ['A','B','C']
condition = []
for seq_i in range(20):
shuffle(seq)
condition += seq
print(condition) # at most two consecutive characters will be same
print(isValidShuffle(condition))
-----------------------------------------------------------------------------
Output
['A', 'B', 'C', 'B', 'C', 'A', 'C', 'B', 'A', 'C', 'B', 'A', 'C', 'A', 'B', 'C', 'B', 'A', 'B', 'A', 'C', 'B', 'C', 'A', 'B', 'C', 'A', 'C', 'A', 'B', 'B', 'C', 'A', 'B', 'A', 'C', 'A', 'B', 'C', 'C', 'A', 'B', 'A', 'B', 'C', 'B', 'A', 'C', 'C', 'A', 'B', 'B', 'C', 'A', 'B', 'A', 'C', 'A', 'B', 'C']
...............................................................................................................................................................
This is not imposing your restriction while creating shuffled sequence but keeps on trying until it find the sequence which meets your consecutive char restriction.
validshuffle = False
condition = ['A']*20 + ['B']*20 + ['C']*20
while not validshuffle:
shuffle(condition)
if isValidShuffle(condition):
validshuffle = True
print(condition)
-------------------------------------------------------------------------------
Output
try
try
['A', 'C', 'A', 'B', 'B', 'C', 'B', 'C', 'A', 'C', 'A', 'C', 'B', 'B', 'B', 'C', 'A', 'A', 'B', 'C', 'A', 'A', 'B', 'B', 'C', 'B', 'B', 'C', 'B', 'C', 'C', 'B', 'A', 'B', 'B', 'A', 'C', 'A', 'A', 'C', 'A', 'C', 'B', 'C', 'A', 'A', 'C', 'A', 'C', 'A', 'C', 'B', 'B', 'B', 'A', 'B', 'C', 'A', 'C', 'A']
If you just want to know, how long is the longest subsequence, you could do this.
This is iterating over it the sequence and recording the length of the subsequences of the same character, saving it, getting the max for each subsequence, and then, getting the max of characters.
This is not exactly the problem you mention, but It could be useful.
from random import shuffle
sequence = ['A']*20 + ['B']*20 + ['C']*20
sequences = {'A': [], 'B':[], 'C':[]}
shuffle(sequence)
current = sequence[0]
acc = 0
for elem in sequence:
if elem == current:
acc += 1
else:
sequences[current].append(acc)
current = elem
acc = 1
else:
sequences[current].append(acc)
for key, seqs in sequences.items():
sequences[key] = max(seqs)
print(max(sequences.items(), key=lambda i: i[1]))

Global list mutation inside function in Python

I am working on a backtracking solution for this problem - "Given a string s, partition s such that every substring of the partition is a palindrome."
I have written this code where I am not able to get how is the global 2D list strings is getting updated? What exactly is happening here? I tried using global keyword too with it inside palinBreak function, but it doesn't help! When should global keyword be used?
Observation: Every element of global list strings changes to local list variable arr. For instance, strings = [x, y] and arr = [z], then strings becomes [z, z, z]; whereas I want it to be [x, y, z]. Why does this happen?
EDIT: Adding expected output vs. output I am getting (take notice from line 3 onwards).
Expected output is:
ans is ['a', 'b', 'a', 'a', 'b'] []
strings is [['a', 'b', 'a', 'a', 'b']]
ans is ['a', 'b', 'aa', 'b'] [['a', 'b', 'a', 'a', 'b']]
strings is [['a', 'b', 'a', 'a', 'b'], ['a', 'b', 'aa', 'b']]
ans is ['a', 'baab'] [['a', 'b', 'a', 'a', 'b'], ['a', 'b', 'aa', 'b']]
strings is [['a', 'b', 'a', 'a', 'b'], ['a', 'b', 'aa', 'b'], ['a', 'baab']]
ans is ['aba', 'a', 'b'] [['a', 'b', 'a', 'a', 'b'], ['a', 'b', 'aa', 'b'], ['a', 'baab']]
strings is [['a', 'b', 'a', 'a', 'b'], ['a', 'b', 'aa', 'b'], ['a', 'baab'], ['aba', 'a', 'b']]
[['a', 'b', 'a', 'a', 'b'], ['a', 'b', 'aa', 'b'], ['a', 'baab'], ['aba', 'a', 'b']]
Output:
ans is ['a', 'b', 'a', 'a', 'b'] []
strings is [['a', 'b', 'a', 'a', 'b']]
ans is ['a', 'b', 'aa', 'b'] [['a', 'b', 'aa', 'b']]
strings is [['a', 'b', 'aa', 'b'], ['a', 'b', 'aa', 'b']]
ans is ['a', 'baab'] [['a', 'baab'], ['a', 'baab']]
strings is [['a', 'baab'], ['a', 'baab'], ['a', 'baab']]
ans is ['aba', 'a', 'b'] [['aba', 'a', 'b'], ['aba', 'a', 'b'], ['aba', 'a', 'b']]
strings is [['aba', 'a', 'b'], ['aba', 'a', 'b'], ['aba', 'a', 'b'], ['aba', 'a', 'b']]
[[], [], [], []]
>>>
Code:
def isPalin(s):
i = 0
j = len(s)-1
while(i<j):
if(s[i]!=s[j]):
return False
i+=1
j-=1
return True
def palinBreak(s, start, arr):
#print "Called", start, arr
#global strings
if(start==len(s)):
print "ans is", arr, strings
strings.append(arr)
print "strings is", strings
return 0
flag = -1
for i in range(1, len(s)-start+1):
curr = s[start : start+i]
#print "Testing curr and start and i", curr, start, i
if(isPalin(curr)):
arr.append(curr)
#print arr, start, i
#print "Next call from", start+i
pb = palinBreak(s, start+i, arr)
if(pb != -1):
flag = 1
arr.pop()
#print "popped l", arr
return flag
strings = []
palinBreak("abaab", 0, [])
print strings
The problem is that arr will be the same list in the inner recursive calls.
Try to replace
pb = palinBreak(s, start+i, arr)
with
pb = palinBreak(s, start+i, list(arr))

Sorting Lists by Repetitions in Python

I have a list that contains multiple repeated items. I'm trying to sort the list by giving items with the most repetitions priority.
So it would turn this
['a', 'b', 'c', 'a', 'b', 'a', 'd']
into this
['a', 'a', 'a', 'b', 'b', 'c', 'd']
>>> from collections import Counter
>>> [k for k,v in Counter(['a', 'b', 'c', 'a', 'b', 'a', 'd']).most_common() for i in xrange(v)]
['a', 'a', 'a', 'b', 'b', 'c', 'd']
This is possibly easier to follow
>>> counter = Counter(['a', 'b', 'c', 'a', 'b', 'a', 'd'])
>>> sorted(counter.elements(), key=counter.get, reverse=True)
['a', 'a', 'a', 'b', 'b', 'c', 'd']
d = {}
for a in l:
d[a] += d.setdefault(a,0)
l.sort(key = lambda k: (d[k],k), reverse = True)
[v for (v, c) in sorted(((x, list(y)) for (x, y) in
itertools.groupby(sorted(['a', 'b', 'c', 'a', 'b', 'a', 'd']))),
key=lambda x: len(x[1]), reverse=True) for z in c]
EDIT:
Now with sum()!
sum((c for (v, c) in sorted(((x, list(y)) for (x, y) in
itertools.groupby(sorted(['a', 'b', 'c', 'a', 'b', 'a', 'd']))),
key=lambda x: len(x[1]), reverse=True)), [])
l = ['a', 'b', 'c', 'a', 'b', 'a', 'd']
sorted_list = [item for item in sorted(l, key=lambda x: l.count(x), reverse=True)]
While this is a simple solution, mind the complexity of counting every element when using large lists.

Evaluating subset of a list using in operator

I have following test code.
a = ['a', 'b', 'c', 'd', 'e']
c = a * 3
b = a
but b in c returns False. b is a sub sequence of c and the list c contains b. So why is it returning false?
Thanks in advance.
b in c
Does not work because b looks like:
['a', 'b', 'c', 'd', 'e']
and c looks like:
['a', 'b', 'c', 'd', 'e', 'a', 'b', 'c', 'd', 'e', 'a', 'b', 'c', 'd', 'e']
In other words, b is not an element of the sequence. Instead, b is a subsequence. If you were to construct c as follows:
c = [a, a, a]
Then c would look like:
[['a', 'b', 'c', 'd', 'e'], ['a', 'b', 'c', 'd', 'e'], ['a', 'b', 'c', 'd', 'e']]
And "b in c" would return True.
Hope this helps.
If you had this code:
a = ['a', 'b', 'c', 'd', 'e']
c = [a] * 3
b = a
when you type b in c you would get True.
In this case
c = [a] * 3 (with [ ] around a)
would return:
[['a', 'b', 'c', 'd', 'e'], ['a', 'b', 'c', 'd', 'e'], ['a', 'b', 'c', 'd', 'e']]

Categories

Resources