Performanceoptimized changing of an dictionary - python

I have a list of dictionaries and I have a solution, described below:
[{"A1":"B1", "C1":"D1"},{"A2":"B2", "C2":"D2"},....]
Expected output would be a dictionary like this
{
"B1":"D1",
"B2":"D2",
...
}
My current procedure is
get one dictionary and create a 2 entries dict to a single one
input:
{"A1":"B1", "C1":"D1"}
output:
{"B1":"D1"}
where the "A1" and "C1" is inside my method configureable:
def method(input_dictionary, default_key_from_dict, default_value_from_dict):
single_dictionary[input_dictionary[default_key_from_dict]] = input_dictionary[default_value_from_dict]
later I perform the following ones:
def function(dict_list):
single_key_value_dictionary_list = list(map(convert_two_entries_dictionary_to_one_by_value, dict_list))
global_dict = reduce(lambda a, b: dict(a, **b), single_key_value_dictionary_list)
return global_dict
I ask myself if there is some better solution for this, I have the generator idea in my mind but I am not sure if it is worth to think about it? Any remarks on this?
UPDATE
There are only 2 keys in each entry of the list as dictionary. 2 keys only.
BR Peter

From the comments since you always have only 2 keys. You can use dict.update.
inp=[{"A1":"B1", "C1":"D1"},{"A2":"B2", "C2":"D2"}]
out={}
for d in inp:
out.update((d.values(),))
out
# {'B1': 'D1', 'B2': 'D2'}

You can use something about this:
dict1 = {"A1":"B1", "C1":"D1"}
it = iter(dict1.values())
list1 = list(zip(it, it))
print(list1)

Related

Merge a dictionary and a list

Am trying to combine a dictionary and a list which has dictionaries and an empty dictionary
dict1 = {'a': 1, 'b': 2}
list1 = [{'c': 3}, {'d':4}]
emptydict = {}
emptylist = []
Trying to merge and make it a final dictionary which looks like below.
final = {'a': 1, 'b': 2, 'c': 3, 'd':4}
Code:
final = {**dict1, **list1[0], **list1[1], **emptydict, **emptylist}
Here I dont know the length of list1, can anyone suggest me a better way than this ?
dict.update updates an existing dictionary. Unfortunately it’s a mutating method that does not return a value. Therefore adapting it to functools.reduce requires a wrapper.
Due to this, I’d be tempted to use a good old loop:
final = dict(dict1)
for d in list1:
final.update(d)
But for completeness, here’s a way using functools.reduce:
import functools
def dict_update(d, v):
d.update(v)
return d
final = functools.reduce(dict_update, list1, dict1.copy())
If you are using python 3.3+, you can use ChainMap to merge list of dicts into a single dict. And then use ** operator to merge dict1 and dict(ChainMap(*list1)).
from collections import ChainMap
final = {**dict1, **ChainMap(*list1)}

How to efficiently perform a dictionary merge?

For a problem I am solving, I have a list of dictionaries. The problem involves multiple queries of the form merge(a, b, c). Merging means, in the result, the count for the common keys is added/subtracted and uncommon keys (and their values) are appended as is.
I am currently using Python's collection.Counter to represent the dictionaries and perform the merging as follows:
def merge(a, b, c):
counter_a, counter_b, counter_c = DICTLIST[a],DICTLIST[b],DICTLIST[c]
total = counter_a + counter_b - counter_c # Type collections.Counter
return total
Although this is a convenient solution, in the problem, there can be up to 10**5 such queries. On such a scale, using this approach is too slow. Is there a better approach to solving this?
NOTE: Pre-computation of the merge queries is not practical as the number of possible inputs is very large.
Example:
DICTLIST[a] = Counter({1:5,2:10})
DICTLIST[b] = Counter({2:10,3:20})
DICTLIST[c] = Counter({1:2})
merge(a,b,c) # Expected Output: {1:3, 2:20, 3:20}
Try this -
def mergeDict(dict1, dict2):
dict3 = {**dict1, **dict2}
for key, value in dict3.items():
if key in dict1 and key in dict2:
dict3[key] = value + dict1[key]
return dict3
Then you can call like this -
# Create first dictionary
dict1 = {1:5,2:10}
# Create second dictionary
dict2 = {2:10,3:20}
# Create third dictionary
dict3 = {1:-2}
dict4 = mergeDict(dict3, mergeDict(dict1, dict2))
Please note I have "-2" in the third dict for the subtraction logic.
you can use **kwargs here
x={1:5,2:10}
y={2:10,3:20}
z={**x, **y}
if you further want to optimize the performance as there are multiple queries you should use "caching + dictionary" because lookup table is always faster than any operation
My first instinct is to look for something like the Javascript "spread" operator for python:
https://mlpipes.com/object-spread-operator-python/
Example here:
old_dict = {'hello': 'world', 'foo': 'bar'}
new_dict = {**old_dict, 'foo': 'baz'}
For your code, you should try something like:
DICTLIST[d] = {**a,**b,**c}

Find value in list of dicts and return id of dict

I'd like to try and find if a value is in a list of dicts, which can be done easily with:
if any(x['aKey'] == 'aValue' for x in my_list_of_dicts):
But this is only a boolean response, I'd like to not only check if the value is there, but to also access it afterwards, so something like:
for i, dictionary in enumerate(my_list_of_dicts):
if dictionary['aKey'] == 'aValue':
# Then do some stuff to that dictionary here
# my_list_of_dicts[i]['aNewKey'] = 'aNewValue'
Is there a better/more pythonic way of writing this out?
With next function, if expected to find only one target dict:
my_list_of_dicts = [{'aKey': 1}, {'aKey': 'aValue'}]
target_dict = next((d for d in my_list_of_dicts if d['aKey'] == 'aValue'), None)
if target_dict: target_dict['aKey'] = 'new_value'
print(my_list_of_dicts)
The output (input list with updated dictionary):
[{'aKey': 1}, {'aKey': 'new_value'}]
You can use a list comprehension. This will return a list of dictionaries that match your condition.
[x for x in my_list_of_dicts if x['aKey']=='aValue' ]

