Skipping to Next item in Dictionary - python

When iterating through a dictionary, I want to skip an item if it has a particular key. I tried something like mydict.next(), but I got an error message 'dict' object has no attribute 'next'
for key, value in mydict.iteritems():
if key == 'skipthis':
mydict.next()
# for others do some complicated process
I am using Python 2.7 if that matters.

Use continue:
for key, value in mydict.iteritems():
if key == 'skipthis':
continue
Also see:
Are break and continue bad programming practices?

I think you want to call mydict.iteritems().next(), however you should just filter the list before iterating.
To filter your list, you could use a generator expression:
r = ((k, v) for k, v in mydict.iteritems() if k != 'skipthis')
for k,v in r:
#do something complicated to filtered items
Because this is a generator expression, it has the property of only traversing the original dict once, leading to a boost in performance over other alternatives which iterate the dictionary, and optionally copy elements to a new one or delete existing elements from it. Generators can also be chained, which can be a powerful concept when iterating.
More info on generator expressions:
http://www.python.org/dev/peps/pep-0289/

Another alternative is this:
for key, value in mydict.iteritems():
if key != 'skipthis':
# Do whatever
It does the same thing as skipping the key with continue. The code under the if statement will only run if the key is not 'skipthis'.
The advantage of this method is that it is cleaner and saves lines. Also is a little better to read in my opinion.

You should ask the question why are you needing to do this? One unit of code should do one thing, so in this case the loop should have had the dict 'cleaned' before it reaches it.
Something along these lines:
def dict_cleaner(my_dict):
#make a dict of stuff you want your loop to deal with
return clean_dict
for key, value in dict_cleaner(mydict).iteritems():
#Do the stuff the loop actually does, no worrying about selecting items from it.

Related

Remove "First" Item From Python Dict

Good afternoon.
I'm sorry if my question may seem dumb or if it has already been posted (I looked for it but didn't seem to find anything. If I'm wrong, please let me know: I'm new here and I may not be the best at searching for the correct questions).
I was wondering if it was possible to remove (pop) a generic item from a dictionary in python.
The idea came from the following exercise:
Write a function to find the sum of the VALUES in a given dictionary.
Obviously there are many ways to do it: summing dictionary.values(), creating a variable for the sum and iterate through the dict and updating it, etc.. But I was trying to solve it with recursion, with something like:
def total_sum(dictionary):
if dictionary == {}:
return 0
return dictionary.pop() + total_sum(dictionary)
The problem with this idea is that we don't know a priori which could be the "first" key of a dict since it's unordered: if it was a list, the index 0 would have been used and it all would have worked.
Since I don't care about the order in which the items are popped, it would be enough to have a way to delete any of the items (a "generic" item). Do you think something like this is possible or should I necessarily make use of some auxiliary variable, losing the whole point of the use of recursion, whose advantage would be a very concise and simple code?
I actually found the following solution, which though, as you can see, makes the code more complex and harder to read: I reckon it could still be interesting and useful if there was some built-in, simple and direct solution to that particular problem of removing the "first" item of a dict, although many "artificious", alternative solutions could be found.
def total_sum(dictionary):
if dictionary == {}:
return 0
return dictionary.pop(list(dictionary.keys())[0]) + total_sum(dictionary)
I will let you here a simple example dictionary on which the function could be applied, if you want to make some simple tests.
ex_dict = {"milk":5, "eggs":2, "flour": 3}
ex_dict.popitem()
it removes the last (most recently added) element from the dictionary
(k := next(iter(d)), d.pop(k))
will remove the leftmost (first) item (if it exists) from a dict object.
And if you want to remove the right most/recent value from the dict
d.popitem()
You can pop items from a dict, but it get's destroyed in the process. If you want to find the sum of values in a dict, it's probably easiest to just use a list comprehension.
sum([v for v in ex_dict.values()])
Instead of thinking in terms of popping values, a more pythonic approach (as far is recursion is pythonic here) is to use an iterator. You can turn the dict's values into an iterator and use that for recursion. This will be memory efficient, and give you a very clean stopping condition for your recursion:
ex_dict = {"milk":5, "eggs":2, "flour": 3}
def sum_rec(it):
if isinstance(it, dict):
it = iter(it.values())
try:
v = next(it)
except StopIteration:
return 0
return v + sum_rec(it)
sum_rec(ex_dict)
# 10
This doesn't really answer the question about popping values, but that really shouldn't be an option because you can't destroy the input dict, and making a copy just to get the sum, as you noted in the comment, could be pretty expensive.
Using popitem() would be almost the same code. You would just catch a different exception and expect the tuple from the pop. (And of course understand you emptied the dict as a side effect):
ex_dict = {"milk":5, "eggs":2, "flour": 3}
def sum_rec(d):
try:
k,v = d.popitem()
except KeyError:
return 0
return v + sum_rec(d)
sum_rec(ex_dict)
# 10
We can use:
dict.pop('keyname')

