How to print the longest dictionary value? - python

I have a dictionary whose values are all lists of strings and I want to print the longest value(in this case, the list with the most strings). I created this for loop:
count=0
for values in d.values():
if len(values)>count:
count=len(values)
print(values)
However, this prints all of the values ever associated with 'count'. I only want the largest one (which is the last line). This is an example of what the for loop prints:
['gul', 'lug']
['tawsed', 'wadset', 'wasted']
['lameness', 'maleness', 'maneless', 'nameless', 'salesmen']
['pores', 'poser', 'prose', 'repos', 'ropes', 'spore']
['arrest', 'rarest', 'raster', 'raters', 'starer', 'tarres', 'terras']
['carets', 'cartes', 'caster', 'caters', 'crates', 'reacts', 'recast', 'traces']
['estrin', 'inerts', 'insert', 'inters', 'niters', 'nitres', 'sinter', 'triens', 'trines']
['least', 'setal', 'slate', 'stale', 'steal', 'stela', 'taels', 'tales', 'teals', 'tesla']
['apers', 'apres', 'asper', 'pares', 'parse', 'pears', 'prase', 'presa', 'rapes', 'reaps', 'spare', 'spear']
How can I get it to print only that last(longest) line?

max(d.values(), key=len)
This prints out the longest list of words from your dict values. I used the max() function, which takes a key parameter that is assigned to the function len(in this case). Basically, the criteria for which value is the 'max' value is now decided by it's len.

Inspired by Dilbert there is a chance for simplification, no need to use lambda to define function for comparing values, we may take advantage of the fact, that len returns length of each item and this is perfect key for deciding who comes first and who is last:
print sorted(d.values(), key=len)[-1]

count = 0
for values in d.values():
if len(values) > count:
values_with_largest_count_first_hit = values
print(values_with_largest_count_first_hit)

print sorted(d.values(), cmp = lambda x, y: cmp(len(x), len(y)))[-1]

Related

Can Python sorting with a key pass me the ordinal position of the item in the original list, instead of the item itself

