Append all possibilities from sequences with numbers - python

I have a question that is consuming my brain. Let us suppose that the variable I stores a sequence, and the variable II another one, and the variable III another one too. The variable one will represent the number 1, the next 2 and the next 3; and then I have another key variable with random characters of these 3 sequences. Giving that fact, I can easily translate the characters of this key variable in the correspondent numbers. In the example, x = 'afh', than, it is the same to say that x = '123', because A OR B OR C = 1, and so on.
Now comes the complicated part:
When the key variable x is translated into numbers, each character individually, I can also return characters randomly from the result. For example: x = '123', then I can return a list like ['a','e','f'], or ['b','d','i'], especially if I use random.choice(). From this, what I couldn't figure out how to do yet is:
How can I append into a list ALL THE POSSIBLE VARIATIONS from the variables I, II, III. For example:
['adg','beh','cfi','aei','ceg',...]
I know how to print endlessly random combinations, but in this case, I get repetitions, and I don't want them. I want to append to a list exactly all the possible variations between I, II and III, because when they're translated into numbers, I can return any character from the correspondent sequence. Well, I hope my example is self-explainable. I thank you all very much for the attention!
I = 'abc' # 1
II = 'def' # 2
III = 'ghi' # 3
x = 'afh' # Random possibility: It could be an input.
L = []
LL = []
for i in range(len(x)):
if x[i] in I:
L.append(1)
if x[i] in II:
L.append(2)
if x[i] in III:
L.append(3)
for i in range(len(L)): # Here lies the mistery...
if L[i] == 1:
LL.append(I)
if L[i] == 2:
LL.append(II)
if L[i] == 3:
LL.append(III)
print L
print LL
The output is:
[1, 2, 3]
['abc', 'def', 'ghi']

Here's how I would rewrite your code. Lengthy if statements like yours are a big code smell. I put the sequences into a tuple and used a single loop. I also replaced the second loop with a list comprehension.
By the way, you could also simplify the indexing if you used zero based indexing like a sensible person.
I = 'abc' # 1
II = 'def' # 2
III = 'ghi' # 3
x = 'afh' # Random possibility: It could be an input.
L = []
LL = []
lists = I, II, III
for c in x:
for i, seq in enumerate(lists):
if c in seq:
L.append(i+1)
LL = [lists[i-1] for i in L]
print L
print LL
Also, be sure to check out the itertools module, and in particular the product function. It's not clear exactly what you mean, but product gives you all combinations of an item from each of a list of sequences.

Thank you very much Antimony! The answer is exactly product() from itertools. The code with it is bloody far more simple:
from itertools import *
I = 'abc' # 1
II = 'def' # 2
III = 'ghi' # 3
IV = product(I,II,III)
for i in IV:
print i
And the output is exactly what I wanted, every possible combination:
('a', 'd', 'g')
('a', 'd', 'h')
('a', 'd', 'i')
('a', 'e', 'g')
('a', 'e', 'h')
('a', 'e', 'i')
('a', 'f', 'g')
('a', 'f', 'h')
('a', 'f', 'i')
('b', 'd', 'g')
('b', 'd', 'h')
('b', 'd', 'i')
('b', 'e', 'g')
('b', 'e', 'h')
('b', 'e', 'i')
('b', 'f', 'g')
('b', 'f', 'h')
('b', 'f', 'i')
('c', 'd', 'g')
('c', 'd', 'h')
('c', 'd', 'i')
('c', 'e', 'g')
('c', 'e', 'h')
('c', 'e', 'i')
('c', 'f', 'g')
('c', 'f', 'h')
('c', 'f', 'i')

python 3.2
[(i,v,c) for i in I for v in II for c in III]

Related

product of list of list of letter [[a,b],[c,d],[a,n]]

I have list of posiple letter for each letter in a word..and I want to find all possiple words.
for example the input is [[l,b],[e,d],[s,t]] this represent a word of 3 letter wher first letter could be l or b, second letter could be e or d and third letter is s or t. I wont the out put to be the product of these lists [les,let,bet,...and so on]. the list could be any length not only three.
I tried
res = list(map(prod, zip(test_list)))
but I get
[<itertools.product object at 0x0000024F65AEC600>, <itertools.product object at 0x0000024F65AEC640>, <itertools.product object at 0x0000024F65AEC680>, <itertools.product object at 0x0000024F65AEC6C0>]
I tried
word1=list(product(letter[0],letter[1],letter[2]))
it works perfectly but I want the code to accept any length pf list
You don't want to zip the test_list, just pass each element of it as an argument to product using the * operator:
>>> test_list = [['l','b'],['e','d'],['s','t']]
>>> import itertools
>>> list(itertools.product(*test_list))
[('l', 'e', 's'), ('l', 'e', 't'), ('l', 'd', 's'), ('l', 'd', 't'), ('b', 'e', 's'), ('b', 'e', 't'), ('b', 'd', 's'), ('b', 'd', 't')]
If you want the result to be in string form, use join:
>>> [''.join(p) for p in itertools.product(*test_list)]
['les', 'let', 'lds', 'ldt', 'bes', 'bet', 'bds', 'bdt']