Choose one key arbitrarily in a dictionary without iteration [duplicate]

This question already has answers here:
dict.keys()[0] on Python 3 [duplicate]
(3 answers)
Closed 6 years ago.
I just wanna make sure that in Python dictionaries there's no way to get just a key (with no specific quality or relation to a certain value) but doing iteration. As much as I found out you have to make a list of them by going through the whole dictionary in a loop. Something like this:
list_keys=[k for k in dic.keys()]
The thing is I just need an arbitrary key if the dictionary is not empty and don't care about the rest. I guess iterating over a long dictionary in addition to creation of a long list for just randomly getting a key is a whole lot overhead, isn't it?
Is there a better trick somebody can point out?
Thanks
A lot of the answers here produce a random key but the original question asked for an arbitrary key. There's quite a difference between those two. Randomness has a handful of mathematical/statistical guarantees.
Python dictionaries are not ordered in any meaningful way. So, yes, accessing an arbitrary key requires iteration. But for a single arbitrary key, we do not need to iterate the entire dictionary. The built-in functions next and iter are useful here:
key = next(iter(mapping))
The iter built-in creates an iterator over the keys in the mapping. The iteration order will be arbitrary. The next built-in returns the first item from the iterator. Iterating the whole mapping is not necessary for an arbitrary key.
If you're going to end up deleting the key from the mapping, you may instead use dict.popitem. Here's the docstring:
D.popitem() -> (k, v), remove and return some (key, value) pair as a 2-tuple;
but raise KeyError if D is empty.
You can use random.choice
rand_key = random.choice(dict.keys())
And this will only work in python 2.x, in python 3.x dict.keys returns an iterator, so you'll have to do cast it into a list -
rand_key = random.choice(list(dict.keys()))
So, for example -
import random
d = {'rand1':'hey there', 'rand2':'you love python, I know!', 'rand3' : 'python has a method for everything!'}
random.choice(list(d.keys()))
Output -
rand1
You are correct: there is not a way to get a random key from an ordinary dict without using iteration. Even solutions like random.choice must iterate through the dictionary in the background.
However you could use a sorted dict:
from sortedcontainers import SortedDict as sd
d = sd(dic)
i = random.randrange(len(d))
ran_key = d.iloc[i]
More here:.
http://www.grantjenks.com/docs/sortedcontainers/sorteddict.html
Note that whether or not using something like SortedDict will result in any efficiency gains is going to be entirely dependent upon the actual implementation. If you are creating a lot of SD objects, or adding new keys very often (which have to be sorted), and are only getting a random key occasionally in relation to those other two tasks, you are unlikely to see much of a performance gain.
How about something like this:
import random
arbitrary_key = random.choice( dic.keys() )
BTW, your use of a list comprehension there really makes no sense:
dic.keys() == [k for k in dic.keys()]
check the length of dictionary like this, this should do !!
import random
if len(yourdict) > 0:
randomKey = random.sample(yourdict,1)
print randomKey[0]
else:
do something
randomKey will return a list, as we have passed 1 so it will return list with 1 key and then get the key by using randomKey[0]

Finding a key in a dictionary without knowing its full name

