Related
I'm new to programming and am having some trouble with this exercise. The goal is to write a function that returns a list of matching items.
Items are defined by a tuple with a letter and a number and we consider item 1 to match item 2 if:
Both their letters are vowels (aeiou), or both are consonants
AND
The sum of their numbers is a multiple of 3
NOTE: The return list should not include duplicate matches --> (1,2) contains the same information as (2,1), the output list should only contain one of them.
Here's an example:
***input:*** [('a', 4), ('b', 5), ('c', 1), ('d', 3), ('e', 2), ('f',6)]
***output:*** [(0,4), (1,2), (3,5)]
Any help would be much appreciated!
from itertools import combinations
lst = [('a', 4), ('b', 5), ('c', 1), ('d', 3), ('e', 2), ('f',6)]
vowels = 'aeiou'
matched = [(i[0],j[0]) for (i,j) in combinations(enumerate(lst),2) if (i[1][0] in vowels) == (j[1][0] in vowels) and ((i[1][1] + j[1][1]) % 3 == 0)]
print(matched)
Sorry, I'm high enough rep to comment, but i'll edit / update once I can.
Im a little confused about the question, what is the purpose of the letters, should we be using their positon in the alphabet as their value? i.e a=0, b=1?
what are we comparing one tuple to?
Thanks
You can use itertools.combinations with enumerate to iterate all combinations and output indices. Combinations do not include permutations, so you will not see duplicates.
from itertools import combinations
lst = [('a', 4), ('b', 5), ('c', 1), ('d', 3), ('e', 2), ('f',6)]
def checker(lst):
vowels = set('aeiou')
for (idx_i, i), (idx_j, j) in combinations(enumerate(lst), 2):
if ((i[0] in vowels) == (j[0] in vowels)) and ((i[1] + j[1]) % 3 == 0):
yield idx_i, idx_j
res = list(checker(lst))
# [(0, 4), (1, 2), (3, 5)]
I have done something like this:
d = [('e', 0), ('f', 1), ('e', 0), ('f', 1)]
e = ['a']
d = [(n,j) for n,(i,j) in zip(e,d)]
d
[('a',0)]
I was just tryig to replace the equivalent tuple value with the array value, without changing the associated numbers. But the list only goes till the len of array e and not d. What I want to get as output is something like this:
d
[('a', 0), ('f', 1), ('e', 0), ('f', 1)]
Just add the unprocessed tail of d to the processed part:
[(n,j) for n,(i,j) in zip(e,d)] + d[len(e):]
#[('a', 0), ('f', 1), ('e', 0), ('f', 1)]
You can use itertools.zip_longest:
[(n or i, j) for n,(i,j) in itertools.zip_longest(e, d)]
Check the doc
If it's acceptable to mutate the original d list, I'd simply replace the first d tuples by iterating on e:
d = [('e', 0), ('f', 1), ('e', 0), ('f', 1)]
e = ['a']
for i, new_letter in enumerate(e):
d[i] = (new_letter, d[i][1])
print(d)
# [('a', 0), ('f', 1), ('e', 0), ('f', 1)]
Note that Python tuples are immutable. d[i][0] = new_letter would fail with the error:
TypeError: 'tuple' object does not support item assignment
The above code modifies the d list in place by replacing old tuples with new ones. It cannot modify the old tuples.
I think the problem is the zip function. The documentation says that (zip) "Returns an iterator of tuples, where the i-th tuple contains the i-th element from each of the argument sequences or iterables. The iterator stops when the shortest input iterable is exhausted."
[(n,j) for n,(i,j) in zip(e,d)] + d[len(e):] should do the trick
I have the following OrderedDict:
OrderedDict([('r', 1), ('s', 1), ('a', 1), ('n', 1), ('y', 1)])
This actually presents a frequency of a letter in a word.
In the first step - I would take the last two elements to create a union tuple like this;
pair1 = list.popitem()
pair2 = list.popitem()
merge_list = (pair1[0],pair2[0])
new_pair = {}
new_pair[merge_list] = str(pair1[1] + pair2[1])
list.update(new_pair);
This created for me the following OrderedList:
OrderedDict([('r', 1), ('s', 1), ('a', 1), (('y', 'n'), '2')])
I would like now to iterate over the elements, each time taking the last three and deciding based on the lower sum of the values what is the union object.
For instance the above list will turn to;
OrderedDict([('r', 1), (('s', 'a'), '2'), (('y', 'n'), '2')])
but the above was:
OrderedDict([ ('r', 1), ('s', 2), ('a', 1), (('y', 'n'), '2')])
The result would be:
OrderedDict([('r', 1), ('s', 2), (('a','y', 'n'), '3')])
as I want the left ones to have the smaller value
I tried to do it myself but doesn't understand how to iterate from end to beginning over an OrderedDict.
How can I do it?
EDITED
Answering the comment:
I get a dictionary of frequency of a letter in a sentence:
{ 's':1, 'a':1, 'n':1, 'y': 1}
and need to create a huffman tree from it.
for instance:
((s,a),(n,y))
I am using python 3.3
Simple example
from collections import OrderedDict
d = OrderedDict()
d['a'] = 1
d['b'] = 2
d['c'] = 3
for key, value in d.items():
print key, value
Output:
a 1
b 2
c 3
how to iterate from end to beginning over an OrderedDict ?
Either:
z = OrderedDict( ... )
for item in z.items()[::-1]:
# operate on item
Or:
z = OrderedDict( ... )
for item in reversed(z.items()):
# operate on item
You can iterate using enumerate and iteritems:
dict = OrderedDict()
# ...
for i, (key, value) in enumerate(dict.iteritems()):
# Do what you want here
For Python 3.x
d = OrderedDict( ... )
for key, value in d.items():
print(key, value)
For Python 2.x
d = OrderedDict( ... )
for key, value in d.iteritems():
print key, value
Note that, as noted in the comments by adsmith, this is probably an instance of an XY Problem and you should reconsider your data structures.
Having said that, if you need to operate only on last three elements, then you don't need to iterate. For example:
MergeInfo = namedtuple('MergeInfo', ['sum', 'toMerge1', 'toMerge2', 'toCopy'])
def mergeLastThree(letters):
if len(letters) < 3:
return False
last = letters.popitem()
last_1 = letters.popitem()
last_2 = letters.popitem()
sum01 = MergeInfo(int(last[1]) + int(last_1[1]), last, last_1, last_2)
sum12 = MergeInfo(int(last_1[1]) + int(last_2[1]), last_1, last_2, last)
sum02 = MergeInfo(int(last[1]) + int(last_2[1]), last, last_2, last_1)
mergeInfo = min((sum01, sum12, sum02), key = lambda s: s.sum)
merged = ((mergeInfo.toMerge1[0], mergeInfo.toMerge2[0]), str(mergeInfo.sum))
letters[merged[0]] = merged[1]
letters[mergeInfo.toCopy[0]] = mergeInfo.toCopy[1]
return True
Then having:
letters = OrderedDict([('r', 1), ('s', 1), ('a', 1), ('n', 1), ('y', 1)])
print letters
mergeLastThree(letters)
print letters
mergeLastThree(letters)
print letters
Produces:
>>> OrderedDict([('r', 1), ('s', 1), ('a', 1), ('n', 1), ('y', 1)])
OrderedDict([('r', 1), ('s', 1), (('y', 'n'), '2'), ('a', 1)])
OrderedDict([('r', 1), (('a', 's'), '2'), (('y', 'n'), '2')])
And to merge the whole structure completely you need to just:
print letters
while mergeLastThree(letters):
pass
print letters
Which gives:
>>> OrderedDict([('r', 1), ('s', 1), ('a', 1), ('n', 1), ('y', 1)])
OrderedDict([((('a', 's'), 'r'), '3'), (('y', 'n'), '2')])
>>>
(If you have a better title, do edit, I couldn't explain it properly! :)
So this is my code:
with open('cipher.txt') as f:
f = f.read().replace(' ', '')
new = []
let = []
for i in f:
let.append(i)
if i.count(i) > 1:
i.count(i) == 1
else:
new = sorted([i + ' ' + str(f.count(i)) for i in f])
for o in new:
print(o)
And this is cipher.txt:
xli uymgo fvsar jsb
I'm supposed to print out the letters used and how many times they are used, my code works, but I need it alphabetical, I tried putting them in a list list(a) and then sorting them, but i didn't quite get it, any ideas? Thanks in advance!
Whenever dealing with counting, you can use collections.Counter here:
>>> from collections import Counter
>>> print sorted(Counter('xli uymgo fvsar jsb'.replace(' ', '')).most_common())
[('a', 1), ('b', 1), ('f', 1), ('g', 1), ('i', 1), ('j', 1), ('l', 1), ('m', 1), ('o', 1), ('r', 1), ('s', 2), ('u', 1), ('v', 1), ('x', 1), ('y', 1)]
If you can't import any modules, then you can append a to a list and then sort it:
new = []
for i in f:
new.append(i + ' ' + str(f.count(i)) # Note that i is a string, so str() is unnecessary
Or, using a list comprehension:
new = [i + ' ' + str(f.count(i)) for i in f]
Finally, to sort it, just put sorted() around it. No extra parameters are needed because your outcome is alphabetical :).
Here's a oneliner without imports:
{s[i]: n for i, n in enumerate(map(s.count, s))}
And in alphabetical order (if the above is d):
for k in sorted(d): print k, d[k]
Or another version (oneliner alphabetical):
sorted(set([(s[i], n) for i, n in enumerate(map(s.count, s))]))
Following is my coding for count letters and i need the output as
[('e', 1), ('g', 2), ('l', 1), ('o', 2)]
and my out put is
[('e', 1), ('g', 2), ('g', 2), ('l', 1), ('o', 2), ('o', 2)]
This is my code
def countLetters(word):
word=list(word)
word.sort()
trans=[]
for j in word:
row=[]
a=word.count(j)
row.append(j)
row.append(a)
trans.append(tuple(row))
return trans
can anyone explain me, how to get the expected output with my code?
Thank you
Why not just use a Counter?
Example:
from collections import Counter
c = Counter("Foobar")
print sorted(c.items())
Output:
[('F', 1), ('a', 1), ('b', 1), ('o', 2), ('r', 1)]
Another way is to use a dict, or better, a defaultdict (when running python 2.6 or lower, since Counter was added in Python 2.7)
Example:
from collections import defaultdict
def countLetters(word):
d = defaultdict(lambda: 0)
for j in word:
d[j] += 1
return sorted(d.items())
print countLetters("Foobar")
Output:
[('F', 1), ('a', 1), ('b', 1), ('o', 2), ('r', 1)]
Or use a simple list comprehension
word = "Foobar"
print sorted((letter, word.count(letter)) for letter in set(word))
>>> from collections import Counter
>>> Counter('google')
Counter({'o': 2, 'g': 2, 'e': 1, 'l': 1})
>>> from operator import itemgetter
>>> sorted(Counter('google').items(), key=itemgetter(0))
[('e', 1), ('g', 2), ('l', 1), ('o', 2)]
>>>
Actually, there is no need for key:
>>> sorted(Counter('google').items())
[('e', 1), ('g', 2), ('l', 1), ('o', 2)]
As tuples are sorted first by the first item, then by the second, etc.
def countLetters(word):
k=[]
Listing=[]
Cororo=[]
for warm in word:
if warm not in k:
k.append(warm)
for cold in range(len(k)):
word.count(k[cold])
Listing.append(word.count(k[cold]))
Cororo.append((k[cold],Listing[cold]))
return sorted(Cororo)
This is a bit of an old fashion way of doing this since you can use the counter module like the guy above me and make life easier.
You can modify your code like this (Python 2.5+):
def countLetters(word):
word=list(word)
word.sort()
trans=[]
for j in word:
row=[]
a=word.count(j)
row.append(j)
row.append(a)
trans.append(tuple(row))
ans = list(set(trans))
ans.sort()
return ans
The problem is you're not accounting for the duplicate occurrence of the letters in your j loop
I think a quick fix will be to modify the iteration as for j in set(word).
This ensures each letter is iterated once.
trans = list(set(trans))
Converting a list to a set removes duplicates (which I think is what you want to do).