clearing a dictionary but keeping the keys - python

Is it possible to clear all the entries within a dictionary but keep all the keys?
For example if I had:
my_dic={
"colour":[],
"number":[]
}
I put some stuff in them:
my_dic["colour"]='Red'
my_dic["number"]='2'
I can clear these by:
my_dic["colour"] = []
my_dic["number"] = []
But this is long winded if I want to clear a large dictionary quickly, is there a quicker way perhaps using for? I want to keep the keys ["colour"], ["number"], without having to recreate them, just clear all the entries within them.

You can simply clear all lists in a loop:
for value in my_dic.values():
del value[:]
Note the value[:] slice deletion; we are removing all indices in the list, not the value reference itself.
Note that if you are using Python 2 you probably want to use my_dic.itervalues() instead of my_dic.values() to avoid creating a new list object for the loop.
Demo:
>>> my_dic = {'colour': ['foo', 'bar'], 'number': [42, 81]}
>>> for value in my_dic.values():
... del value[:]
...
>>> my_dic
{'colour': [], 'number': []}
You could also replace all values with new empty lists:
my_dic.update((key, []) for key in my_dic)
or replace the whole dictionary entirely:
my_dic = {key: [] for key in my_dic}
Take into account these two approaches will not update other references to either the lists (first approach) or the whole dictionary (second approach).

You no need to delete keys from dictionary:
for key in my_dict:
my_dict[key] = []

One liner:
my_dict = dict.fromkeys(my_dict, None)
You can also replace the None type with other values that are immutable. A mutable type such as a list will cause all of the values in your new dictionary to be the same list.
For mutable types you would have to populate the dictionary with distinct instances of that type as others have shown.

Related

Python - How to create sublists from list of strings based on part of the string?

I saw similar questions but unfortunately I didnt found answer for my problem.
I have a list:
list = ['a_abc', 'a_xyz', 'a_foo', 'b_abc', 'b_xyz', 'b_foo']
I want to split this list into 3 based on character after underscore _.
Desired output would be:
list_1 = ['a_abc', 'b_abc']
list_2 = ['a_xyz', 'b_xyz']
list_3 = ['a_foo', 'b_foo']
I would like to avoid something like:
for element in list:
if 'abc' in element...
if 'xyz' in element...
because I have over 200 strings to group in this way in my use case. So code "should recognize" the same part of the string (after underscore) and group this in sublists.
Since I didnt notice similar issue any advice is highly appreciated.
You shouldn't want to do this with one or more lists, because you don't know at runtime how many there are (or, even if you know, it will be repeated code).
Instead, you can use defaultdict; it's like a default dictionary, but handles missing value simply creating a new element with your specified factory.
In this case, defaultdict(list) means to create a dictionary with a list factory; when a key is missing, the object will create an empty list for that key.
from collections import defaultdict
l = ['a_abc', 'a_xyz', 'a_foo', 'b_abc', 'b_xyz', 'b_foo']
d = defaultdict(list)
for el in l:
key = el.split("_")[1]
# key = el[2:] # use this if the format of elements is <letter>_<other_chars>
d[key].append(el)
print(d)
# defaultdict(<class 'list'>, {'abc': ['a_abc', 'b_abc'], 'xyz': ['a_xyz', 'b_xyz'], 'foo': ['a_foo', 'b_foo']})
print(d["abc"])
# ['a_abc', 'b_abc']

how to delete and add multiple items without iterating a dictionary in python 3.7x?

