Going through the last x elements in an ordered dictionary? - python

I want to go through an x number of the most recently added entries of an ordered dictionary. So far, the only way I can think of is this:
listLastKeys = orderedDict.keys()[-x:]
for key in listLastKeys:
#do stuff with orderedDict[key]
But it feels redundant and somewhat wasteful to make another list and go through the ordered dictionary with that list when the ordered dictionary should already know what order it is in. Is there an alternative way? Thanks!

Iterate over the dict in reverse and apply an itertools.islice:
from itertools import islice
for key in islice(reversed(your_ordered_dict), 5):
# do something with last 5 keys

Instead of reversing it like you are, you can loop through it in reverse order using reversed(). Example:
D = {0 : 'h', 1: 'i', 2:'j'}
x = 1
for key in reversed(D.keys()):
if x == key:
break

You could keep a list of the keys present in the dictionary last run.
I don't know the exact semantics of your program, but this is a function that will check for new keys.
keys=[] #this list should be global
def checkNewKeys(myDict):
for key, item in myDict.iteritems():
if key not in keys:
#do what you want with new keys
keys.append(key)
This basically keep track of what was in the dictionary the whole run of your program, without needing to create a new list every time.

Related

How to remove random excess keys and values from dictionary in Python

I have a dictionary variable with several thousands of items. For the purpose of writing code and debugging, I want to temporarily reduce its size to more easily work with it (i.e. check contents by printing). I don't really care which items get removed for this purpose. I tried to keep only 10 first keys with this code:
i = 0
for x in dict1:
if i >= 10:
dict1.pop(x)
i += 1
but I get the error:
RuntimeError: dictionary changed size during iteration
What is the best way to do it?
You could just rewrite the dictionary selecting a slice from its items.
dict(list(dict1.items())[:10])
Select some random keys to delete first, then iterate over that list and remove them.
import random
keys = random.sample(list(dict1.keys()), k=10)
for k in keys:
dict1.pop(k)
You can convert the dictionary into a list of items, split, and convert back to a dictionary like this:
splitPosition = 10
subDict = dict(list(dict1.items())[:splitPosition])

Creating list from list of dictionaries

I'm tasked with creating a list of the values associated with a specific key from a list of dictionaries.
Currently, I'm two for loops and a conditional into this but I know there's a much more efficient way of going about this.
#lst = list of dict.
#k = specific key being checked for
for dict in lst:
for ind in dict:
if dict[ind] == k:
ret_val.append(dict[ind])
The instructions also state that I am to assume that all dictionaries contain the key and that the value should only be added if the value doesn't already exist.
You might be looking for this:
ret_val = [dict[ind] for dict in lst for ind in dict if dict[ind]==k]

How do I compare the values mapped to keys in a dictionary with elements in list to avoid redundancy?

I currently have a list which stores the URLs that I have read from a file. I then made a dictionary by mapping those URLs to a simple key (0,1,2,3, etc.).
Now I want to make sure that if the same URL shows up again that it doesn't get mapped to a different key. So I am trying to make a conditional statement to check for that. Basically I want to check if the item in the list( the URL) is the same as the value of any of the keys in the dictionary. If it is I don't want to add it again since that would be redundant.
I'm not sure what to put inside the if conditional statement for this to work.
pairs = {} #my dictionary
for i in list1:
if ( i == t for t in pairs ):
i = i +1
else:
pairs[j] = i
j = j + 1
Any help would be appreciated!
Thank you.
This might be what you're looking for. It adds the unique values to pairs, numbering them starting at zero. Duplicate values are ignored and do not affect the numbering:
pairs = {}
v = 0
for k in list1:
if k not in pairs:
pairs[k] = v
v += 1
To map items in a list to increasing integer keys there's this delightful idiom, which uses a collections.defaultdict with its own length as a default factory
import collections
map = collections.defaultdict()
items = 'aaaabdcdvsaafvggddd'
map.default_factory = map.__len__
for x in items:
map[x]
print(map)
You can access all values in your dict (pairs) by a simple pairs.values(). In your if condition, you can just add another condition that checks if the new item already exists in the values of your dictionary.

