How to properly eliminate elements in dictionary until one string remains - python

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 :-)

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']

Enumerating all possible scenarios

I am trying to find all of the possible combinations for a set. Suppose I have 2 vehicles (A and B) and I want to use them by sending them and then return. Send and return are two distinct actions, and I want to enumerate all of the possible sequences of sending and returning this vehicle. Thus the set is [ A, A, B, B]. I use this code to enumerate:
from itertools import permutations
a = permutations(['A', 'A', 'B', 'B'])
# Print the permutations
seq = []
for i in list(a):
seq.append(i)
seq = list(set(seq)) # remove duplicates
The result is as follows:
('A', 'B', 'B', 'A')
('A', 'B', 'A', 'B')
('A', 'A', 'B', 'B')
('B', 'A', 'B', 'A')
('B', 'B', 'A', 'A')
('B', 'A', 'A', 'B')
Suppose my assumption is the two vehicles identical. Thus, it doesn't matter which one is on the first order (i.e. ABBA is the same as BAAB). Here's what I expect the result is:
('A', 'B', 'B', 'A')
('A', 'B', 'A', 'B')
('A', 'A', 'B', 'B')
I can do this easily by removing the last three elements. However, I encounter a problem when I try to do the same thing for three vehicles ( a = permutations(['A', 'A', 'B', 'B', 'C', 'C']). How to ensure that the result already considers the three identical vehicles?
One way would be to generate all the combinations, then filter for only those where the first mention of each vehicle is in alphabetical order.
In recent versions of Python, dict retains first-insertion order, so we can use it to determine the first mention; something like:
from itertools import permutations
seq = set()
for i in permutations(['A', 'A', 'B', 'B']):
first_mentions = {car: None for car in i}.keys()
if list(first_mentions) == sorted(first_mentions):
seq.add(i)
(This works in practice since Python 3.5, and officially since Python 3.7)
from itertools import permutations
a = permutations(['A', 'A', 'B', 'B'])
seq = []
for i in list(a):
if i[0]=='A':
seq.append(i)
seq = list(set(seq))
print(seq)
Try this, I think this should do

Why reading/unpacking data from itertools.permutation changed its attribute/content?

I am trying to use the permutation feature from itertools, then I noticed. If I try to unpack/read the data from permutation, it changes some attribute info
from itertools import permutations
a = permutations('abc')
print(('a', 'b', 'c') in a)
for x in a:
print(x)
print(('a', 'b', 'c') in a)
for x in a:
print(x)
Output:
True
('a', 'c', 'b')
('b', 'a', 'c')
('b', 'c', 'a')
('c', 'a', 'b')
('c', 'b', 'a')
False
How come does this happen? I checked out the official page, and cannot find any clue.
My environment is pycharm with python 3.7.4
As others aready said, the problem is that a is not a list, but a generator; that is, a sequence that gets used up as you iterate over it -- hence you can only iterate over it once.
If you look carefully, you'll see that your first print loop only printed five of the six permutations; the first permutation disappeared when you checked it against ('a', 'b', 'c') in your first print statement. The for-loop then prints out what's left, and the rest of your code is trying to drink from an empty cup.
To get the behavior you expect, make a into a list like this:
a = list(permutations('abc'))
And when you get a chance, read up on generators, iterators, and "comprehensions"; they're everywhere in Python (often hidden in plain sight), and they're great.
Get rid from generator and convert the output to list since the comparison is vanishing because it used already. itertools.permutation is just an iterator which is shifting to next when you use one value in comparison.
CODE:
from itertools import permutations
a = list(permutations('abc'))
print(('a', 'b', 'c') in a)
for x in a:
print(x)
print(('a', 'b', 'c') in a)
for x in a:
print(x)
OUTPUT:
True
('a', 'b', 'c')
('a', 'c', 'b')
('b', 'a', 'c')
('b', 'c', 'a')
('c', 'a', 'b')
('c', 'b', 'a')
True
('a', 'b', 'c')
('a', 'c', 'b')
('b', 'a', 'c')
('b', 'c', 'a')
('c', 'a', 'b')
('c', 'b', 'a')

Replacing items in nested array and list-tuple

Good day to all.
I've been looking for a way to replace items within an array.
Basically I have an array with nested list that looks like that:
array = [ ('a', 'a'), 'c', ('c', 'a'), 'g', 'g', ('h', 'a'), 'a']
Now I'm looking for a way to replace all the appearances of 'a' with 'z'.
and I was hopping to use the following code line in order to achieve that:
new_array = [w.replace('a', 'z') for w in array]
new_array = [ ('z', 'z'), 'c', ('c', 'z'), 'g', 'g', ('h', 'z'), 'a']
Yet, unfortunately I'm receiving the following error:
AttributeError: 'tuple' object has no attribute 'replace'.
I understand the main problem is caused by the use of the tuple (a, x), but they're crucial part of the desired array.
I've spent hours looking for a way around it, And I would highly appreciate any hint in the right direction.
Your help is appreciated!
def replace(value, find, rep):
if isinstance(value, tuple):
return tuple(rep if val==find else val for val in value)
return value
new_array = [replace(val, 'a', 'z') for val in array]
the last ) should be ].
array = [ ('a', 'a'), 'c', ('c', 'a'), 'g', 'g', ('h', 'a'), 'a']
map(lambda l: tuple(i if i != 'a' else 'z' for i in l) if isinstance(l, tuple) else l, array)

Append all possibilities from sequences with numbers

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]

Categories

Resources