Iterating through a dictionary for X number of times - python

Assume the dictionary contains more than 10 key-value pairs. The dictionary ought to be sorted by values (of integers). Print out the top 10 values (and corresponding keys). I think there is a better solution that what I have given here.
for keys in sorted(x):
c=c+1
if c>10:
break
else:
print keys, x['keys']

for key in sorted(x, key=x.get, reverse=True)[:10]:
print key, x[key]
For really large dict you should consider using a heapq
from heapq import nlargest
for key in nlargest(10, x, key=x.get):
print key, x[key]

There is no order defined on dictionary keys, so the "first" keys are not well defined. Specifically, what you did is easier done with x.keys()[:10].

topten = sorted(x.items(), key=lambda x:-x[1])[:10]

You can iterate over dict for X number of times using the following code.
Python 3.8
def highest_contributor(self, top=1):
slice_dict_only_to_keys = list(self.contributors.keys())[:top]
for _key in slice_dict_only_to_keys:
self.log("Top Contributor: {} ({})".format(_key, self.contributors[_key]))
Don't worry about integers and incrementing them with your code. You don't need them.
Simple, readable and Maintainable.

Related

Python dictionary comprehension to group together equal keys

I have a code snippit that groups together equal keys from a list of dicts and adds the dict with equal ObjectID to a list under that key.
Code bellow works, but I am trying to convert it to a Dictionary comprehension
group togheter subblocks if they have equal ObjectID
output = {}
subblkDBF : list[dict]
for row in subblkDBF:
if row["OBJECTID"] not in output:
output[row["OBJECTID"]] = []
output[row["OBJECTID"]].append(row)
Using a comprehension is possible, but likely inefficient in this case, since you need to (a) check if a key is in the dictionary at every iteration, and (b) append to, rather than set the value. You can, however, eliminate some of the boilerplate using collections.defaultdict:
output = defaultdict(list)
for row in subblkDBF:
output[row['OBJECTID']].append(row)
The problem with using a comprehension is that if really want a one-liner, you have to nest a list comprehension that traverses the entire list multiple times (once for each key):
{k: [d for d in subblkDBF if d['OBJECTID'] == k] for k in set(d['OBJECTID'] for d in subblkDBF)}
Iterating over subblkDBF in both the inner and outer loop leads to O(n^2) complexity, which is pointless, especially given how illegible the result is.
As the other answer shows, these problems go away if you're willing to sort the list first, or better yet, if it is already sorted.
If rows are sorted by Object ID (or all rows with equal Object ID are at least next to each other, no matter the overall order of those IDs) you could write a neat dict comprehension using itertools.groupby:
from itertools import groupby
from operator import itemgetter
output = {k: list(g) for k, g in groupby(subblkDBF, key=itemgetter("OBJECTID"))}
However, if this is not the case, you'd have to sort by the same key first, making this a lot less neat, and less efficient than above or the loop (O(nlogn) instead of O(n)).
key = itemgetter("OBJECTID")
output = {k: list(g) for k, g in groupby(sorted(subblkDBF, key=key), key=key)}
You can adding an else block to safe on time n slightly improve perfomrance a little:
output = {}
subblkDBF : list[dict]
for row in subblkDBF:
if row["OBJECTID"] not in output:
output[row["OBJECTID"]] = [row]
else:
output[row["OBJECTID"]].append(row)

Can't seem to iterate over a sorted dictionary where the keys are number strings. How do you sort a dictionary to iterate?

I have this dictionary (dic) where the keys are strings, but the strings are actually just numbers.
I can't find a way to iterate over the sorted string (since sorting the dictionary will not sort numerically)
for j in sorted([int(k) for k in dic.iteritems()]):
print dic[str(j)] #converting the integer back into a string for the key
it gives me
KeyError
Intuitively this should work, but I just dont get why it doesn't.
dict.iteritems() returns 2-tuples, which cannot be converted into ints.
for j in sorted(dic, key=int):
print dic[j]
Apart from using key=int you could also slightly modify your existing comprehension:
for _, value in sorted((int(key), dic[key]) for key in dic):
print(value)
it's not as nice but it's an alternative if you want to unpack not only your keys but also your values.
With iteritems you need an additional unpacking in the comprehension:
for _, value in sorted((int(key), value) for key, value in dic.iteritems()):
print(value)

