How to prevent Python dictionary key ordering reversal? - python

I have the following python code snippet involving dictionary,
sample_dict = {
"name": "Kelly",
"age": 25,
"salary": 8000,
"city": "New york"
}
keys = ["name", "salary"]
sample_dict = {k: sample_dict[k] for k in sample_dict.keys() - keys}
print(sample_dict)
Why the output is {'city': 'New york', 'age': 25} and not {'age': 25, 'city': 'New york'}?
What causes the reverse ordering of dictionary keys? Any help will be highly appreciated. I executed the code on Spyder and Python 3.8.5 version.

I guess the order is lost during processing of - between your keys() and your keys list (because it involves conversion to sets which are unordered). You can build your comprehension as follow to prevent it.
keys = {"name", "salary"}
sample_dict = {k: sample_dict[k] for k in sample_dict.keys() if k not in keys}

#Tranbi has provided the solution to the OP. I just supplement some materials.
Although dict preserves insertion order since 3.7.
Changed in version 3.7: Dictionary order is guaranteed to be insertion order. This behavior was an implementation detail of CPython from 3.6.
set does not.
Being an unordered collection, sets do not record element position or order of insertion.
If you check the result of sample_dict.keys() - keys, you will find it is a set.
remain_keys = sample_dict.keys() - keys
print(type(remain_keys))
# set
for k in remain_keys:
print(k)
# city
# age
Because dict.keys() returns a set-like view.
Keys views are set-like since their entries are unique and hashable. ... For set-like views, all of the operations defined for the abstract base class collections.abc.Set are available (for example, ==, <, or ^).

Related

How to reverse order to pop out Python 3.6.4

Instead of it deleting the 'ALL' first, I would like the popitem to delete the 'CS' first and continue in that order from top to bottom.
Here is my code:
my_dictionary ={
's02.001':'CS',
's02.002':'OEM',
's02.003':'ALL'
}
numero = len(my_dictionary)
print(my_dictionary)
my_dictionary.popitem()
print(my_dictionary)
Although it's generally not a good pattern to use a dictionary as an ordered data type, you can do what you want like this:
my_dictionary.pop(next(iter(my_dictionary.keys())))
.popitem() doesn't take parameters, but .pop() does take a specific key to pop.
Even if dicts happen to be ordered in CPython 3.6+, they're the not right data structure if you need this sort of thing. I'd recommend using a list of 2-tuples instead.
If you don't want to do that, you can, as a hack, find the "first" key, then pop the value:
next_key = next(iter(my_dictionary))
next_value = my_dictionary.pop(next_key)
This may fail on other Python implementations than CPython.
Popitem removes an arbitrary key-value pair from the dictionary in Python versions older than 3.7. In 3.7+ popitem removes the last inserted key-value pair from the dictionary..
If you know the key, you can just remove the k, v pair from the dict. If you need the dict to stay in order, you can use an ordered dict. https://docs.python.org/3/library/collections.html#collections.OrderedDict
However it's worth noting that built-in dicts remember insertion order, which is guaranteed in Python 3.7+.
my_dictionary ={
's02.001':'CS',
's02.002':'OEM',
's02.003':'ALL'
}
numero = len(my_dictionary)
print(my_dictionary)
{'s02.001': 'CS', 's02.002': 'OEM', 's02.003': 'ALL'}
del my_dictionary['s02.001']
print(my_dictionary)
{'s02.002': 'OEM', 's02.003': 'ALL'}

RuntimeError: dictionary changed size

I have two nested dictionaries. Each dictionary has a key/value pair that are the same. I have some code that says hey if these are the same, update an existing dictionary with another key/value combo that exists in one of the dictionaries to the other dictionary. I get the error RuntimeError: dictionary changed size during iteration. I've seen that you can use deepcopy to solve for this, but does anybody else have any other ideas?
performances = [
{'campaign_id': 'bob'},
{'campaign_id': 'alice'},
]
campaign_will_spend = [
{'id': 'bob'},
{'id': 'alice'},
]
for item in campaign_will_spend:
ad_dictt = dict()
for willspendkey, willspendvalue in item.items():
if willspendkey == "id":
for i in performances:
for key, value in i.items():
if key == 'campaign_id' and value == willspendvalue:
i['lifetime_budget'] = item
You're causing yourself a lot of trouble by treating dictionaries like lists and iterating over them in their entirety to find a particular item. Most of the code goes away when you just stop doing that, and the rest of it goes away if you build a dictionary to be able to easily look up entries in campaign_will_spend:
# Easy lookup for campaign_will_spend dictionaries by id.
cws_by_id = {d['id']: d for d in campaign_will_spend}
for p in performances:
p["lifetime_budget"] = cws_by_id[p["campaign_id"]]

How to put 2 dictionaries in one dictionary as elements?