Using dict.fromkeys(), assign each value to an empty dictionary

I've hit a bit of a problem with creating empty dictionaries within dictionaries while using fromkeys(); they all link to the same one.
Here's a quick bit of code to demonstrate what I mean:
a = dict.fromkeys( range( 3 ), {} )
for key in a:
a[key][0] = key
Output I'd want is like a[0][0]=0, a[1][0]=1, a[2][0]=2, yet they all equal 2 since it's editing the same dictionarionary 3 times
If I was to define the dictionary like a = {0: {}, 1: {}, 2: {}}, it works, but that's not very practical for if you need to build it from a bigger list.
With fromkeys, I've tried {}, dict(), dict.copy() and b={}; b.copy(), how would I go about doing this?
The problem is that {} is a single value to fromkeys, and not a factory. Therefore you get the single mutable dict, not individual copies of it.
defaultdict is one way to create a dict that has a builtin factory.
from collections import defaultdict as dd
from pprint import pprint as pp
a = dd(dict)
for key in range(3):
a[key][0] = key
pp(a)
If you want something more strictly evaluated, you will need to use a dict comprehension or map.
a = {key: {} for key in range(3)}
But then, if you're going to do that, you may as well get it all done
a = {key: {0: key} for key in range(3)}
Just iterate over keys and insert a dict for each key:
{k: {0: k} for k in keys}
Here, keys is an iterable of hashable values such as range(3) in your example.

Converting Dictionary to List? [duplicate]

This question already has answers here:
How can I convert a dictionary into a list of tuples?
(13 answers)
Closed 3 years ago.
I'm trying to convert a Python dictionary into a Python list, in order to perform some calculations.
#My dictionary
dict = {}
dict['Capital']="London"
dict['Food']="Fish&Chips"
dict['2012']="Olympics"
#lists
temp = []
dictList = []
#My attempt:
for key, value in dict.iteritems():
aKey = key
aValue = value
temp.append(aKey)
temp.append(aValue)
dictList.append(temp)
aKey = ""
aValue = ""
That's my attempt at it... but I can't work out what's wrong?
dict.items()
Does the trick.
Converting from dict to list is made easy in Python. Three examples:
>> d = {'a': 'Arthur', 'b': 'Belling'}
>> d.items()
[('a', 'Arthur'), ('b', 'Belling')]
>> d.keys()
['a', 'b']
>> d.values()
['Arthur', 'Belling']
Your problem is that you have key and value in quotes making them strings, i.e. you're setting aKey to contain the string "key" and not the value of the variable key. Also, you're not clearing out the temp list, so you're adding to it each time, instead of just having two items in it.
To fix your code, try something like:
for key, value in dict.iteritems():
temp = [key,value]
dictlist.append(temp)
You don't need to copy the loop variables key and value into another variable before using them so I dropped them out. Similarly, you don't need to use append to build up a list, you can just specify it between square brackets as shown above. And we could have done dictlist.append([key,value]) if we wanted to be as brief as possible.
Or just use dict.items() as has been suggested.
You should use dict.items().
Here is a one liner solution for your problem:
[(k,v) for k,v in dict.items()]
and result:
[('Food', 'Fish&Chips'), ('2012', 'Olympics'), ('Capital', 'London')]
or you can do
l=[]
[l.extend([k,v]) for k,v in dict.items()]
for:
['Food', 'Fish&Chips', '2012', 'Olympics', 'Capital', 'London']
>>> a = {'foo': 'bar', 'baz': 'quux', 'hello': 'world'}
>>> list(reduce(lambda x, y: x + y, a.items()))
['foo', 'bar', 'baz', 'quux', 'hello', 'world']
To explain: a.items() returns a list of tuples. Adding two tuples together makes one tuple containing all elements. Thus the reduction creates one tuple containing all keys and values and then the list(...) makes a list from that.
Probably you just want this:
dictList = dict.items()
Your approach has two problems. For one you use key and value in quotes, which are strings with the letters "key" and "value", not related to the variables of that names. Also you keep adding elements to the "temporary" list and never get rid of old elements that are already in it from previous iterations. Make sure you have a new and empty temp list in each iteration and use the key and value variables:
for key, value in dict.iteritems():
temp = []
aKey = key
aValue = value
temp.append(aKey)
temp.append(aValue)
dictList.append(temp)
Also note that this could be written shorter without the temporary variables (and in Python 3 with items() instead of iteritems()):
for key, value in dict.items():
dictList.append([key, value])
If you're making a dictionary only to make a list of tuples, as creating dicts like you are may be a pain, you might look into using zip()
Its especialy useful if you've got one heading, and multiple rows. For instance if I assume that you want Olympics stats for countries:
headers = ['Capital', 'Food', 'Year']
countries = [
['London', 'Fish & Chips', '2012'],
['Beijing', 'Noodles', '2008'],
]
for olympics in countries:
print zip(headers, olympics)
gives
[('Capital', 'London'), ('Food', 'Fish & Chips'), ('Year', '2012')]
[('Capital', 'Beijing'), ('Food', 'Noodles'), ('Year', '2008')]
Don't know if thats the end goal, and my be off topic, but it could be something to keep in mind.

Categories