Search element in dictionary by mulitple conditions without looping

I have a dictionary like one below (but with 10k key-value pairs):
test_dict={'2*foo*+':['5','10'],'3*bar*-':['15','20']}
Is there a way in python to find an element which key.split("*")[0]==2, key.split("*")[2]=="+" and val[1]<15 without looping through the dictionary. Its easy to do by for loop, but in my case this is a part of a bigger code which is nested into another for loop, so it will take very long to finish.
Thanks,
As asked, the answer is no. There is no way to test the keys and values of a dictionary without looking at each one in turn until you find a match.
However, if you build a more complex datastructure (possibly consisting of a series of dicts) so that entries are also indexed by key.split("*")[0], then you would only have to loop over those elements.
(It does sound like you are trying to build an in-memory database though - you might well be better off just using a proper database, and relying on the caching to keep most of it in memory.)
You can use filter with a set():
test_dict={'2*foo*+':['5','10'],'3*bar*-':['15':'20']}
possibilities = list(filter(lambda x: int(x[0].split("*")[0]) == 2 and x[0].split("*")[2] == "+" and int(x[1][1]) < 15, test_dict.items()))
You note that "this is a part of a bigger code which is nested into another for loop" so I suggest that you build an index of key parts before your outer loop. Your indexes will contain sets of keys matching individual conditions. Because they contain sets you can find fast intersections to find keys that satisfy your key condition.
from collections import defaultdict
key_index_num = defaultdict(set)
key_index_word = defaultdict(set)
key_index_sign = defaultdict(set)
for key in test_dict:
num, word, sign = key.split('*')
key_index_num[num].add(key)
key_index_word[word].add(key)
key_index_sign[sign].add(key)
Then it will be easy to find keys in your inner loop. Let's say you want to find all keys that have num == '2' and sign == '+'. Find the keys by doing:
keys = key_index_num['2'].intersection(key_index_sign['+'])
Note: I have built three indexes, but if the three parts of your key are always unique you can build a single key index. The code would then look like this:
from collections import defaultdict
key_index = defaultdict(set)
for key in test_dict:
for key_part in key.split('*'):
key_index[key_part].add(key)
And keys search would look like:
keys = key_index['2'].intersection(key_index['+'])

Sorting a dict on __iter__

I am trying to sort a dict based on its key and return an iterator to the values from within an overridden iter method in a class. Is there a nicer and more efficient way of doing this than creating a new list, inserting into the list as I sort through the keys?
How about something like this:
def itersorted(d):
for key in sorted(d):
yield d[key]
By far the easiest approach, and almost certainly the fastest, is something along the lines of:
def sorted_dict(d):
keys = d.keys()
keys.sort()
for key in keys:
yield d[key]
You can't sort without fetching all keys. Fetching all keys into a list and then sorting that list is the most efficient way to do that; list sorting is very fast, and fetching the keys list like that is as fast as it can be. You can then either create a new list of values or yield the values as the example does. Keep in mind that you can't modify the dict if you are iterating over it (the next iteration would fail) so if you want to modify the dict before you're done with the result of sorted_dict(), make it return a list.
def sortedDict(dictobj):
return (value for key, value in sorted(dictobj.iteritems()))
This will create a single intermediate list, the 'sorted()' method returns a real list. But at least it's only one.
Assuming you want a default sort order, you can used sorted(list) or list.sort(). If you want your own sort logic, Python lists support the ability to sort based on a function you pass in. For example, the following would be a way to sort numbers from least to greatest (the default behavior) using a function.
def compareTwo(a, b):
if a > b:
return 1
if a == b:
return 0
if a < b:
return -1
List.Sort(compareTwo)
print a
This approach is conceptually a bit cleaner than manually creating a new list and appending the new values and allows you to control the sort logic.

Categories