Remove certain keys from a dictionary in python - 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.

Related

Iterating over dictionary by skipping the first key-value

I have defined a dictionary with a key and a dataframe, like this
data = {'Value':[0,1,2,3,4]}
kernel_df = pd.DataFrame(data, index=['M0','M1','M2','M3','M4'])
my_dict = {'dummy':kernel_df}
And my_dict is later filled with appropriate data. Next, I want to iterate over the dictionary starting from the second key, because the first (index 0) is dummy and I want to skip that. If I use
for key in my_dict:
Then the first key is also read. If I use
for i in {1..len(my_dict)}:
df = my_dict[i]
I receive the following error
for i in {1..len(my_dict)}:
AttributeError: 'float' object has no attribute 'len'
How can I fix that?
A dictionary doesn't have an inherent order(well okay, things changed in Python 3.7 where they now maintain the order of insertion.
However, you still can't index a dictionary like you would index a list.
(Okay you can get close to that kind of behavior if you really so wished, but I'll address that towards the end).
In your case, you can just iterate through the keys and skip the key if it's 'dummy' (or whatever you've defined it as).
for key in my_dict:
if key != 'dummy':
do your thing
Perhaps a better alternative would be to simply remove the 'dummy' key once you know your dictionary has bee populated with proper values.
Now, coming back to getting the 'first key' because one is a >= Python 3.7 user:
Okay if someone really wanted to rely on the technical implementation of a version specific feature, they could probably do something like this:
for idx, key in enumerate(my_dict.keys()):
if idx != 0:
do your thing
This is far from idiomatic code though, so really, you shouldn't.

Python convert named string fields to tuple

Similar to this question: Tuple declaration in Python
I have this function:
def get_mouse():
# Get: x:4631 y:506 screen:0 window:63557060
mouse = os.popen( "xdotool getmouselocation" ).read().splitlines()
print mouse
return mouse
When I run it it prints:
['x:2403 y:368 screen:0 window:60817757']
I can split the line and create 4 separate fields in a list but from Python code examples I've seen I feel there is a better way of doing it. I'm thinking something like x:= or window:=, etc.
I'm not sure how to properly define these "named tuple fields" nor how to reference them in subsequent commands?
I'd like to read more on the whole subject if there is a reference link handy.
It seems it would be a better option to use a dictionary here. Dictionaries allow you to set a key, and a value associated to that key. This way you can call a key such as dictionary['x'] and get the corresponding value from the dictionary (if it exists!)
data = ['x:2403 y:368 screen:0 window:60817757'] #Your return data seems to be stored as a list
result = dict(d.split(':') for d in data[0].split())
result['x']
#'2403'
result['window']
#'60817757'
You can read more on a few things here such as;
Comprehensions
Dictionaries
Happy learning!
try
dict(mouse.split(':') for el in mouse
This should give you a dict (rather than tuples, though dicts are mutable and also required hashability of keys)
{x: 2403, y:368, ...}
Also the splitlines is probably not needed, as you are only reading one line. You could do something like:
mouse = [os.popen( "xdotool getmouselocation" ).read()]
Though I don't know what xdotool getmouselocation does or if it could ever return multiple lines.

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().

Is there a more elegant way to write this in Python?

I want to append 'status' to the dict value indexed by 'update_fields' or add ['status'] as a value to kwargs indexed by 'update_fields' if that key isn't present.
kwargs.setdefault('update_fields', kwargs.get('update_fields', []).append('status'))
It's either this or about 3 lines of code, surely python can do better than this!
get and setdefault are essentially two methods of doing the same thing; putting them together is repeating yourself. The only difference between get and setdefault is that setdefault sets the value if the default doesn't exist. After that, they are identical semantically.
So this part:
kwargs.get('update_fields', [])
..is redundant. setdefault sets the default (and returns it, like get) if the dictionary doesn't have a value for that key yet, otherwise it just looks up the value associated with the key.
So all you need is:
kwargs.setdefault('update_fields', []).append('status')
You don't need the kwargs.get() bit, setdefault only sets the value if it's not already there, you can just write:
kwargs.setdefault('update_fields', []).append('status')

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.

Categories

Resources