Iterating over a python dictionary?

I have a dictionary where the keys are integers and the values are strings. The dictionary has been sorted using key values.
I need to copy the corresponding string values (keeping the sorted order) to a list. I cannot figure out how to iterate over the dictionary.
I know the number of key-value pairs in the dictionary (let it be 'n').
Some_ordered_dict
resultant_list=[]
for i in range(n):
resultant_list.append(Some_ordered_dict[increment-key?]
The dictionary was sorted using OrderedDict from some dictionary 'dic' as follows;
od=collections.OrderedDict(sorted(dic.items()))
The essential point is that I have to display the strings values of the dictionary in the same order as they appear in the sorted dictionary.
resultant_list = [d[k] for k in sorted(d)]
The standard Python dictionary does not guarantee that items in a dictionary will be kept in any order. Next thing is that you have to iterate using a "for in" statement like such:
Some_ordered_dict
resultant_list=[]
for i in Some_ordered_dict:
resultant_list.append(Some_ordered_dict[i])
You should take a look at the ordered dict collection to ensure that the items on your dict are kept in the order that you expect.
Using the standard unordered dictionary in python you could use something like this:
resultant_list = []
for i in sorted(dict.keys()):
resultant_list.append(dict[i])
As mentioned in other posts, dictionaries do not guarantee order. One way to get a sorted list would be to created a list of tuples out of your dict's (key, value) pairs, then sort this list based n the first element(the key), as follows:
my_dict = {2: 'two', 3: 'three', 1: 'one'}
my_tuple_list = list(zip(my_dict.keys(), my_dict.values()))
my_sorted_list = sorted(my_tuple_list, key = lambda item: item[0])
resultant_list = [x[1] for x in my_sorted_list]

sort dictionary of objects

I have a dictionary of objects where the key is a simple string, and the value is a data object with a few attributes. I'd like to sort my dictionary based on an attribute in the values of the dictionary. i have used this to sort based on the dictionaries values
sorted = dict.values()
sorted.sort(key = operator.attrgetter('total'), reverse=True)
This yields a sorted list of values (which is expected) and I lose my original keys from the dictionary (naturally). I would like to sort both the keys and values together... how can I achieve this? Any help would be greatly appreciated?
Use .items() (or its iterator version iteritems) instead of .values() to get a list of (key, value) tuples.
items = sorted(dct.iteritems(), key=lambda x: x[1].total, reverse=True)
You'll want to use .items() rather than .values(), for example:
def keyFromItem(func):
return lambda item: func(*item)
sorted(
dict.items(),
key=keyFromItem( lambda k,v: (v['total'], k) )
)
The above will sort first based on total, and for items with equal total, will sort them alphabetically by key. It will return items as (key,value) pairs, which you could just do [x[1] for x in sorted(...)] to get the values.
Use items instead of values - and a just use a lambda to fecth the sorting key itself, since there won't be a ready made operator for it:
sorted = dict.items()
sorted.sort(key = lambda item: item[1].total, reverse=True)

Correspendence between list indices originated from dictionary

I wrote the below code working with dictionary and list:
d = computeRanks() # dictionary of id : interestRank pairs
lst = list(d) # tuples (id, interestRank)
interestingIds = []
for i in range(20): # choice randomly 20 highly ranked ids
choice = randomWeightedChoice(d.values()) # returns random index from list
interestingIds.append(lst[choice][0])
There seems to be possible error because I'm not sure if there is a correspondence between indices in lst and d.values().
Do you know how to write this better?
One of the policies of dict is that the results of dict.keys() and dict.values() will correspond so long as the contents of the dictionary are not modified.
As #Ignacio says, the index choice does correspond to the intended element of lst, so your code's logic is correct. But your code should be much simpler: d already contains IDs for the elements, so rewrite randomWeightedChoice to take a dictionary and return an ID.
Perhaps it will help you to know that you can iterate over a dictionary's key-value pairs with d.items():
for k, v in d.items():
etc.

Categories

Resources