i use this code to store items of dictionaries in doc variable.
This code works fine but I miss the first element of time because of the if statement.
def convert(old):
time_key = 'Time '
# Save the time
time_item = (time_key, old[time_key])
# Add remove it
del old[time_key]
# Copy remaining items to new dicts and save them in a list
return [dict([time_item, item]) for item in old.items()]
row = {
'Time ': '2017-12-01T13:54:04',
'Energy [kWh]': '0.01',
'Voltage [V]': '221.64',
'Current [A]': '0.08',
}
new_data = convert(row)
#print(new_data)
Zeitvalue= ""
Device=""
Value=""
for d in new_data:
#print(d)
for key, value in d.items():
if key == 'Time ':
Zeitvalue = value
#print(value)
continue
else:
Device = key
Value = value
doc = {'Time ':Zeitvalue,'Device':Device, 'Measure':Value}
print("This is doc variable:",doc) # doc vaiable with missed time element
SO when i print doc i got this
Output:
doc: {'Device': 'Voltage [V]', 'Measure': '221.64', 'Time ': ''} # **ISSUE: variable time is missed here, How to fix it ?**
doc: {'Device': 'Current [A]', 'Measure': '0.08', 'Time ': '2017-12-01T13:54:04'}
doc: {'Device': 'Energy [kWh]', 'Measure': '0.01', 'Time ': '2017-12-01T13:54:04'}
See the below changes in the code. Remove continue statement. Also assign value to doc after the inner loop for dictionary is over as you need all three values.
for d in new_data:
#print(d)
for key, value in d.items():
if key == 'Time ':
Zeitvalue = value
#print(value)
else:
Device = key
Value = value
doc = {'Time ':Zeitvalue,'Device':Device, 'Measure':Value}
print(doc)
if you are just setting values then place the doc assignment outside the for loop
for d in new_data:
for key, value in d.items():
if key == 'Time ':
Zeitvalue = value
continue
else:
Device = key
Value = value
doc = {'Time ':Zeitvalue,'Device':Device, 'Measure':Value}
you have problem in this line:
doc = {'Time ':Zeitvalue,'Device':Device, 'Measure':Value} when you use it inside the for loop! , each iteration overrides the previous assignment, furthermore - you cause unexpected behavior , since dictionary is not order data structure - meaning : if you encountered "tine" key first - it will work fine , but if you did not encountered 'time' first - the value of it is still == "" , since you initiate it to that value and you did not updated it since.
move the doc = {'Time ':Zeitvalue,'Device':Device, 'Measure':Value} to the outer loop , and not the one going over each key and value and you will be fine.
Related
How can I match the key name from general_key_array with all_keys dictionary to get "aws." as substring? I added the startswith section but it returns True all the time.
general_keys = dict()
all_keys = {'activity': 'ins','install': 'all','aws.a': 'data', 'aws.b': 'data1', 'aws.c': 'data2'} #read from file
general_key_array = ['install', 'aws.']
for key in general_key_array:
if key.startswith(key) in all_keys:
general_keys[key] = dict(filter(lambda item: key in item[0], all_keys.items()))
You can do it all with a single dictionary comprehension.
general_keys = {key: value for key, value in all_keys.items()
if any(key.startswith(gk) for gk in general_key_array)}
key.startswith(key) is always equal to True because it's tautological that a string starts with itself.
you can add a for loop with the keys of all_keys after the first one you wrote to solve the problem like this
general_keys = dict()
all_keys = {'activity': 'ins','install': 'all','aws.a': 'data', 'aws.b': 'data1', 'aws.c': 'data2'}
general_key_array = ['install', 'aws.']
for key in general_key_array:
for s in all_keys :
if s.startswith(key): # s is part of all_keys, no tautology here
general_keys[key] = dict(filter(lambda item: key in item[0], all_keys.items()))
This question already has answers here:
Recursive function does not return specified value
(2 answers)
Closed 1 year ago.
I have the orders of a platform in a csv file and I want to organize it to put in a database (probably mongodb). So the final data structure may be:
{'user1':
{'meals': {'hamburger': 2}, {'pizza': 1},
{'weekdays': {'monday': 1}},{'tuesday':1}, {'friday': 1}
}
So, I am trying to do a very simple code that organize the number of ocurrencies, but before I want to structure the dictionary keys dinamically. The data is in a csv file
import csv
import pprint
def addKeysNestedDict(dictionary, keys):
# print(dictionary)
if len(keys) > 1:
if keys[0] not in dictionary.keys():
dictionary[keys[0]] = {'meals': '', 'weekdays': ''}
print('inside addKeys IF: ')
print(dictionary)
addKeysNestedDict(dictionary, keys[1:])
else:
dictionary[keys[0]] = {'meals': '', 'weekdays': ''}
print('inside addKeys: ')
print(dictionary) # PRINTS EXPECTED VALUES
return dictionary
def organize_orders(file):
pp = pprint.PrettyPrinter(indent=4)
dict_read = csv.DictReader(file, fieldnames=['name', 'food', 'day'])
list_dict = list(dict_read)
set_names = set()
set_food = set()
set_day = set()
# people = {} # DOESN'T MATTER IF IT IS DECLARED BOFORE
for n in list_dict:
set_names.add(n['name'])
set_food.add(n['food'])
set_day.add(n['day'])
print(addKeysNestedDict({}, list(set_names))) # PRINTS NONE
people = (addKeysNestedDict({}, list(set_names)))
print('people: ')
print(people) # PRINTS NONE
# for s_n in set_names:
# for s_f in set_food:
# for s_d in set_day:
# people[s_n][s_f] = list_dict.count(s_f)
# people[s_n][s_d] = list_dict.count(s_d)
def analyze_log(path_to_file):
with open(path_to_file) as csvfile:
return(organize_orders(csvfile))
analyze_log('some csv file with path')
I culd not figure out why I get none returned from addKeysNestedDict() method, since it prints exactly what I want one line before method return
Change the function to:
def addKeysNestedDict(dictionary, keys):
# print(dictionary)
if len(keys) > 1:
if keys[0] not in dictionary.keys():
dictionary[keys[0]] = {'meals': '', 'weekdays': ''}
print('inside addKeys IF: ')
print(dictionary)
addKeysNestedDict(dictionary, keys[1:])
else:
dictionary[keys[0]] = {'meals': '', 'weekdays': ''}
print('inside addKeys: ')
print(dictionary) # PRINTS EXPECTED VALUES
return dictionary
Notice that I moved the return dictionary statement out of the specific branch, which causes both of your branches to return the dictionary you're building in your function.
I store data in csv file as follwing:
row = dict_items([('Time ': '2017-12-01T13:54:04'), ('Energy [kWh]': '0.01'), ('Voltage [V]': '221.64'), ('Current [A]': '0.08')])
Now i want to store it like that:
('Time ': '2017-12-01T13:54:04', 'Energy [kWh]': '0.01'),
('Time ': '2017-12-01T13:54:04','Voltage [V]': '221.64'),
('Time ': '2017-12-01T13:54:04','Current [A]': '0.08')])
so i wrote this code bellow and i define
Device=""
Value=""
for key, value in row.items():
print(row.items())
if key == 'Time':
Timevalue = value
print(Zeitvalue)
Device = key
Value = value
doc = {'Device':Device, 'Measure':Value , 'Time':Timevalue }
i got this error:
NameError: name 'Timevalue' is not defined
How can i make the Timevalue variable globale to avoid this Problem?
Thank you
That ('Time ': '2017-12-01T13:54:04', 'Energy [kWh]': '0.01') syntax is not valid Python. Assuming you actually want a list of dictionaries, it's not too hard to perform that conversion.
You first need to grab the time stamp so it can be combined with each of the other items, and then you can drop it from the dict to make it easier to copy the remaining items to the new structure. Note that this modifies the original dict passed to the function. If you don't want that, you can either make a copy of the passed-in dict, or put an if test in the loop that copies the data to the new structure so that the time item is skipped.
def convert(old):
time_key = 'Time '
# Save the time
time_item = (time_key, old[time_key])
# Add remove it
del old[time_key]
# Copy remaining items to new dicts and save them in a list
return [dict([time_item, item]) for item in old.items()]
row = {
'Time ': '2017-12-01T13:54:04',
'Energy [kWh]': '0.01',
'Voltage [V]': '221.64',
'Current [A]': '0.08',
}
new_data = convert(row)
for d in new_data:
print(d)
output
{'Time ': '2017-12-01T13:54:04', 'Energy [kWh]': '0.01'}
{'Time ': '2017-12-01T13:54:04', 'Voltage [V]': '221.64'}
{'Time ': '2017-12-01T13:54:04', 'Current [A]': '0.08'}
Here's how to do it if you don't want to mutate or copy the original dict:
def convert(old):
time_key = 'Time '
# Save the time
time_item = (time_key, old[time_key])
# Copy other items to new dicts and save them in a list
return [dict([time_item, (key, val)])
for key, val in old.items() if key != time_key]
Note that this is less efficient because it has to test every key to ensure it's not the time key.
To save the data in a list of OrderedDicts, we need to change the logic slightly. We also need to create the OrderedDicts properly so that the items are in the desired order.
from collections import OrderedDict
from pprint import pprint
def convert(row):
time_key = 'Time '
time_value = row[time_key]
new_data = []
for key, val in row.items():
if key == time_key:
continue
new_data.append(OrderedDict(Device=key, Measure=val, Time=time_value))
return new_data
row = {
'Time ': '2017-12-01T13:54:04', 'Energy [kWh]': '0.01',
'Voltage [V]': '221.64', 'Current [A]': '0.08'
}
new_data = convert(row)
pprint(new_data)
output
[OrderedDict([('Device', 'Energy [kWh]'),
('Measure', '0.01'),
('Time', '2017-12-01T13:54:04')]),
OrderedDict([('Device', 'Voltage [V]'),
('Measure', '221.64'),
('Time', '2017-12-01T13:54:04')]),
OrderedDict([('Device', 'Current [A]'),
('Measure', '0.08'),
('Time', '2017-12-01T13:54:04')])]
I am checking the key in dictionary, if it contains space remove it.
def query_combination(sentence,mydict):
for key in mydict.keys():
if key == 'key':
pass
else:
print 'key is : ',key
if " " in key:
temp = key
key = key.replace(' ',"")
print 'new key : ',key
sentence = sentence.replace(temp ,key)
print 'new sentence : ',sentence
print mydict
mydict = {'films': {'match': ['Space', 'Movie', 'six', 'two', 'one']}, u'Popeye Doyle': {'score': 100, 'match': [u'People', 'heaven', 'released']}}
sentence ='What films featured the character Popeye Doyle'
combination = query_combination(sentence,mydict)
I could not dynamically change the new key value to mydict. Any suggestion much appreciable
If you get a string out of the dictionary, and then change it and make a new string, the dictionary won't know about it; you can add a new entry to the dictionary and remove the old one:
if " " in key:
newkey = key.replace(' ',"")
mydict[newkey] = mydict[key]
del mydict[key]
print 'new key : ', newkey
You could try this
def query_combination(sentence,mydict):
for key in mydict.iterkeys():
if " " in key:
temp = key
mydict[key.replace(" ","")] = mydict[key] # create new key
del mydict[key] # delete old key
sentence = sentence.replace(temp ,key)
Another solution in one line would be
mydict[key.replace(" ","")] = mydict.pop(key)
key = key.replace(' ',"") does not affect the actual key in the dictionary, it is changing a copy of that key. You need to add the value to the dictionary with the new key and remove the old key. Here's one way to do it:
def query_combination(sentence, mydict):
for old_key, new_key in [(key, key.replace(' ', '')) for key in mydict if ' ' in key]:
mydict[new_key] = mydict.pop(old_key)
sentence = sentence.replace(old_key, new_key)
Note, however, that you are replacing the key in the string sentence, but sentence is local to function query_combination(), so the outer scope sentence is unaffected by the replacement. I am not sure if that was what you hoped your code would do, but if it was you could simply return the revised sentence from the function, or include it as an item in the dictionary.
Given that sentence is not actually updated by your function, you can simplify the whole function to a mere dictionary comprehension:
>>> mydict = {'films': {'match': ['Space', 'Movie', 'six', 'two', 'one']}, u'Popeye Doyle': {'score': 100, 'match': [u'People', 'heaven', 'released']}}
>>> mydict = {key.replace(' ', '') : value for key, value in mydict.items()}
>>> mydict
{'films': {'match': ['Space', 'Movie', 'six', 'two', 'one']}, u'PopeyeDoyle': {'score': 100, 'match': [u'People', 'heaven', 'released']}}
I'm struggling with a recursive merge problem.
Let's say I have:
a=[{'name':"bob",
'age':10,
'email':"bob#bla",
'profile':{'id':1, 'role':"admin"}},
{'name':"bob",
'age':10,
'email':"other mail",
'profile':{'id':2, 'role':"dba"},
'home':"/home/bob"
}]
and I need something to recursively merge entries. If value for an existing given key on the same level is different it appends the value to an array.
b = merge(a)
print b
{'name':"bob",
'age':10,
'email':["bob#bla","other mail"],
'profile':{'id':[1,2], 'role'=["admin", "dba"], 'home':"/home/bob"}
I wrote this code:
def merge(items):
merged = {}
for item in items:
for key in item.keys():
if key in merged.keys():
if item[key] != merged[key]:
if not isinstance(merged[key], list):
merged[key] = [merged[key]]
if item[key] not in merged[key]:
merged[key].append(item[key])
else:
merged[key] = item[key]
return merged
The output is:
{'age': 10,
'email': ['bob#bla', 'other mail'],
'home': '/home/bob',
'name': 'bob',
'profile': [{'id': 1, 'role': 'admin'}, {'id': 2, 'role': 'dba'}]}
Which is not what I want.
I can't figure out how to deal with recursion.
Thanks :)
As you iterate over each dictionary in the arguments, then each key and value in each dictionary, you want the following rules:
If there is nothing against that key in the output, add the new key and value to the output;
If there is a value for that key, and it's the same as the new value, do nothing;
If there is a value for that key, and it's a list, append the new value to the list;
If there is a value for that key, and it's a dictionary, recursively merge the new value with the existing dictionary;
If there is a value for that key, and it's neither a list nor a dictionary, make the value in the output a list of the current value and the new value.
In code:
def merge(*dicts):
"""Recursively merge the argument dictionaries."""
out = {}
for dct in dicts:
for key, val in dct.items():
try:
out[key].append(val) # 3.
except AttributeError:
if out[key] == val:
pass # 2.
elif isinstance(out[key], dict):
out[key] = merge(out[key], val) # 4.
else:
out[key] = [out[key], val] # 5.
except KeyError:
out[key] = val # 1.
return out
In use:
>>> import pprint
>>> pprint.pprint(merge(*a))
{'age': 10,
'email': ['bob#bla', 'other mail'],
'home': '/home/bob',
'name': 'bob',
'profile': {'id': [1, 2], 'role': ['admin', 'dba']}}