Checking which key has the most letters in its dictionary in Python - python

I have a dictionary in a Python code like this:
S = {(x0): 'omicron', (x1): 'a', (x2): 'ab', (x3): 'abbr', (x4): 'abr', (x5): 'abrf', (x6): 'abrfa', (x7): 'af', '(x8)': 'afc'}
I would like to check which key has its corresponding dictionary with the highest numer of letters, except for the one that has 'omicron'. The answer in this example should be: (x6), because it has a dictionary with 5 letters, more than any other key, and not counting (x0):'omicron'.
Is there an efficient way to do this? Thank you.

You could use the key parameter of max:
res = max(S, key=lambda x: (S[x] != 'omicron', len(S[x])))
print(res)
Output
(x6)
This will make the keys that the value is different than 'omicron' have a higher value than one that are equals (1 > 0). For those keys that do not have 'omicron' value use the length as a tie-breaker.

S = {('x0'): 'omicron', ('x1'): 'a', ('x2'): 'ab', ('x3'): 'abbr', ('x4'): 'abr', ('x5'): 'abrf', ('x6'): 'abrfa', ('x7'): 'af', ('x8'): 'afc'}
keys = list(S.keys())
longest = 0
word = ''
for i in range(len(keys)):
if len(S[f'{keys[i]}']) > longest and S[f'{keys[i]}'] != 'omicron':
longest = len(S[f'{keys[i]}'])
word = keys[i]
print(longest, word)
Output:
5 x6

Related

Problem with retrieving the value of item in list/dictionary of objects in Python3

I'm trying to put string variables into list/dictionary in python3.7 and trying to retrieve them later for use.
I know that I can create a dictionary like:
string_dict1 = {"A":"A", "B":"B", "C":"C", "D":"D", "E":"E", "F":"F"}
and then retrieve the values, but it is not I want in this specific case.
Here is the code:
A = ""
B = "ABD"
C = ""
D = "sddd"
E = ""
F = "dsas"
string_dict = {A:"A", B:"B", C:"C", D:"D", E:"E", F:"F"}
string_list = [A,B,C,D,E,F]
for key,val in string_dict.items():
if key == "":
print(val)
for item in string_list:
if item == "":
print(string_list.index(item))
The result I got is:
E
0
0
0
And the result I want is:
A
C
E
0
2
4
If you print string_dict you notice the problem:
string_dict = {A:"A", B:"B", C:"C", D:"D", E:"E", F:"F"}
print(string_dict)
# output: {'': 'E', 'ABD': 'B', 'sddd': 'D', 'dsas': 'F'}
It contains a single entry with the value "".
This is because you are associating multiple values ​​to the same key, and this is not possible in python, so only the last assignment is valid (in this case E:"E").
If you want to associate multiple values ​​with the same key, you could associate a list:
string_dict = {A:["A","C","E"], B:"B", D:"D", F:"F"}
Regarding the list of strings string_list, you get 0 since the method .index(item) returns the index of the first occurrence of item in the list. In your case 0. For example, if you change the list [A,B,C,D,E,F] to [B,B,C,D,E,F]. Your code will print 2.
If you want to print the index of the empty string in your list:
for index, value in enumerate(string_list):
if value == '':
print(index)
Or in a more elegant way you can use a list comprehension:
[i for i,x in enumerate(string_list) if x=='']
Well, I don't think there's a way to get what you want from a dictionary because of how they work. You can print your dictionary and see that it looks like this:
{'': 'E', 'ABD': 'B', 'sddd': 'D', 'dsas': 'F'}
What happened here is A was overwritten by C and then E.
But I played around with the list and here's how I got the last three digits right:
for item in string_list:
if item != '':
print(string_list.index(item) - 1)
This prints:
0
2
4

how to manipulate string on the basis of occurrence of characters and index of character. ex: 'tree' to 'eert'