I am looking to put 2 dictionaries into one dictionary.
note. I am not looking to merge them or join them. I am looking for a method similar append for dictionary.
Note;
I want them to hold their structures. don't want the data to mix up
Example
I Have this,
dic1 = {'Apple':'Mac', 'Microsoft': 'Surface', 'Google': 'Chromebook', 'Lenovo':'ThinkPad'}
dic2 = {1:'Apple', 2:'Amazon', 3:'Microsoft', 4:'Google', 5:'Facebook'}
I want this
dic3 = {{'Apple':'Mac', 'Microsoft': 'Surface', 'Google': 'Chromebook', 'Lenovo':'ThinkPad'},
{1:'Apple', 2:'Amazon', 3:'Microsoft', 4:'Google', 5:'Facebook'}}
Thanks in advance
That's not how dictionaries work. You can have a list or tuple (or possibly a frozenset) that looks mostly like what you want, but dictionaries do not allow this kind of linear concatenation. They are strictly associative containers, meaning that every value must have an associated key.
If you can associate each dictionary with a key, however, then what you want becomes extremely straightforward:
dic3 = {
'dic1': {'Apple':'Mac', 'Microsoft': 'Surface', 'Google': 'Chromebook', 'Lenovo':'ThinkPad'},
'dic2': {1:'Apple', 2:'Amazon', 3:'Microsoft', 4:'Google', 5:'Facebook'}
}
Or, using your variables:
dic3 = {'dic1': dic1, 'dic2': dic2}
Update: check the added example at the bottom.
If you don't want to change dic1 or dic2, you can do this:
dic3 = {**dic1, **dic2}
dic3 will be a dictionary.
Any common key will have the value appearing later (to the right).
For the type of output you expect (set of dictionaries), you need to create a hashable dictionary as follows:
class hashabledict(dict):
def __hash__(self):
return hash(tuple(sorted(self.items())))
dic1 = {'Apple':'Mac', 'Microsoft': 'Surface', 'Google': 'Chromebook', 'Lenovo':'ThinkPad'}
dic2 = {1:'Apple', 2:'Amazon', 3:'Microsoft', 4:'Google', 5:'Facebook'}
dic3 = {hashabledict(dic1), hashabledict(dic2)}
The above hashabledict class definition has been taken from here: Python hashable dicts

Update a python dictionary w/ lists

I'm struggling to update a dictionary of lists using loops.
weather_dict = \
{
"texas": [],
"colorado": = [],
"virginia": = [],
"illinois": = [],
"california": = []
}
arbitrary_weather = [10, 20, 30, 40, 50]
My goal is to have the values of
arbitrary_weather
pushed into lists within the dictionary using loops. The correlation map is sequential, arbitrary_weather[0] --> texas[],
arbitrary_weather[1] --> colorado[], etc. With every iteration of the code, arbitrary_weather is going to change, but the dictionary will continue to append its lists in the same sequential order.
I'm relatively new to python, but working on a graduate project that is going to accumulate a lot of data over time. Eventually, the lists of data within the dictionary will be analyzed using python panda. I have never used panda, so if possible, it would be tremendously helpful to learn best practices for building dictionaries used in data analytics.
Thank you!
If you can make sure the the number of keys in dictionary always equal the len of the list then you can loop through the dictionary and add one at a time
weather_dict = {
"texas" : [],
"colorado" : [],
"virginia" : [],
"illinois" : [],
"california" : []
}
arbitrary_weather = [10, 20, 30, 40, 50]
i = 0
for k in weather_dict:
weather_dict[k].append(arbitrary_weather[i])
i += 1
print(weather_dict)
EDIT:
Note that python 3.6 and below iterate through dict is not ordered, if you using python 3.6 and below I suggest using the answer made by Mad Physicist of turning keys into a list so it's ordered
Keep in mind that until python 3.6, dictionaries were not ordered. In fact, you're only using your initial dict as a repository for key names, so I'd recommend storing it as a sequence of key names, not a dictionary with empty values:
states = ['Texas', 'Colorado', 'Illinois', 'California']
You can turn the initial measurements into a dictionary using a comprehension, and append to the lists after that:
weather_dict = {state: [value] for state, value in zip(states, arbitrary_weather)}
You can do that even if you keep the original dictionary as a dictionary, since it is iterable over the keys.

How to get dict value x via dict value y from list of dicts

(Python 2.x) A list of dicts with only unique key-value pairs, sorted alfabetically by name, names are unique as well:
dictlist = [
{'name': 'Monty', 'has': 'eggs'},
{'name': 'Terry', 'has': 'bacon'}
]
I want to get what a given name has, by name. The following works.
names = ['Monty', 'Terry']
print dictlist[names.index('Terry')]['has']
I've made a parallel list with just names in the same order as the names in the dictlist, so I can make use of the order of the list. (I could fill names with a for loop, but that's not relevant here).
From here, among others, I know I could do this:
print next((d['has'] for d in dictlist if d['name'] == 'Terry'), None)
but that's only better if dictlist isn't sorted by name.
So I'm wondering if there isn't a more concise way of doing this, preferably one that's at least as readable as the first method?
I would not use a list at all. I would use a dictionary instead.
dictlist = {
'Monty': {'has': 'eggs'},
'Terry': {'has': 'bacon'}
}
This allows you to look up values by name like so: dictlist['Monty']['has']
If you must use a list then I think you have a good solution as-is.

Categories