How to combine every nth dict element in python list? - python

Input:
list1 = [
{
"dict_a":"dict_a_values"
},
{
"dict_b":"dict_b_values"
},
{
"dict_c":"dict_c_values"
},
{
"dict_d":"dict_d_values"
}
]
Assuming n=2, every two elements have to be combined together.
Output:
list1 = [
{
"dict_a":"dict_a_values",
"dict_c":"dict_c_values"
},
{
"dict_b":"dict_b_values",
"dict_d":"dict_d_values"
}
]
Ideally, it'd be nicer if the output could look like something as follows with an extra layer of nesting:
[
{"dict_combined_ac": {
"dict_a":"dict_a_values",
"dict_c":"dict_c_values"
}},
{"dict_combined_bd": {
"dict_b":"dict_b_values",
"dict_d":"dict_d_values"
}}
]
But since this is really difficult to implement, I'd be more than satisfied with an output looking something similar to the first example. Thanks in advance!
What I've tried so far:
[ ''.join(x) for x in zip(list1[0::2], list1[1::2]) ]
However, I know this doesn't work because I'm working with dict elements and not str elements and when wrapping the lists with str(), every two letters is being combined instead. I'm also unsure of how I can adjust this to be for every n elements instead of just 2.

Given the original list, as in the question, the following should generate the required output:
result_list = list()
n = 2 # number of elements you want in each partition
seen_idx = set()
for i in range(len(list1)): # iterate over all indices
if i not in seen_idx:
curr_idx_list = list() # current partition
for j in range(i, len(list1), n): # generate indices for a combination partition
seen_idx.add(j) # keep record of seen indices
curr_idx_list.append(j) # store indices for current partition
# At this point we have indices of a partition, now combine
temp_dict = dict() # temporary dictionary where we store combined values
for j in curr_idx_list: # iterate over indices of current partition
temp_dict.update(list1[j])
result_list.append(temp_dict) # add to result list
print(result_list, '\n')
# Bonus: change result list into list of nested dictionaries
new_res_list = list()
for elem in result_list: # for each (combined) dictionary in the list, we make new keys
key_names = list(elem.keys())
key_names = [e.split('_')[1] for e in key_names]
new_key = 'dict_combined_' + ''.join(key_names)
temp_dict = {new_key: elem}
new_res_list.append(temp_dict)
print(new_res_list, '\n')
The output is as follows:
[{'dict_a': 'dict_a_values', 'dict_c': 'dict_c_values'}, {'dict_b': 'dict_b_values', 'dict_d': 'dict_d_values'}]
[{'dict_combined_ac': {'dict_a': 'dict_a_values', 'dict_c': 'dict_c_values'}}, {'dict_combined_bd': {'dict_b': 'dict_b_values', 'dict_d': 'dict_d_values'}}]

Related

how can I extract key value pairs from nested JSON with for loops