"tree" to "eert" as 'e' occured twice and among 'r' and 't', as 'r' is of higher index so that will come first.
Was able to get the occurence of each character and clubbed same occurance characters together
def stringFunction(mystr):
mydict = {}
for i in range(len(mystr)):
if mystr[i] in mydict:
mydict[mystr[i]] = mydict.get(mystr[i]) + 1
else:
mydict[mystr[i]] = 1
print(mydict)
print(set(sorted(mydict.values())))
final_list = []
for each in set(sorted(mydict.values())):
print(each)
listOfKeys = []
listOfItems = mydict.items()
for item in listOfItems:
if item[1] == each:
listOfKeys.append(item[0])
print(listOfKeys)
Output of above code was
{'r': 1, 'e': 2, 't': 1}
set([1, 2])
1
['r', 't']
2
['e']
Expected result = "eert"
save the word, frequency of word and rank/index of the word in a list. then sort the list by the order first frequency and then the index value (in solution i didn't reverse it). once result is get, get the character from the last element to first element (if not reversed , else if reverse then get it from first element to last element).
def func(st):
#storing word , word count , word index in a tuple and
# then stroing this all in a list
l =[(i,st.count(i),st.index(i)) for i in set(st)]
# sort the list in reverse order on the base of frequency of word
# and then index value of word i
l.sort(key=lambda x:[x[1],x[2]],reverse=True)
# finally joining the word and no of times it come ie if p come 2 time
# it become 'pp' and append to final word
return ''.join([i[0]*i[1] for i in l])
print(func("apple")) # ppela
print(func("deer")) # eerd
print(func("tree")) # eert
this may work:
from collections import Counter
def stringFunction(mystr):
return "".join(n * char for n, char in Counter(reversed(mystr)).most_common())
print(stringFunction("apple")) # ppela
print(stringFunction("deer")) # eerd
print(stringFunction("tree")) # eert
where collections.Counter is used to count the number of occurrences of the letters and the reverseing takes care of the order of the letter that occur the same amount of times.
if you really want to avoid imports you could do this (this will only generate the correct order in python >= 3.5):
def stringFunction(mystr):
counter = {}
for char in reversed(mystr):
counter[char] = counter.get(char, 0) + 1
ret = "".join(
n * char
for char, n in sorted(counter.items(), key=lambda x: x[1], reverse=True)
)
return ret

How to identify matching values in dictionary and create a new string with only those keys?

I have a method that pulls repeating letters from a string and adds them to a dictionary with the amount of times they repeat as the values. Now what I would like to do is pull all the keys that have matching values and create a string with only those keys.
example:
text = "theerrrdd"
count = {}
same_value = ""
for ch in text:
if text.count(ch) > 1:
count[ch] = text.count(ch)
How can I check count for keys with matching values, and if found, add those keys to same_value?
So in this example "e" and "d" would both have a value of 2. I want to add them to same_value so that when called, same_value would return "ed".
I basically just want to be able to identify which letters repeated the same amount of time.
First create a letter to count mapping, then reverse this mapping. Using the collections module:
from collections import defaultdict, Counter
text = 'theerrrdd'
# create dictionary mapping letter to count
letter_count = Counter(text)
# reverse mapping to give count to letters mapping
count_letters = defaultdict(list)
for letter, count in letter_count.items():
count_letters[count].append(letter)
Result:
print(count_letters)
defaultdict(<class 'list'>, {1: ['t', 'h'],
2: ['e', 'd'],
3: ['r']})
Then, for example, count_letters[2] gives you all letters which are seen twice in your input string.
Using str.count in a loop is inefficient as it requires a full iteration of your string for each letter. In other words, such an algorithm has quadratic complexity, while collections.Counter has linear complexity.
Another approach would be to use set() to get just the unique characters in the string, loop through the set and create a dict where the counts are the keys with lists of characters for each count. Then you can generate strings for each count using join().
text = "theerrrdd"
chars = set(text)
counts = {}
for ch in chars:
ch_count = text.count(ch)
if counts.get(ch_count, None):
counts[ch_count].append(ch)
else:
counts[ch_count] = [ch]
# print string of chars where count is 2
print(''.join(counts[2]))
# OUTPUT
# ed
I think the most simple solution of all !!
from collections import Counter
text = "theerrrdd"
count = Counter(text)
same_value = ''.join([k for k in count.keys() if count[k] > 1])
print(count)
print(same_value)
From counter dictionary, create another dictionary with all same count letters as values and the count as key. Iterate through values of this newly created dictionary to find all values whose length is greater than 1 and then form strings:
from collections import defaultdict
text = "theerrrdd"
count = {}
new_dict = defaultdict(list)
for ch in text:
if text.count(ch) > 1:
count[ch] = text.count(ch)
for k, v in count.items():
new_dict[v].append(k)
same_values_list = [v for v in new_dict.values() if len(v) > 1]
for x in same_values_list:
print(''.join(x))
# ed
new_dict is the newly created dictionary with count as key and all letters with that count as the value for that key:
print(new_dict)
# defaultdict(<class 'list'>, {2: ['e', 'd'],
# 3: ['r']})

Adding certain lengthy elements to a list

I'm doing a project for my school and for now I have the following code:
def conjunto_palavras_para_cadeia1(conjunto):
acc = []
conjunto = sorted(conjunto, key=lambda x: (len(x), x))
def by_size(words, size):
result = []
for word in words:
if len(word) == size:
result.append(word)
return result
for i in range(0, len(conjunto)):
if i > 0:
acc.append(("{} ->".format(i)))
acc.append(by_size(conjunto, i))
acc = ('[%s]' % ', '.join(map(str, acc)))
print( acc.replace(",", "") and acc.replace("'", "") )
conjunto_palavras_para_cadeia1(c)
I have this list: c = ['A', 'E', 'LA', 'ELA'] and what I want is to return a string where the words go from the smallest one to the biggest on in terms of length, and in between they are organized alphabetically. I'm not being able to do that...
OUTPUT: [;1 ->, [A, E], ;2 ->, [LA], ;3 ->, [ELA]]
WANTED OUTPUT: ’[1->[A, E];2->[LA];3->[ELA]]’
Taking a look at your program, the only issue appears to be when you are formatting your output for display. Note that you can use str.format to insert lists into strings, something like this:
'{}->{}'.format(i, sublist)
Here's my crack at your problem, using sorted + itertools.groupby.
from itertools import groupby
r = []
for i, g in groupby(sorted(c, key=len), key=len):
r.append('{}->{}'.format(i, sorted(g)).replace("'", ''))
print('[{}]'.format(';'.join(r)))
[1->[A, E];2->[LA];3->[ELA]]
A breakdown of the algorithm stepwise is as follows -
sort elements by length
group consecutive elements by length
for each group, sort sub-lists alphabetically, and then format them as strings
at the end, join each group string and surround with square brackets []
Shortest solution (with using of pure python):
c = ['A', 'E', 'LA', 'ELA']
result = {}
for item in c:
result[len(item)] = [item] if len(item) not in result else result[len(item)] + [item]
str_result = ', '.join(['{0} -> {1}'.format(res, sorted(result[res])) for res in result])
I will explain:
We are getting items one by one in loop. And we adding them to dictionary by generating lists with index of word length.
We have in result:
{1: ['A', 'E'], 2: ['LA'], 3: ['ELA']}
And in str_result:
1 -> ['A', 'E'], 2 -> ['LA'], 3 -> ['ELA']
Should you have questions - ask

Sorting string values according to a custom alphabet in Python

I am looking for an efficient way to sort a list of strings according a custom alphabet.
For example, I have a string alphabet which is "bafmxpzv" and a list of strings composed from only the characters contained in that alphabet.
I would like a way to sort that list similarly to other common sorts, but using this custom alphabet. How can I do that?
Let's create an alphabet and a list of words:
In [32]: alphabet = "bafmxpzv"
In [33]: a = ['af', 'ax', 'am', 'ab', 'zvpmf']
Now let's sort them according to where the letters appear in alphabet:
In [34]: sorted(a, key=lambda word: [alphabet.index(c) for c in word])
Out[34]: ['ab', 'af', 'am', 'ax', 'zvpmf']
The above sorts in the correct order.
sorted enables a wide range of custom sorting. The sorted function has three optional arguments: cmp, key, and reverse:
cmp is good for complex sorting tasks. If specified, cmp should be a functionIt that takes two arguments. It should return a negative, zero or positive number depending on whether the first argument is considered smaller than, equal to, or larger than the second argument. For this case, cmp is overkill.
key, if spedified, should be a function that takes one argument and returns something that python knows natively how to sort. In this case, key returns a list of the indices of each of the word's characters in the alphabet.
In this case, key returns the index of a letter in alphabet.
reverse, if true, reverses the sort-order.
A nonworking alternative
From the comments, this alternative form was mentioned:
In [35]: sorted(a, key=lambda word: [alphabet.index(c) for c in word[0]])
Out[35]: ['af', 'ax', 'am', 'ab', 'zvpmf']
Note that this does not sort in the correct order. That is because the key function here only considers the first letter of each word. This can be demonstrated by testing key:
In [2]: key=lambda word: [alphabet.index(c) for c in word[0]]
In [3]: key('af')
Out[3]: [1]
In [4]: key('ax')
Out[4]: [1]
Observe that key returns the same value for two different strings, af and ax. The value returned reflects only the first character of each word. Because of this, sorted has no way of determining that af belongs before ax.
Update, I misread your question, you have a list of strings, not a single string, here's how to do it, the idea is the same, use a sort based on a custom comparison function:
def acmp (a,b):
la = len(a)
lb = len(b)
lm = min(la,lb)
p = 0
while p < lm:
pa = alphabet.index(a[p])
pb = alphabet.index(b[p])
if pa > pb:
return 1
if pb > pa:
return -1
p = p + 1
if la > lb:
return 1
if lb > la:
return -1
return 0
mylist = ['baf', 'bam', 'pxm']
mylist.sort(cmp = acmp)
Instead of using index() which requires finding the index of a char, a better alternative consists in building a hash map to be used in the sorting, in order to retrieve the index directly.
Example:
>>> alphabet = "bafmxpzv"
>>> a = ['af', 'ax', 'am', 'ab', 'zvpmf']
>>> order = dict(zip(alphabet, range(len(alphabet))))
>>> sorted(a, key=lambda word: [order[c] for c in word])
['ab', 'af', 'am', 'ax', 'zvpmf']

Categories

Resources