I wonder if a existing dictionary instance can add and/or delete multiple items without using iterations.
I mean something like this.
supposition:(it actually doesn't work)
D = {"key1":"value1", "key2":"value2", "key3":"value3"}
tags = ["key1","key2"]
D.pop(tags)
print(D)
{"key3":"value3"}
Thank you in advance.
If so, you could iterate a list instead of iterate the full dict:
D = {"key1":"value1", "key2":"value2", "key3":"value3"}
for i in ["key1", "key2"]:
D.pop(i)
print(D)
If you don't actually need to avoid iteration, but rather just want to do the transformation of the dictionary in an expression, rather than a statement, you could use a dictionary comprehension to create a new dictionary containing only the keys (and the associated values) that don't match your list of things to remove:
D = {key: value for key, value in D.items() if key not in tags}
Unfortunately, this doesn't modify D in place, so if you need to change the value referenced through some other variable this won't help you (and you'd need to do an explicit loop). Note that if you don't care about the values being removed, you probably should use del D[key] instead of D.pop(key).
If all you're wanting to do is show the dictionary where key from list is not present, why not just create a new dic:
D = {"key1":"value1", "key2":"value2", "key3":"value3"}
tags=["key1", "key2"]
dict = {key:value for key, value in D.items() if key not in tags}
print(dict)

How to access a dict's values and delete them?

I have a Python dict stuffs with keys and values(list);
{'car':['bmw','porsche','benz'] 'fruits':['banana','apple']}
And I would like delete first value from cars: bmw and first value from fruits: banana
How can I access and delete them please? I have tried .pop(index), but it doesn't work...
You can create a new dictionary where you skip the first element using [1:]
stuffs = {'car':['bmw','porsche','benz'], 'fruits':['banana','apple']}
stuffs_new = {k:v[1:] for k,v in stuffs.items()}
# {'car': ['porsche', 'benz'], 'fruits': ['apple']}
An easy way of doing this is to use a for loop and iterate over each item in you're dictionary, and pop the first element:
dictionary = {'car':['bmw','porsche','benz'], 'fruits':['banana','apple']}
for key in dictionary:
dictionary[key].pop(0)
Or, as a list comprehension
dictionary = {'car':['bmw','porsche','benz'], 'fruits':['banana','apple']}
[dictionary[i].pop(0) for i in dictionary]
These pieces of code reference the dictionary at each of it's keys ('car' and 'fruits') and then proceeds to use pop on the values indexed by these keys.
Edit:
Don't use a list comprehension if you don't intend to store the list. In the case where you are iterating over large values, you could run into memory errors due to storing a whole load of useless values. Such as in this case:
[print(i) for i in range(9823498)]
This will store 9823498 None values*, where as a for loop would not. but still achieve the same thing.
You were almost there.
Use either:
del dict[key]
Or
dict.pop(key, value)
The second will remove but also leave the item available as a return

Creating a dict containing a sub-dict as the new value with the index as the key

I have a dictionary currently setup as
{'name': 'firm', 'name':'firm', etc},
Where keys are analyst names and values are analyst firms.
I am trying to create a new dictionary where the new values are the old k,v pairs and the associated key is simply the index (1, 2, 3, 4, etc).
Current code is below:
num_analysts = len(analysts.keys())
for k,v in analysts.items():
analysts_dict = dict.fromkeys(range(num_analysts), [k,v])
Current result
Each numeric key is getting given the same value (old k,v pair). What is wrong with my expression?
You can enumerate the items and convert them to a dictionary. However, dictionaries, in general, are not ordered. This means that the keys may be assigned essentially randomly.
dict(enumerate(analysts.items(), 1))
#{1: ('name1', 'firm1'), 2: ('name2', 'firm2')}
Enumerate and dictionary comprehension for this
d = {'name1': 'firm1', 'name2': 'firm2'}
d2 = {idx: '{}, {}'.format(item, d[item]) for idx, item in enumerate(d, start = 1)}
{1: 'name1, firm1', 2: 'name2, firm2'}
There are already effective answer posted by others. So I may just put the reason why your own solution does't work properly. It may caused by lazy binding. There are good resource on: http://quickinsights.io/python/python-closures-and-late-binding/
Because late binding will literally pick up the last one in dictionary you created. But this last one is not "virtually last one", it is determined by the OS. (Other people already give some explanation on dict data-structure.)
For each time you run in python command line the result may change. If you put the code in .py file, For each time you run in IDE, the result will be same.(always the last one in dict)
During each iteration, analysts_dict is assigned value based on the result of dict.items().
However, you should use comprehension to generate the final result in one line,
E.g. [{i: e} for i, e in enumerate(analysts.items())]
analysts = {
"a": 13,
"b": 123,
"c": 1234
}
num_analysts = len(analysts.keys())
analysts_dict = [{i: e} for i, e in enumerate(analysts.items())]
print(analysts_dict)
>> [{0: ('a', 13)}, {1: ('b', 123)}, {2: ('c', 1234)}]
This code
for k,v in analysts.items():
analysts_dict = dict.fromkeys(range(num_analysts), [k,v])
loops over the original dict and on each loop iteration it creates a new dict using the range numbers as the keys. By the way, every item in that dict shares a reference to a single [k, v] list object. That's generally a bad idea. You should only use an immutable object (eg None, a number, or a string) as the value arg to the dict.fromkeys method. The purpose of the method is to allow you to create a dict with a simple default value for the keys you supply, you can't use it to make a dict with lists as the values if you want those lists to be separate lists.
The new dict object is bound to the name analysts_dict. On the next loop iteration, a new dict is created and bound to that name, replacing the one just created on the previous loop, and the replaced dict is destroyed.
So you end up with an analysts_dict containing a bunch of references to the final [k, v] pair read from the original dict.
To get your desired result, you should use DYZ's code, which I won't repeat here. Note that it stores the old name & firm info in tuples, which is better than using lists for this application.

Checking items in a list of dictionaries in python

I have a list of dictionaries=
a = [{"ID":1, "VALUE":2},{"ID":2, "VALUE":2},{"ID":3, "VALUE":4},...]
"ID" is a unique identifier for each dictionary. Considering the list is huge, what is the fastest way of checking if a dictionary with a certain "ID" is in the list, and if not append to it? And then update its "VALUE" ("VALUE" will be updated if the dict is already in list, otherwise a certain value will be written)
You'd not use a list. Use a dictionary instead, mapping ids to nested dictionaries:
a = {
1: {'VALUE': 2, 'foo': 'bar'},
42: {'VALUE': 45, 'spam': 'eggs'},
}
Note that you don't need to include the ID key in the nested dictionary; doing so would be redundant.
Now you can simply look up if a key exists:
if someid in a:
a[someid]['VALUE'] = newvalue
I did make the assumption that your ID keys are not necessarily sequential numbers. I also made the assumption you need to store other information besides VALUE; otherwise just a flat dictionary mapping ID to VALUE values would suffice.
A dictionary lets you look up values by key in O(1) time (constant time independent of the size of the dictionary). Lists let you look up elements in constant time too, but only if you know the index.
If you don't and have to scan through the list, you have a O(N) operation, where N is the number of elements. You need to look at each and every dictionary in your list to see if it matches ID, and if ID is not present, that means you have to search from start to finish. A dictionary will still tell you in O(1) time that the key is not there.
If you can, convert to a dictionary as the other answers suggest, but in case you you have reason* to not change the data structure storing your items, here's what you can do:
items = [{"ID":1, "VALUE":2}, {"ID":2, "VALUE":2}, {"ID":3, "VALUE":4}]
def set_value_by_id(id, value):
# Try to find the item, if it exists
for item in items:
if item["ID"] == id:
break
# Make and append the item if it doesn't exist
else: # Here, `else` means "if the loop terminated not via break"
item = {"ID": id}
items.append(id)
# In either case, set the value
item["VALUE"] = value
* Some valid reasons I can think of include preserving the order of items and allowing duplicate items with the same id. For ways to make dictionaries work with those requirements, you might want to take a look at OrderedDict and this answer about duplicate keys.
Convert your list into a dict and then checking for values is much more efficient.
d = dict((item['ID'], item['VALUE']) for item in a)
for new_key, new_value in new_items:
if new_key not in d:
d[new_key] = new_value
Also need to update on key found:
d = dict((item['ID'], item['VALUE']) for item in a)
for new_key, new_value in new_items:
d.setdefault(new_key, 0)
d[new_key] = new_value
Answering the question you asked, without changing the datastructure around, there's no real faster way of looking without a loop and checking every element and doing a dictionary lookup for each one - but you can push the loop down to the Python runtime instead of using Python's for loop.
I haven't tried if it ends up faster though.
a = [{"ID":1, "VALUE":2},{"ID":2, "VALUE":2},{"ID":3, "VALUE":4}]
id = 2
tmp = filter(lambda d: d['ID']==id, a)
# the filter will either return an empty list, or a list of one item.
if not tmp:
tmp = {"ID":id, "VALUE":"default"}
a.append(tmp)
else:
tmp = tmp[0]
# tmp is bound to the found/new dictionary

Categories