How to identify possible chain pattern from list of tuples

Edited
Looking for easy or optimized way of implementing below problem, seems with "networkx" we can achieve this quite easily (Thanks to BENY in comment section)
input_list = [('A','B'),('D','C'),('C','B'),('E','D'),('I','J'),('L','K'),('J','K')] # path map
def get_chain_list(sp, d):
global result
result.append(sp)
if sp in d : get_chain_list(d[sp], d)
return tuple(result)
d = dict(input_list)
s1 = set(d.keys())
s2 = set(d.values())
sps = s1 - s2
master_chain = []
for sp in sps :
result = []
master_chain.append(get_chain_list(sp, d))
output_list = sorted(master_chain, key=len, reverse=True)
print(output_list)
[('E', 'D', 'C', 'B'), ('I', 'J', 'K'), ('A', 'B'), ('L', 'K')] # Chains in input list
This is more like a networkx problem
import networkx as nx
G = nx.Graph()
G.add_edges_from(input_list)
l = [*nx.connected_components(G)]
Out[6]: [{'A', 'B', 'C', 'D', 'E'}, {'I', 'J', 'K', 'L'}]
Use
output_list = set(input_list)
then form the required chain pattern using tuples like so:
from string import ascii_uppercase
input_list = [('A','B'),('D','C'),('C','B'),
('E','D'),('I','J'),('L','K'),('J','K')]
src=sorted({e for t in input_list for e in t})
ss=""
tgt=[]
for c in src:
if ss+c in ascii_uppercase:
ss+=c
else:
tgt.append(tuple(ss))
ss=c
else:
tgt.append(tuple(ss))
>>> tgt
[('A', 'B', 'C', 'D', 'E'), ('I', 'J', 'K', 'L')]

How to get new input to generator in Python without create a new generator

I try to write code that gets a list and generates all of this transformations by using yield statement.
The problem is when I want to get new input to generator by using send function, I continue to get the old input.
def permute(items):
permutations = [x for x in itertools.permutations(items)]
permutations.sort()
for n in permutations:
yield (n)
g = permute(['b','a','c'])
print(next(g)) #('a', 'b', 'c')
print(next(g)) #('a', 'c', 'b')
g.send(['e','q','c'])
print(next(g)) #('b', 'c', 'a') need to be ('c', 'e', 'q')
How can I empty the permutation list and repeat to sorting permutations list step without create a new generator?
Why not just create a new object of type permute and use it
import itertools
def permute(items):
permutations = [x for x in itertools.permutations(items)]
permutations.sort()
for n in permutations:
yield (n)
g = permute(['b','a','c'])
print(next(g)) #('a', 'b', 'c')
print(next(g)) #('a', 'c', 'b')
g = permute(['e','q','c'])
print(next(g)) #('b', 'c', 'a') need to be ('c', 'e', 'q')
#I get ('c', 'e', 'q')

why this python function skips index 1 to 3 without iterating index 2 when running in a for loop