I have a dictionary with a key called ev#### where #### is some number that I do not know ahead of time. There is only one of this type of key in the dictionary and no other key starts with ev.
What's the cleanest way to access that key without knowing what the #### is?
You can try this list comprehension: (ideone)
result = [v for k, v in d.iteritems() if k.startswith('ev')][0]
Or this approach using a generator expression: (ideone)
result = next(v for k, v in d.iteritems() if k.startswith('ev'))
Note that these will both require a linear scan of the items in the dictionary, unlike an ordinary key-lookup which runs in constant time on average (assuming a good hash function). The generator expression however can stop as soon as it finds the key. The list comprehension will always scan the entire dicitonary.
If there is only one such value in the dictionary, I would say it's better to use an approach similar to this:
for k,v in d.iteritems():
if k.startswith('ev'):
result = v
break
else:
raise KeyError() # or set to default value
That way you don't have to loop through every value in the dictionary, but only until you find the key, which should speed up the calculation by ~ 2x on average.
Store the item in the dictionary without the ev prefix in the first place.
If you also need to access it with the prefix, store it both ways.
If there can be multiple prefixes for a given number, use a second dictionary that stores the actual keys associated with each number as a list or sub-dictionary, and use that to find the available keys in the main dictionary matching the number.
If you can't easily do this when the dictionary is initially created (e.g. someone else's code is giving you the dict and you can't change it), and you will be doing a lot of lookups of this sort, it is probably worthwhile to iterate over the dict once and make the second dict, or use a dict to cache the lookups, or something of that sort, to avoid iterating the keys each time.

Suggestions for improving how I loop through the values of a dictionary?

This is what I have been using:
for i in iter(SHAPES):
SHAPES[i].drawOrder(97)
SHAPES[i].alpha(CFG["SHP_alpha"])
.
.
This is what I thought about doing:
for i, v in app.SHAPES.items():
v.drawOrder(97)
v.alpha(CFG["SHP_alpha"])
.
.
Which of the two am I supposed to use? Are there any other ways of doing it?
If you don't need the key, just ignore it and use .itervalues(). If you need both key and value, .iteritems() is indeed the way to go. Note that in Python 3, those got rid of the iter prefix and Python 2 .values() and .items() (which returned lists) are gone. They have their (rare) uses, but when you just iterate, there is no need to copy half of the dictionary.
And never call iter yourself unless you really need an iterator (e.g. for next). Which is hardly more often than never ;) for i in iterable already uses iter(iterable) implicitly.
Iterate over the values in the dict.
for v in SHAPES.itervalues():
v.drawOrder(97)
...
The option that gives the most flexibility for a dictionary is to use enumerate() and dict.iteritems().
for i, (k,v) in enumerate(SHAPES.iteritems()):
print "My index is {0}, key is {1}, and value is {2}".format(i, k, v)

Remove certain keys from a dictionary in python

I'm trying to construct a dictionary that contains a series of sets:
{Field1:{Value1, Value2, Value3}, Field2{Value4}}
The trouble is, I then wish to delete any fields from the dictionary that only have one value in the set. I have been writing code like this:
for field in FieldSet:
if len(FieldSet[field]) == 1:
del(FieldSet[field])
But receive the error "RuntimeError: dictionary changed size during execution". (Not surprising, since that's what I'm doing.) It's not the be-all and end-all if I have to knock together some sort of workaround, but is it possible to do this?
Iterate over the return value from .keys() instead. Since you get a list of keys back, it won't be affected by changing the dictionary after you've called it.
A sometimes-preferable alternative to changing FieldSet in place is sometimes (depending on the amount of alterations performed) to build a new one and bind it to the existing name:
FieldSet = dict((k, v) for k, v in FieldSet.iteritems()
if len(v) != 1)
There is the pop method. It removes the element that a key calls. With respect to your example this looks like:
for field in FieldSet.keys():
if len(FieldSet[field]) == 1:
FieldSet.pop(field)
This is in python 3.2, but I'm not sure if it's a new feature:
http://docs.python.org/dev/library/stdtypes.html#dict.pop
Just tried it and it works as advertised.

Categories

Resources