Dictionaries - Check key for multiple values - python

in my program (that searches for specific keys) i want to implement that it terminates if the key has more than one value. How can i check a key for multiple values?
edit: thanks for clearing up my mistake.
It seems my values are lists. In that case how can i check for multiple items in the list that is my value?

Using the len builtin in python, you can check the length of a list. If the length of the value is more then 1 then there are more then one value in the list.
for key in dictionary: # loop through all the keys
value = dictionary[key] # get value for the key
if len(value) > 1:
break # stop loop if list length is more than 1
Note that this assumes that every value in the dictionary is a list or container.

It is not possible for a dictionary key to have more than one value: either the key is not present in the dictionary, so it has no value, or it is present, and it has one value.
That value may be a tuple, list, dictionary, etc., which contains multiple values, but it is still one value itself. The value may also be None which can be a marker for no value, but it is still a value.
As #Ulisha's comment said, if you try to assign a new value to a key, the new value will just replace the old value. Again, there can be at most one value for a given key, although there are ways to simulate multiple values by using container objects such a tuple, list, or dict.
If you are looking at a specific item and you want to test if it is a list, you can use
if isinstance(item, list):
This will also catch items that have a type that descends from list, such as a priority queue. If you want to expand that to also detect tuples, dicts, sets, and most other "containers", you can use
if isinstance(item, collections.Container):
For this you will, of course, need to import the collections module.
Remember that even if the item is a list, it may have no, one, or multiple items.

Related

Error Changing Dictionary Keys

I've two defaultdicts I eventually want to merge, but first I need to make their keys match. According to some threads I've seen here, I can use pop() to replace keys in a dictionary. But that only updates the existing dictionary, whereas I want to create a new dictionary with the new keys. So something like:
existing_dict_one -> new_dict_one
This is what I've so far:
def split_tabs(x):
"""
Function to split tab-separated strings, used to break up the keys that are separated by tabs.
"""
return x.split('\t')
def create_dict(old_dict):
"""
Function to create a new defaultdict from an existing defaultdict, just with
different keys.
"""
new_dict = old_dict.copy() # Create a copy of old_dict to house the new keys, but with the same values.
for key, value in new_dict.iteritems():
umi = split_tabs(key)[0] # Change key to be UMI, which is the 0th index of the tab-delimited key.
# new_key = key.replace(key, umi)
new_dict[umi] = new_dict.pop(key)
return new_dict
However, I'm getting the following error
RuntimeError: dictionary changed size during iteration
and I don't know how to fix it. Does anyone know how to correct it? I'd like to use the variable "umi" as the new key.
I'd like to post the variable "key" and dictionary "old_dict" I'm using for testing this code, but it's messy and takes up a lot of space. So here's a pastebin link that contains them instead.
Note that "umi" comes from variable "key" which is separated by tabs. So I split "key" and get the first object as "umi".
Just use a dict comprehension for this:
new_dict = {split_tabs(key)[0]: value for key, value in old_dict.iteritems()}
Trying to modify a dictionary while iterating over it is not a good idea in general.
If you use .items() instead of .iteritems(), you won't have that problem, because that will just return a list that is disconnected from the dictionary. In python 3 it would be 'list(new_dict.items())`.
Also if there's any possibility that the dictionary values are mutable, you'll have to use copy.deepcopy(old_dict) instead of just old_dict.copy().

Ignoring a key when looping through a sorted dictionary in Python

I have a dictionary in python and I'm assigning elements to an array utilizing a key with four elements. I want to plot my arrays by looping through my sorted dictionary but I'd like to ignore one of the keys in the loop. My code looks like this:
key = (process, temp, board, chip)
#Do some stuff in a loop
for key in sorted(svmDict):
#plot some things but don't sort with the variable chip
I found some articles for removing a specific key but in my case chip is actually a variable and I removing each key seems cumbersome and likely unnecessary.
If you're not worried about speed I would just check whether or not you are at an acceptable key in the loop. You can directly check against one value you want to skip or make a list of values you want to skip
ignore_list = [chip]
for key in sorted(svmDict):
if key not in ignore_list:
#do the thing

Delete an item from a python dictionary when two keys have the same value

I have a python dictionary which has two keys with the same value.
mydict = {'a':'hi','b':'bye','c':'hi'}
What do I do if I want to delete just the element 'c':'hi'
I tried both del mydict['c'] and mydict.pop('c',None). Both these give me a KeyError.
First of all, there won't be a difference when you assign the same value to multiple keys. All elements in a python dict are required to have unique, immutable keys but there is no such constraint on the value. So don't worry too much about that!
This aside, both of the options you proposed behave as intended. The KeyError being thrown means that the key 'c' is not present in the dictionary. This leads me to believe that what you have shown is not in the dictionary at the time when the del or pop is called.

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.

Most efficient way to update attribute of one instance

I'm creating an arbitrary number of instances (using for loops and ranges). At some event in the future, I need to change an attribute for only one of the instances. What's the best way to do this?
Right now, I'm doing the following:
1) Manage the instances in a list.
2) Iterate through the list to find a key value.
3) Once I find the right object within the list (i.e. key value = value I'm looking for), change whatever attribute I need to change.
for Instance within ListofInstances:
if Instance.KeyValue == SearchValue:
Instance.AttributeToChange = 10
This feels really inefficient: I'm basically iterating over the entire list of instances, even through I only need to change an attribute in one of them.
Should I be storing the Instance references in a structure more suitable for random access (e.g. dictionary with KeyValue as the dictionary key?) Is a dictionary any more efficient in this case? Should I be using something else?
Thanks,
Mike
Should I be storing the Instance references in a structure more suitable for random access (e.g. dictionary with KeyValue as the dictionary key?)
Yes, if you are mapping from a key to a value (which you are in this case), such that one typically accesses an element via its key, then a dict rather than a list is better.
Is a dictionary any more efficient in this case?
Yes, it is much more efficient. A dictionary takes O(1) on average to lookup an item by its key whereas a list takes O(n) to lookup an item by its key, which is what you are currently doing.
Using a Dictionary
# Construct the dictionary
d = {}
# Insert items into the dictionary
d[key1] = value1
d[key2] = value2
# ...
# Checking if an item exists
if key in d:
# Do something requiring d[key]
# such as updating an attribute:
d[key].attr = val
As you mention, you need to keep an auxiliary dictionary with the key value as the key and the instance (or list of instance with that value for their attribute) as the value(s) -- way more efficient. Indeed, there's nothing more efficient than a dictionary for such uses.
It depends on what the other needs of your program are. If all you ever do with these objects is access the one with that particular key value, then sure, a dictionary is perfect. But if you need to preserve the order of the elements, storing them in a dictionary won't do that. (You could store them in both a dict and a list, or there might be a data structure that provides a compromise between random access and order preservation) Alternatively, if more than one object can have the same key value, then you can't store both of them in a single dict at the same time, at least not directly. (You could have a dict of lists or something)

Categories

Resources