I wrote a function in order to remove parts that duplicates in two strings. I first transform string into list and iterate through the two list to find if characters on the same position are the same. The problem is when iterating,
the code skips index 2. (ex:list="index",the iterator jump to 'd' after iterating 'i').
I've tried to use "replace" method to do string operation but I did not get the result I want. "Replace" method removed parts that I want.
def popp(s,t):
s_lis=list(s)
t_lis=list(t)
ind=0
for i,j in zip(s_lis,t_lis):
if i==j:
s_lis.pop(ind)
t_lis.pop(ind)
else:ind+=1
return s_lis,t_lis
# test the code
print(popp('hackerhappy','hackerrank'))
expected result: ['h','p','p','y'] ['r','n','k']
actual result: ['k', 'r', 'h', 'a', 'p', 'p', 'y'], ['k', 'r', 'r', 'a', 'n', 'k']
To begin with, you should use itertools.zip_longest which makes a zip out of the longest subsequence. You are using zip which makes a zip out of the shortest subsequence which is what you don't want.
So in our case, it will be
print(list(zip_longest(s_lis, t_lis)))
#[('h', 'h'), ('a', 'a'), ('c', 'c'), ('k', 'k'), ('e', 'e'),
#('r', 'r'), ('h', 'r'), ('a', 'a'), ('p', 'n'), ('p', 'k'), ('y', None)]
Then you should use another list to append the non-common characters rather then operating on the same list you are iterating on via s_lis.pop(idx)
So if the characters in the tuple do not match, append them if they are not None
from itertools import zip_longest
def popp(s,t):
s_lis = list(s)
t_lis = list(t)
s_res = []
t_res = []
#Use zip_longest to zip the two lists
for i, j in zip_longest(s_lis, t_lis):
#If the characters do not match, and they are not None, append them
#to the list
if i != j:
if i!=None:
s_res.append(i)
if j!=None:
t_res.append(j)
return s_res, t_res
The output will look like:
print(popp('hackerhappy','hackerrank'))
#(['h', 'p', 'p', 'y'], ['r', 'n', 'k'])
You could modify your code slightly
def popp(s, t):
s_lis = list(s)
t_lis = list(t)
s_res = []
t_res = []
# match each character. Stops once the
# shortest list ends
for i, j in zip(s_lis, t_lis):
if i != j:
s_res.append(i)
t_res.append(j)
# if s is longer, take rest of the string and
# add it to residual
if len(s) > len(t):
for x in s_lis[len(t):]:
s_res.append(x)
if len(t) > len(s):
for x in t_lis[len(s):]:
t_res.append(x)
print(s_res)
print(t_res)
popp('hackerhappy','hackerrank')

How to properly eliminate elements in dictionary until one string remains

I really need help on this
def get_winner (dict_winner):
new_dict = {}
for winner in dict_winner:
first_letter = winner[0]
value = dict_winner[winner]
if first_letter in new_dict:
new_dict[first_letter] += value
else:
new_dict[first_letter] = value
return (new_dict)
get_winner({
('C', 'A', 'B', 'D') :3,
('D', 'B', 'C', 'A') :2,
('C', 'D', 'A', 'B') :1,
('A', 'D', 'B', 'C') :2,
('A', 'D', 'C', 'B') :4,
('A', 'C', 'D', 'B') :2
})
#Outputs {'A': 8, 'D': 2, 'C': 4}
Now I want the result be a tuple of str, NoneType..
Also, it is eliminating only the letter with the smallest value in first place only one time. I want it to repeat this process until I get one winner in the end. So in this case all the B's will be eliminated in the dict itself, not in the output. for example:
first time = [8, 0, 4, 2]
second time = {
('C', 'A', 'D') :3,
('D', 'C', 'A') :2,
('C', 'D', 'A') :1,
('A', 'D', 'C') :2,
('A', 'D', 'C') :4,
('A', 'C', 'D') :2
})
#Outputs C = 4 D = 2 A = 8
third time= {
('C', 'A') :3,
('C', 'A') :2,
('C', 'A') :1,
('A', 'C') :2,
('A', 'C') :4,
('A', 'C') :2
})
#Outputs C = 6 A = 8
8/ 14 > 50%, I know that should have been the case since the beginning because A already had the majority value. But i am assuming A has a value of 40% which is when elimination should begin. So, could you point out where I went wrong in coding this? In the example A should be the winner! So the output shopuld be
('A', None)
Your current code counts the number of times each candidate is the first on the list. It doesn't "eliminate" anyone, it just gives the appearance of doing so since one of your candidates gets no first-place votes.
I suggest doing it recursively. Your base case is "a candidate gets over 50% of the vote". Something like this:
def get_winner(vote_dict)
total_votes = sum(vote_dict.values())
votes_by_candidate = defaultdict(int) # This makes your if/else block redundant
for vote_pattern in vote_dict:
votes_by_candidate[vote_pattern[0]] += vote_dict[vote_pattern]
for candidate in votes_by_candidate:
if votes_by_candidate[candidate] * 2 > total_votes:
return candidate
new_dict = defaultdict(int)
eliminated = min(votes_by_candidate, key=votes_by_candidate.get)
for vote_pattern in vote_dict:
new_pattern = [candidate for candidate in vote_pattern if candidate != eliminated]
new_dict[new_pattern] += vote_dict[vote_pattern]
return get_winner(new_dict)
My solution - in one step:
def get_winner(candidates):
winners = dict.fromkeys(map(lambda f: f[0] for f in candidates.keys()))
for cand, votes in candidates.iteritems():
winners[cand[0]]+=votes
return [winner for winner, vote in winners.iteritems() if vote ==max(winners.values())]
It is not fancy, but it is simple :-)

Categories

Resources