I have nested json in multilevel lists of dicts
Try to extract key value pairs. I can make separate listst of keys 'code_details' and of values 'url_details' with for loops. But I want to store the result as key:value pairs.
code_details = []
url_details = []
for item in all_content:
code_details.append(item ['code'])
media_details = item ['media']
for i in media_details:
resources_details = i['resources']
for j in resources_details:
url_details.append(j ['url'])
How can I adjust for loops to store key:value pair in a dict {'code':'url'}
json examples
all_content[{"code": "0100410ZWA",
},
{"media": [
{
"containsExplicitContent": true,
"imageType": "Packshot",
"resources": [
{
"expirationDate": "2021-05-20T11:07:00Z",
"format": "ORIGINAL",
"url": "https://media.lingeriestyling.com/marie_jo_l'aventure-lingerie-padded_bra-tom-0120826-pink-0_L_35590.jpg"
}
]}]
code_details example:
['0502570SRE',
'0102649ALF',
'0602640ALF',
'0502572SRE',
'0102646ALF',
'0102570SRE',
'0502571SRE',
'0602570SRE',
'0502640ALF',
'0102640ALF',
'0102574SRE',
'0502642ALF',
'0102576SRE',
'0502641ALF',
'0663321AME',
'0163244AUT',
'0563240AUT',
'0663320AME',
url_details example:
['https://media.lingeriestyling.com/eservices/marie_jo-lingerie-briefs-danae-0502570-red-0_3558237.jpg',
'https://media.lingeriestyling.com/eservices/marie_jo-lingerie-briefs-danae-0502570-red-0_3560011.jpg',
'https://media.lingeriestyling.com/eservices/marie_jo-lingerie-briefs-danae-0502570-red-2_3560012.jpg',
'https://media.lingeriestyling.com/eservices/marie_jo-lingerie-briefs-danae-0502570-red-3_3560013.jpg',
'https://media.lingeriestyling.com/eservices/marie_jo-lingerie-briefs-danae-0502570-red-0_3558965.jpg',
'https://media.lingeriestyling.com/eservices/marie_jo-lingerie-briefs-danae-0502570-red-2_3558970.jpg',
'https://media.lingeriestyling.com/eservices/marie_jo-lingerie-briefs-danae-0502570-red-3_3558976.jpg',
'https://media.lingeriestyling.com/eservices/marie_jo-lingerie-balcony_bra-raia-0102649-multicolour-0_3558308.jpg',
You can create a dict and update it in each iteration. Notice that dict values will be a lists
code_details = {}
for item in all_content:
media_details = item ['media']
# we need to clean it every iteration
url_details = []
for i in media_details:
resources_details = i['resources']
for j in resources_details:
url_details.append(j ['url'])
# here our magic is
code = item ['code'])
code_details[code] = url_details

How to search an object list for a specific attribute value that exists in another list of objects

I have two lists
list1 = [obj1, obj2, ... objn] # len(list1) == N
list2 = [obj1, obj2, ... objm] # len(list2) == M
here's a json representation of obj:
obj = {
"a1": 0,
"a2": 1,
"a3": 2
}
How would I determine the objects from list2 with the same value for obj["a1"] as those in list1? Note it's possible to have multiple occurrences of this. The objects in both lists are formatted the same.
I am only interested in seeing if the value for a certain object attribute from one list can be found in another
For example
list1 = [
{
"a1":0,
"a2":5,
"a3":4
},
{
"a1":2,
"a2":3,
"a3":1
}
...
]
list2 = [
# first object
{
"a1":0,
"a2":3,
"a3":1
},
# second object
{
"a1":3,
"a2":1,
"a3":0
}
...
]
In this case, the first object in list2 contains the same attribute value for obj["a1"] as list1
using pandas you can try this
list1 = [
{
"a1":0,
"a2":5,
"a3":4
},
{
"a1":2,
"a2":3,
"a3":1
}
]
list2 = [
# first object
{
"a1":0,
"a2":3,
"a3":1
},
# second object
{
"a1":3,
"a2":1,
"a3":0
}
]
df1 = pd.DataFrame(list1)
df2 = pd.DataFrame(list2)
a1 = df2[df2['a1'].isin(df1['a1'])]
a1.to_json(orient='records', lines=True)
Check Pandas, you can easily transform the lists to pandas and from there, doing what you need is pretty straight forward.
Index the two pandas with "a1", and then check this link to get intersection
try this; (I have not run the code. but this should work!)
import pandas as pd
df1 = pd.DataFrame(list1)
df2 = pd.DataFrame(list2)
df1.set_index("a1",inplace=True)
df2.set_index("a1",inplace=True)
df1.index.intersection(df2.index)
This should give you the list of intersections
The easiest solution would be to simply go through a double loop:
for obj1 in list1:
for key in obj1:
for obj2 in list2:
if (obj1[key] == obj2[key]):
# Do what you want
You could try looking into different libraries and you may find an answer. However you can play around with dictionaries to achieve the same results. Let me know if you have any issues with this method.
def get_groups(list1, list2):
# assuming the obj are dictionaries in lists 1 & 2
# we store entries into the known_data as
# (category, value) : [obj_references]
# eg known_data = {('a1', 0) : [obj1, obj23, obj3]}
known_data = {}
for obj in list1:
for category, value in obj.items():
key = (category, value)
entry = known_data.get(key, []) or []
entry.append(obj)
known_data[key] = entry
# now we can iterate over list2 and check to see if it shares any keys
# for groups we store our common key (category, value)
# and map to a 2D array [ [list1 objs] , [list2 objs]]
groups = {}
for obj in list2:
for category, value in obj.items():
key = (category, value)
if key not in known_data:
continue
entry = groups.get(key) or [[], [known_data[key]]]
entry[0].append(obj)
groups[key] = entry
return groups

Convert list of lists with strings into list of dictionaries

I'm trying to convert a list of lists with strings like:
[
["amenity=language_school"],
["amenity=sport_school,place=rural", "amenity=sport_school,place=urban"],
["amenity=middle_school,place=city", "amenity=high_school,place=city"]
]
Some lists can have multiple string elements, and some of the string elements can have multiple key:values separated by a , like "amenity=high_school,place=city".
My goal is to get a list of dicts, in which the key of each dict could append in list several values from the same key. Like this:
[
{"amenity":"language_school"},
{"amenity":"sport_school", "place":["rural","urban"]},
{"amenity":["middle_school", "high_school"], "place":"city"}
]
This code works for you. Just if you want any list with just one member to become converted to a simple String it needs to add one line code to it.
Good wishes
output_list = []
for each_row in [
["amenity=language_school"],
["amenity=sport_school,place=rural", "amenity=sport_school,place=urban"],
["amenity=middle_school,place=city", "amenity=high_school,place=city"]
]:
output_list.append(dict())
for each_element in each_row:
for each_def in each_element.split(','):
key, value = each_def.split('=')
if key in output_list[-1]:
if value not in output_list[-1][key]:
output_list[-1][key].append(value)
else:
output_list[-1][key] = [value]
print(output_list)
The output:
[{'amenity': ['language_school']}, {'amenity': ['sport_school'], 'place': ['rural', 'urban']}, {'amenity': ['middle_school', 'high_school'], 'place': ['city']}]
And this is an alternative way with the same output:
output_list = []
for each_row in [
["amenity=language_school"],
["amenity=sport_school,place=rural", "amenity=sport_school,place=urban"],
["amenity=middle_school,place=city", "amenity=high_school,place=city"]
]:
output_list.append(dict())
for each_element in each_row:
for each_def in each_element.split(','):
key, value = each_def.split('=')
content = output_list[-1].get(key, [])
output_list[-1][key] = content + ([value] if value not in content else [])
print(output_list)

Using a list of lists as a lookup table and updating a value in new list of lists

I have an application that creates a list of lists. The second element in the list needs to be assigned using lookup list which also consists of a list of lists.
I have used the "all" method to match the values in the list. If the list value exists in the lookup list, it should update the second position element in the new list. However this is not the case. The == comparative yields a False match for all elements, even though they all exist in both lists.
I have also tried various combinations of index finding commands but they are not able to unpack the values of each list.
My code is below. The goal is to replace the "xxx" values in the newData with the numbers in the lookupList.
lookupList= [['Garry','34'],['Simon', '24'] ,['Louise','13'] ]
newData = [['Louise','xxx'],['Garry', 'xxx'] ,['Simon','xxx'] ]
#Matching values
for i in newData:
if (all(i[0] == elem[0] for elem in lookupList)):
i[1] = elem[1]
You can't do what you want with all(), because elem is not a local variable outside of the generator expression.
Instead of using a list, use a dictionary to store the lookupList:
lookupDict = dict(lookupList)
and looking up matches is a simple constant-time (fast) lookup:
for entry in newData:
if entry[0] in lookupDict:
entry[1] = lookupDict[entry[0]]
you should use dictionaries instead, like this:
lookupList = newData = {}
old_lookupList = [['Garry','34'],['Simon', '24'] ,['Louise','13'] ]
old_newData = [['Louise','xxx'],['Garry', 'xxx'] ,['Simon','xxx'] ]
#convert into dictionary
for e in old_newData: newData[e[0]] = e[1]
for e in old_lookupList: lookupList[e[0]] = e[1]
#Matching values
for key in lookupList:
if key in newData.keys():
newData[key]=lookupList[key]
#convert into list
output_list = []
for x in newData:
output_list.append([x, newData[x]])
I like the following code since it can be tweaked and used in different ways:
lookupList= [ ['Garry', '34'],['Simon', '24'] ,['Louise', '13'] ]
newData = [ ['Louise', 'xxx'],['Garry', 'xxx'], ['Peter', 'xxx'] ,['Simon', 'xxx'] ]
#Matching values
for R in newData:
for i in range(0, len(lookupList) + 1):
try:
if lookupList[i][0] == R[0]:
R[1] = lookupList[i][1]
break
except:
print('Lookup fail on record:', R)
print(newData)

List of dicts: Getting list of matching dictionary based on id

I'm trying to get the matching IDs and store the data into one list. I have a list of dictionaries:
list = [
{'id':'123','name':'Jason','location': 'McHale'},
{'id':'432','name':'Tom','location': 'Sydney'},
{'id':'123','name':'Jason','location':'Tompson Hall'}
]
Expected output would be something like
# {'id':'123','name':'Jason','location': ['McHale', 'Tompson Hall']},
# {'id':'432','name':'Tom','location': 'Sydney'},
How can I get matching data based on dict ID value? I've tried:
for item in mylist:
list2 = []
row = any(list['id'] == list.id for id in list)
list2.append(row)
This doesn't work (it throws: TypeError: tuple indices must be integers or slices, not str). How can I get all items with the same ID and store into one dict?
First, you're iterating through the list of dictionaries in your for loop, but never referencing the dictionaries, which you're storing in item. I think when you wrote list[id] you mean item[id].
Second, any() returns a boolean (true or false), which isn't what you want. Instead, maybe try row = [dic for dic in list if dic['id'] == item['id']]
Third, if you define list2 within your for loop, it will go away every iteration. Move list2 = [] before the for loop.
That should give you a good start. Remember that row is just a list of all dictionaries that have the same id.
I would use kdopen's approach along with a merging method after converting the dictionary entries I expect to become lists into lists. Of course if you want to avoid redundancy then make them sets.
mylist = [
{'id':'123','name':['Jason'],'location': ['McHale']},
{'id':'432','name':['Tom'],'location': ['Sydney']},
{'id':'123','name':['Jason'],'location':['Tompson Hall']}
]
def merge(mylist,ID):
matches = [d for d in mylist if d['id']== ID]
shell = {'id':ID,'name':[],'location':[]}
for m in matches:
shell['name']+=m['name']
shell['location']+=m['location']
mylist.remove(m)
mylist.append(shell)
return mylist
updated_list = merge(mylist,'123')
Given this input
mylist = [
{'id':'123','name':'Jason','location': 'McHale'},
{'id':'432','name':'Tom','location': 'Sydney'},
{'id':'123','name':'Jason','location':'Tompson Hall'}
]
You can just extract it with a comprehension
matched = [d for d in mylist if d['id'] == '123']
Then you want to merge the locations. Assuming matched is not empty
final = matched[0]
final['location'] = [d['location'] for d in matched]
Here it is in the interpreter
In [1]: mylist = [
...: {'id':'123','name':'Jason','location': 'McHale'},
...: {'id':'432','name':'Tom','location': 'Sydney'},
...: {'id':'123','name':'Jason','location':'Tompson Hall'}
...: ]
In [2]: matched = [d for d in mylist if d['id'] == '123']
In [3]: final=matched[0]
In [4]: final['location'] = [d['location'] for d in matched]
In [5]: final
Out[5]: {'id': '123', 'location': ['McHale', 'Tompson Hall'], 'name': 'Jason'}
Obviously, you'd want to replace '123' with a variable holding the desired id value.
Wrapping it all up in a function:
def merge_all(df):
ids = {d['id'] for d in df}
result = []
for id in ids:
matches = [d for d in df if d['id'] == id]
combined = matches[0]
combined['location'] = [d['location'] for d in matches]
result.append(combined)
return result
Also, please don't use list as a variable name. It shadows the builtin list class.

Categories