I have a list of items I need to sort but the the value I want used in the sort for each item is not in the list itself. The sorting information is in another list, which positionally aligns with the first one.
Ie., l = list of items to sort, v = list of values to use for sorting. When sorting l[0], the value in v[0] should be used.
So during the sort, I need python to tell me the ordinal position of the item being sorted, instead of giving the item itself.
So effectively what I would do is this:
l = sort(key = lambda index_of_item: v[index_of_item])
By default I think that this would not work as python is invoking that lambda with an actual item from l, not the item's position. Is there a way to have python give me the position instead?
(If there were some identifier in each item being sorted I could use that myself inside the lambda to extrapolate the index_of_item, but sadly there isn't)
Convert your list of items to a list of tuples that includes the original index; this can be done using enumerate(). Then you can use that index to access the other list.
augumented_list = list(enumerate(l))
augmented_list.sort(key = lambda item: v[item[0]])
result = [x[1] for x in augmented_list]
Another option is to use zip() to combine the elements of both lists, then use the value from the other list as the sort key.
result = [x[0] for x in sorted(zip(l, v), key = lambda x: x[1])]

I'm having trouble with figuring out how the following code works?

Could someone please explain why ref_len = 9 after it runs, and how the second line in the code shown below works?
ref_len_list = [9,9,5,9]
ref_len = min(ref_len_list, key=lambda x:abs(x-8))
The line:
ref_len = min(ref_len_list, key=lambda x:abs(x-8))
will look for the number in ref_len_list for which abs(number - 8) has the lowest value, and thus is the value closest to 8. From this list it gets the number 9, because abs(9-8) < abs(5-8). If there would be both 9s and 7s in this list, it would just give the first one of those.
So:
min([9,9,5,9], key=lambda x:abs(x-8)) # --> 9
min([7,9,5,6], key=lambda x:abs(x-8)) # --> 7
min([9,7,5,6], key=lambda x:abs(x-8)) # --> 9
min([7,9,5,8], key=lambda x:abs(x-8)) # --> 8
The line works by using the min function and passing the optional key argument to it. The key argument will specify for the function what criteria it should use when ranking the elements of the list.
In this case the key argument is given an anonymous lambda function which will take a number x as an argument and return abs(x-8).
The function lambda x:abs(x-8)) can be re-written as follows:
def func(x):
return abs(x-8)
The second line of code, ref_len = min(ref_len_list, key=lambda x:abs(x-8)) simply looks at the first line of code, ref_len_list = [9,9,5,9] and finds the value closest to 8. It just picks an item from the list that satisfies the code.
min picks the minimum value from the list. If given no key argument, it just uses the values themselves to determine what the "minimum" is (i.e. from a list of numbers it's somewhat obvious what the minimum is). Given a key argument, it uses that function to get the value for each item in the list that it should consider. It's typically mean for cases like this:
[{'foo': 3, 'bar': 'baz'}, {'foo': 4}]
min can't just know what value it should use here, so you'd do min(lst, key=lambda i: i['foo']), which returns {'foo': 3, 'bar': 'baz'}, since it has the lowest value for i['foo'] (3). But key doesn't have to get a key from a dict, it can return any value it wants. Here it returns abs(x - 8), so the result is the number whose value is the smallest when subtracted from 8.

in python, how I append the index of a certain string in a list to another list if there are duplicate entries in the first list?

Say I have a list K, and a list B. If an entry in K fulfills my condition x, I want the index of that entry in my list B. The problem is since there are duplicate entries in the first list, using k.index only gives me the index of the first occurrence in that list. Here's what I have:
for i in k:
if i = x:
b.append(k.index(i))
Here is a simple solution:
for n, item in enumerate(k):
if item == x:
b.append(n)
The built-in enumerate function returns an index value for the iterations starting at 0 just like a list index
This can be done using the built-in enumerate function instead of list.index:
Return an enumerate object. iterable must be a sequence, an iterator, or some other object which supports iteration. The __next__() method of the iterator returned by enumerate() returns a tuple containing a count (from start which defaults to 0) and the values obtained from iterating over iterable.
for idx, i in enumerate(k):
if i == x:
b.append(idx)

Dictionary with lists as values - find longest list

I have a dictionary where the values are lists. I need to find which key has the longest list as value, after removing the duplicates. If i just find the longest list this won't work as there may be a lot of duplicates. I have tried several things, but nothing is remotely close to being correct.
d = # your dictionary of lists
max_key = max(d, key= lambda x: len(set(d[x])))
# here's the short version. I'll explain....
max( # the function that grabs the biggest value
d, # this is the dictionary, it iterates through and grabs each key...
key = # this overrides the default behavior of max
lambda x: # defines a lambda to handle new behavior for max
len( # the length of...
set( # the set containing (sets have no duplicates)
d[x] # the list defined by key `x`
)
)
)
Since the code for max iterates through the dictionaries' keys (that's what a dictionary iterates through, by the by. for x in dict: print x will print each key in dict) it will return the key that it finds to have the highest result when it applies the function we built (that's what the lambda does) for key=. You could literally do ANYTHING here, that's the beauty of it. However, if you wanted the key AND the value, you might be able to do something like this....
d = # your dictionary
max_key, max_value = max(d.items(), key = lambda k,v: len(set(v)))
# THIS DOESN'T WORK, SEE MY NOTE AT BOTTOM
This differs because instead of passing d, which is a dictionary, we pass d.items(), which is a list of tuples built from d's keys and values. As example:
d = {"foo":"bar", "spam":['green','eggs','and','ham']}
print(d.items())
# [ ("foo", "bar"),
# ("spam", ["green","eggs","and","ham"])]
We're not looking at a dictionary anymore, but all the data is still there! It makes it easier to deal with using the unpack statement I used: max_key, max_value =. This works the same way as if you did WIDTH, HEIGHT = 1024, 768. max still works as usual, it iterates through the new list we built with d.items() and passes those values to its key function (the lambda k,v: len(set(v))). You'll also notice we don't have to do len(set(d[k])) but instead are operating directly on v, that's because d.items() has already created the d[k] value, and using lambda k,v is using that same unpack statement to assign the key to k and the value to v.
Magic! Magic that doesn't work, apparently. I didn't dig deep enough here, and lambdas cannot, in fact, unpack values on their own. Instead, do:
max_key, max_value = max(d.items(), key = lambda x: len(set(x[1])))
for less advanced user this can be a solution:
longest = max(len(item) for item in your_dict.values())
result = [item for item in your_dict.values() if len(item) == longest]

Max Value within a List of Lists of Tuple

I have a problem to get the highest Value in a dynamic List of Lists of Tuples.
The List can looks like this:
adymlist = [[('name1',1)],[('name2',2),('name3',1), ...('name10', 20)], ...,[('name m',int),..]]
Now I loop through the List to get the highest Value (integer):
total = {}
y=0
while y < len(adymlist):
if len(adymlist) == 1:
#has the List only 1 Element -> save it in total
total[adymlist[y][0][0]] = adymlist[y][0][1]
y += 1
else:
# here is the problem
# iterate through each lists to get the highest Value
# and you dont know how long this list can be
# safe the highest Value in total f.e. total = {'name1':1,'name10':20, ..}
I tried a lot to get the maximum Value but I found no conclusion to my problem. I know i must loop through each Tuple in the List and compare it with the next one but it dont know how to code it correct.
Also I can use the function max() but it doesnt work with strings and integers. f.e.
a = [ ('a',5),('z',1)] -> result is max(a) ---> ('z',1) obv 5 > 1 but z > a so I tried to expand the max function with max(a, key=int) but I get an Type Error.
Hope you can understand what I want ;-)
UPDATE
Thanks so far.
If I use itertools.chain(*adymlist) and max(flatlist, key=lambda x: x[1])
I will get an exception like : max_word = max(flatlist, key=lambda x: x[1])
TypeError: 'int' object is unsubscriptable
BUT If I use itertools.chain(adymlist) it works fine. But I dont know how to summate all integers from each Tuple of the List. I need your help to figure it out.
Otherwise I wrote a workaround for itertools.chain(*adymlist) to get the sum of all integers and the highest integer in that list.
chain = itertools.chain(*adymlist)
flatlist = list(chain)
# flatlist = string, integer, string, integer, ...
max_count = max(flatlist[1:len(flatlist):2])
total_count = sum(flatlist[1:len(flatlist):2])
# index of highest integer
idx = flatlist.index(next((n for n in flatlist if n == max_count)))
max_keyword = flatlist[idx-1]
It still does what I want, but isn't it to dirty?
To clarify, looks like you've got a list of lists of tuples. It doesn't look like we care about what list they are in, so we can simplify this to two steps
Flatten the list of lists to a list of tuples
Find the max value
The first part can be accomplished via itertools.chain (see e.g., Flattening a shallow list in Python)
The second can be solved through max, you have the right idea, but you should be passing in a function rather than the type you want. This function needs to return the value you've keyed on, in this case ,the second part of the tuple
max(flatlist, key=lambda x: x[1])
Correction
I re-read your question - are you looking for the max value in each sub-list? If this is the case, then only the second part is applicable. Simply iterate over your list for each list
A bit more pythonic than what you currently have would like
output = []
for lst in lists:
output.append( max(flatlist, key=lambda x: x[1]) )
or
map(lambda x: max(x, key=lambda y: y[1]) , lists)
As spintheblack says, you have a list of lists of tuples. I presume you are looking for the highest integer value of all tuples.
You can iterate over the outer list, then over the list of tuples tuples like this:
max_so_far = 0
for list in adymlist:
for t in list:
if t[1] > max_so_far:
max_so_far = t[1]
print max_so_far
This is a little bit more verbose but might be easier to understand.

Categories