I am pulling data from a MySQL db which comes in as a list.
'''
my_cursor.execute(sql_str)
my_results = my_cursor.fetchall()
print(my_results)
'''
OUTPUT
[('Allen, Jamie', 2), ('Anderson, Abbie', 1391), ('Anderson, Marcie', 1380), etc.,etc.
Instead of a list, I want to populate a dictionary.
'''
my_cursor.execute(sql_str)
my_result = {}
my_result = [{'Name': row[0], 'ID': row[1]} for row in my_cursor.fetchall()]
print(my_result)
'''
OUTPUT
[{'Name': 'Allen, Jamie', 'ID': 2}, {'Name': 'Anderson, Abbie', 'ID': 1391}, etc.
As you can see I am getting a list of directories not a directory. I really would appreciate your help.
Thanks,
John
You can convert the list to a dictionary like this:
L = [('Allen, Jamie', 2), ('Anderson, Abbie', 1391), ('Anderson, Marcie', 1380)]
D = dict(L)
print(D)
Now the dictionary D looks like this:
{'Allen, Jamie': 2, 'Anderson, Abbie': 1391, 'Anderson, Marcie': 1380}
You're using a list comprehension, so you're getting a list:
[{'Name': row[0], 'ID': row[1]} for row in my_cursor.fetchall()]
if you want a dictionary, use a dictionary comprehension instead:
$ python3 ./t.py
{'Dan': 1, 'John': 2}
data = [
[ "Dan", 1 ],
[ "John", 2 ]
]
print({row[0]: row[1] for row in data})
You could do as follows:
my_cursor.execute(sql_str)
my_result = {}
for x, y in a:
my_result[x] = y
print(my_result)
Depending on what library you're using for SQL, you may actually just be able to pass dictionary = True as an argument when creating your cursor object - I know this at least exists in mysql-connector-python.
my_cursor = conn.cursor(dictionary = True)
You don't say what MySQL package you're using. If it's mysql-connector-python, you can use my_cursor.description or my_cursor.column_names:
colnames = my_cursor.column_names
# Alternate for older library versions: colnames = [desc[0] for desc in my_cursor.description]
my_results = [dict(zip(colnames,record)) for record in my_results]
Related
I have created the following dictionary:
Book_list={
'Fiction': {1001: ['Pride and Prejudice', 'available'],
1002: ['Fahrenheit 451', 'available']},
'Horror': {2001: ['House of leaves', 'available'],
2002: ['The Shinking', 'available']}}
now I want to store the status that is "available" in a variable with its key so that it can be used further for delete or update.
So the output I mean is like:
status={1001:available,1002:available,2001:available,2002:available}
Please help me by telling that how could I get this output.
One approach is to use a dictionary comprehension:
rs = {ii : status for category in Book_list.values() for ii, (name, status) in category.items() if status == "available"}
print(rs)
Output
{1001: 'available', 1002: 'available', 2001: 'available', 2002: 'available'}
The above is equivalent to the followings nested for loops:
for category in Book_list.values():
for ii, (name, status) in category.items():
if status == "available":
rs[ii] = status
For understanding the unpacking expressions such as:
# _, category
# ii, (name, status)
you could read this link. For a general introduction to Python's data structures I suggest reading the documentation.
def receive_available_books(Book_list):
status = {}
for cat in Book_list.values():
for code, book in cat.items():
status[code] = book[1]
return status
Output:
{1001: 'available', 1002: 'available', 2001: 'available', 2002: 'available'}
Using Python 3.10's structural pattern matching, maybe not super appropriate/helpful for this, but I just wanted to try it :-)
rs = {}
for category in Book_list.values():
for item in category.items():
match item:
case ii, [_, 'available' as status]:
rs[ii] = status
(code adapted from Dani's)
With this code you get almost exactly the output you want:
d={}
for a in Book_list.values():
for x,y in a.items():
d[x]=y[1]
print("status=", d)
You could also, of course, assign d to your a status variable.
This code just creates first an empty d as dict and then fills it with data and finally prints it. To fill d with data, a, x and y take different values while walking (iterating) over your object:
a: For example {1001: ['Pride and Prejudice', 'available'], 1002: ['Fahrenheit 451', 'available']}
x: For example 1001
y: For example ['Pride and Prejudice', 'available']
y[1] would then be 'available'
Basically I have a list
data_list = [
'__att_names' : [
['id', 'name'], --> "__t_idx": 0
['location', 'address'] --> "__t_idx": 1
['random_key1', 'random_key2'] "__t_idx": 2
['random_key3', 'random_key4'] "__t_idx": 3
]
"__root": {
"comparables": [
"__g_id": "153564396",
"__atts": [
1, --> This would be technically __att_names[0][1]
'somerandomname',--> This would be technically __att_names[0][2]
{
"__atts": [
'location_value', --> This would be technically __att_names[1][1]
'address_value',--> This would be technically __att_names[1][2]
"__atts": [
]
"__t_idx": 1 --> It can keep getting nested.. further and further.
]
"__t_idx": 1
}
{
"__atts": [
'random_key3value'
'random_key3value'
]
"__t_idx": 3
}
{
"__atts": [
'random_key1value'
'random_key2value'
]
"__t_idx": 2
}
],
"__t_idx": 0 ---> This maps to the first item in __att_names
]
}
]
My desired output in this case would be
[
{
'id': 1,
'name': 'somerandomname',
'location': 'address_value',
'random_key1': 'random_key1value',
'random_key2': 'random_key2value',
'random_key3': 'random_key3value',
'random_key4': 'random_key4value',
}
]
I was able to get it working for the first few nested fields for __att_names, but my code was getting really long and wonky when I was doing nested and it felt really repetitive.
I feel like there is a neater and recursive way to solve this.
This is my current approach:
As of now the following code does take care first the very first nested object..
payload_names = data_list['__att_names']
comparable_data = data_list['__root']['comparables']
output_arr = []
for items in comparable_data[:1]:
output = {}
index_number = items.get('__t_idx')
attributes = items.get('__atts')
if attributes:
recursive_function(index_number, attributes, payload_names, output)
output_arr.append(output)
def recursive_function(index, attributes, payload_names, output):
category_location = payload_names[index]
for index, categories in enumerate(category_location):
output[categories] = attributes[index]
if type(attributes[index]) == dict:
has_nested_index = attributes[index].get('__t_idx')
has_nested_attributes = attributes[index].get('__atts')
if has_nested_attributes and has_nested_index:
recursive_function(has_nested_index, has_nested_attributes, payload_names, output)
else:
continue
To further explain given example:
[ {
'id': 1,
'name': 'somerandomname',
'location': 'address_value',
'random_key1': 'random_key1value',
'random_key2': 'random_key2value',
'random_key3': 'random_key3value',
'random_key4': 'random_key4value',
}
]
Specifically 'location': 'address_value', The value 'address_value' was derived from the array of comparables key which has the array of dictionaries with key value pair. i.e __g_id and __atts and also __t_idx note some of them might not have __g_id but when there is a key __atts there is also __t_idx which would map the index with array in __att_names
Overally
__att_names are basically all the different keys
and all the items within comparables -> __atts are basically the values for the key names in __att_names.
__t_idx helps us map __atts array items to __att_names and create a dictionary key-value as outcome.
If you want to restructure a complex JSON object, my recommendation is to use jq.
Python package
Oficial website
The data you present is really confusing and ofuscated, so I'm not sure what exact filtering your case would require. But your problem involves indefinitely nested data, for what I understand. So instead of a recursive function, you could make a loop that unnests the data into the plain structure that you desire. There's already a question on that topic.
You can traverse the structure while tracking the __t_idx key values that correspond to list elements that are not dictionaries:
data_list = {'__att_names': [['id', 'name'], ['location', 'address'], ['random_key1', 'random_key2'], ['random_key3', 'random_key4']], '__root': {'comparables': [{'__g_id': '153564396', '__atts': [1, 'somerandomname', {'__atts': ['location_value', 'address_value', {'__atts': [], '__t_idx': 1}], '__t_idx': 1}, {'__atts': ['random_key3value', 'random_key4value'], '__t_idx': 3}, {'__atts': ['random_key1value', 'random_key2value'], '__t_idx': 2}], '__t_idx': 0}]}}
def get_vals(d, f = False, t_idx = None):
if isinstance(d, dict) and '__atts' in d:
yield from [i for a, b in d.items() for i in get_vals(b, t_idx = d.get('__t_idx'))]
elif isinstance(d, list):
yield from [i for b in d for i in get_vals(b, f = True, t_idx = t_idx)]
elif f and t_idx is not None:
yield (d, t_idx)
result = []
for i in data_list['__root']['comparables']:
new_d = {}
for a, b in get_vals(i):
new_d[b] = iter([*new_d.get(b, []), a])
result.append({j:next(new_d[i]) for i, a in enumerate(data_list['__att_names']) for j in a})
print(result)
Output:
[
{'id': 1,
'name': 'somerandomname',
'location': 'location_value',
'address': 'address_value',
'random_key1': 'random_key1value',
'random_key2': 'random_key2value',
'random_key3': 'random_key3value',
'random_key4': 'random_key4value'
}
]
I'm trying to convert a list of asset objects that has a list of attribute objects into an array of dictionaries. I'm trying to denormalise the parent/child relationship into a single dictionary.
For the context of my code below I have an asset object with a short_name and the asset object has a list of attributes with an attribute_value and attribute_name.
My intended result is something like this;
[{'name': 'Test', 'attr': 0.9}, {'name': 'Test2', 'attr': 0.5}]
So far I've written it like this;
a_list = []
for a in self.assets:
asset_dict = {'name': a.short_name }
for x in a.attributes:
asset_dict = asset_dict | { x.attribute_name : x.attribute_value }
a_list.append(asset_dict)
This works fine, but I'm looking for a neater solution.
I experimented with;
result = [{'name':a.short_name} | {x.attribute_name : x.attribute_value} for x in a.attribute for a in self.assets]
However, I just can't seem to get the syntax correct and not sure if it is possible to do something like this.
EDIT: Inputs on request (excluding the class definition);
self.assets = [Asset(short_name='Test'),Asset(short_name='Test2')]
self.assets[0].attributes = [Attribute(attribute_name='attr',attribute_value=0.9)]
self.assets[1].attributes = [Attribute(attribute_name='attr',attribute_value=0.5)]
This should work:
a_list = [
{'name': a.short_name} |
{x.attribute_name: x.attribute_value for x in a.attributes}
for a in self.assets
]
or
a_list = [
{'name': a.short_name, **{x.attribute_name: x.attribute_value
for x in a.attributes}}
for a in self.assets
]
I have a list in the below format.
['111: {"id":"de80ca97","data":"test"}', '222: {"id":"8916a167","data":"touch"}', '333: {"id":"12966e98","data":"tap"}']
I need to remove the data column from above list / json and replace it with key value of the list.
I need to transform it to the below structure.
Desired output:
[
{
"score":111,
"id":"de80ca97"
},
{
"score":222,
"id":"8916a167"
},
{
"score":333,
"id":"12966e98"
}
]
Any suggestions or ideas most welcome.
You can use a for loop or you can also use a list comprehension as follows:
>>> import json
>>> l = ['111: {"id":"de80ca97","data":"test"}', '222: {"id":"8916a167","data":"touch"}', '333: {"id":"12966e98","data":"tap"}']
>>> [{'score': int(e.split()[0][:-1]), 'id': json.loads(e.split()[1])['id']} for e in l]
If you prefer to use a for loop:
new_l = []
for e in l:
key, json_str = e.split()
new_l.append({'score': int(key[:-1]), 'id': json.loads(json_str)['id']})
I want to push two dictionaries into a list via for loop. I don't get why it is not working. Could you pls help? :)
result = {}
results = []
for i in range(count): # Count is 2, 2 different dictionaries
result.update({
'workitem_id': str(api_results[i]['workitem_id']),
'workitem_header': api_results[i]['workitem_header'],
'workitem_desc': api_results[i]['workitem_desc'],
'workitem_duration': str(api_results[i]['workitem_duration'])})
print(result) # Shows the two different dictionaries
results.append(result)
print(results) # Shows the list of two dictionaries, but the list contains the last dictionary for 2 times.
Output print(result): {Dictionary 1} , {Dictionary 2}
Output print(results): [{Dictionary 2} , {Dictionary 2}]
The expected output of print(results):
[{Dictionary 1}, {Dictionary 2}]
results = []
for i in range(count): #->Count is 2, 2 different dictionaries
result = {
'workitem_id' :str(api_results[i]['workitem_id']),
'workitem_header':api_results[i]['workitem_header'],
'workitem_desc':api_results[i]['workitem_desc'],
'workitem_duration':str(api_results[i] ['workitem_duration'])}
print(result)
results.append(result)
print(results)
During the second iteration, the .update method will update the first dictionary in the list. This is because it the two dictionary point to the same reference.
A similar example would be:
a = [1, 2, 3]
b = a
a[0] = 'this value is changed in b as well'
print(b)
#['this value is changed in b as well', 2, 3]
Is there any reason that we're not just using a more straightforward for loop?
results = []
for x in api_results:
result = {
'workitem_id': str(x['workitem_id']),
'workitem_header': x['workitem_header'],
'workitem_desc': x['workitem_desc'],
'workitem_duration': str(x['workitem_duration'])
}
results.append(result)
print(results)
You need to do something like
dictionaries = [ # Let this be the list of dictionaries you have (in your api response?)
{
'workitem_id': 1,
'workitem_header': 'header1',
'workitem_desc': 'description2',
'workitem_duration': 'duration2'
},
{
'workitem_id': 2,
'workitem_header': 'header2',
'workitem_desc': 'description2',
'workitem_duration': 'duration2'
}
]
results = []
for dictionary in dictionaries:
results.append(dictionary)
print(results)