Assuming I have the following:
[
{"sku": "ZZZ", "name":"None name","shelf": 10},
{"sku": "AAA", "name":"One name","shelf": 10},
{"sku": "BBB", "name":"The name", "shelf": None},
{"sku": "CCC", "name":"A name"}
]
I am trying to find the best (most elegant maybe) way to:
Add "shelf": 'Default' when missing or set to None
Split the list per shelf, so the one above should give out two named lists: one for Default and one for '10'
This is the desired output:
[
{"10":[
{"sku": "ZZZ", "name":"None name"},
{"sku": "AAA", "name":"One name"}]
},
{"default":[
{"sku": "CCC", "name":"A name"},
{"sku": "BBB", "name":"The name"]
}
]
Using pydash.collections.for_each(initial_list,reorganize) I can sort the first problem, but I am not sure how to deal with the second.
def reorganize(x):
if 'shelf' not in x: x['shelf'] = 'default'
if x['shelf'] is None: x['shelf'] = 'default'
I also do not thing this is the best way to solve the problem.
Reason for pivoting the list is because I need to call an API which needs the shelf as parameter and cannot accept multiple shelf at the same time (but accepts multiple SKUs).
input_list = [
{"sku": "ZZZ", "name":"None name","shelf": 10},
{"sku": "AAA", "name":"One name","shelf": 10},
{"sku": "BBB", "name":"The name", "shelf": None},
{"sku": "CCC", "name":"A name"}
]
output_dict = {}
for d in input_list:
output_dict.setdefault(d.pop('shelf', 'default') or 'default', []).append(d)
output_dict is:
{10: [{'sku': 'ZZZ', 'name': 'None name'}, {'sku': 'AAA', 'name': 'One name'}], 'default': [{'sku': 'BBB', 'name': 'The name'}, {'sku': 'CCC', 'name': 'A name'}]}
Let's explain the code:
pop returns the shelf entry and removes it from the dictionary;
if shelf is not present, pop returns the default value, i.e. its
second (optional) argument ('default' in this case). The or is
used to handle the cases when shelf is present, but with a None
or '' value: in this case, default is used.
setdefault returns the value of the dictionary with key equal to
the first argument, or it returns the second argument if the key is
not present.
append adds the current dictionary (with shelf entry removed by pop) to the list corresponding to its shelf value.
lst = [
{"sku": "ZZZ", "name":"None name","shelf": 10},
{"sku": "AAA", "name":"One name","shelf": 10},
{"sku": "BBB", "name":"The name", "shelf": None},
{"sku": "CCC", "name":"A name"}
]
lst2 = list()
for dct in lst:
v = dct.pop("shelf", None) or "default"
for d in lst2:
if d.get(v):
d[v].append(dct)
break
else:
lst2.append({v: [dct]})
print(lst2)
Output:
[{10: [{'sku': 'ZZZ', 'name': 'None name'},
{'sku': 'AAA', 'name': 'One name'}]},
{'default': [{'sku': 'BBB', 'name': 'The name'},
{'sku': 'CCC', 'name': 'A name'}]}]
Breaking it down:
Define a list, lst2, to become the output list.
Iterate through the dictionaries of lst, and define a variable, v,
to check if the value of the soon-to-be-created-dictionary should be the value of the current dictionary's "shelf" key, or "default".
Iterate through each dictionary of the lst2. If coresponding key are found, append the dictionary to the key of the lst2.
my take on the question, with pandas:
df = pd.DataFrame([
{"sku": "ZZZ", "name":"None name","shelf": 10},
{"sku": "AAA", "name":"One name","shelf": 10},
{"sku": "BBB", "name":"The name", "shelf": None},
{"sku": "CCC", "name":"A name"}
])
df.shelf = df.shelf.fillna('default')
for shelf, skus in df.groupby('shelf').sku.apply(list).items():
print(shelf, "=>", skus)
>>>
10.0 => ['ZZZ', 'AAA']
default => ['BBB', 'CCC']
Related
I have dictionary like that:
dic={'61': {'NAME': 'John', 'LASTNAME': 'X', 'EMAIL': 'X#example.com', 'GRADE': '99'}, '52': {'NAME': 'Jennifer', 'LASTNAME': 'Y', 'EMAIL': 'Y#example.com', 'GRADE': '98'}}
obj = json.dumps(dic,indent=3)
print(obj)
I want to create Json for some values.
{
"NAME": "John",
"LASTNAME": "X",
,
"NAME": "Jennifer",
"LASTNAME": "Y"
}
Any idea for help?
If I understand correctly you want to keep the values of your original data without the indices and also filter out some of them (keep only "NAME" and "LASTNAME"). You can do so by using a combination of dictionary and list comprehensions:
array = [{k:v for k,v in d.items()if k in ("NAME","LASTNAME")} for d in dic.values()]
This creates the following output:
>>> array
[{'NAME': 'John', 'LASTNAME': 'X'}, {'NAME': 'Jennifer', 'LASTNAME': 'Y'}]
a =[{
"id":"1",
"Name":'BK',
"Age":'56'
},
{
"id":"1",
"Sex":'Male'
},
{
"id":"2",
"Name":"AK",
"Age":"32"
}]
I have a list of dictionary with a person information split in multiple dictionary as above for ex above id 1's information is contained in first 2 dictionary , how can i get an output of below
{1: {'Name':'BK','Age':'56','Sex':'Male'}, 2: { 'Name': 'AK','Age':'32'}}
You can use a defaultdict to collect the results.
from collections import defaultdict
a =[{ "id":"1", "Name":'BK', "Age":'56' }, { "id":"1", "Sex":'Male' }, { "id":"2", "Name":"AK", "Age":"32" }]
results = defaultdict(dict)
key = lambda d: d['id']
for a_dict in a:
results[a_dict.pop('id')].update(a_dict)
This gives you:
>>> results
defaultdict(<class 'dict'>, {'1': {'Name': 'BK', 'Age': '56', 'Sex': 'Male'}, '2': {'Name': 'AK', 'Age': '32'}})
The defaultdict type behaves like a normal dict, except that when you reference an unknown value, a default value is returned. This means that as the dicts in a are iterated over, the values (except for id) are updated onto either an existing dict, or an automatic newly created one.
How does collections.defaultdict work?
Using defaultdict
from collections import defaultdict
a = [{
"id": "1",
"Name": 'BK',
"Age": '56'
},
{
"id": "1",
"Sex": 'Male'
},
{
"id": "2",
"Name": "AK",
"Age": "32"
}
]
final_ = defaultdict(dict)
for row in a:
final_[row.pop('id')].update(row)
print(final_)
defaultdict(<class 'dict'>, {'1': {'Name': 'BK', 'Age': '56', 'Sex': 'Male'}, '2': {'Name': 'AK', 'Age': '32'}})
You can combine 2 dictionaries by using the .update() function
dict_a = { "id":"1", "Name":'BK', "Age":'56' }
dict_b = { "id":"1", "Sex":'Male' }
dict_a.update(dict_b) # {'Age': '56', 'Name': 'BK', 'Sex': 'Male', 'id': '1'}
Since the output the you want is in dictionary form
combined_dict = {}
for item in a:
id = item.pop("id") # pop() remove the id key from item and return the value
if id in combined_dict:
combined_dict[id].update(item)
else:
combined_dict[id] = item
print(combined_dict) # {'1': {'Name': 'BK', 'Age': '56', 'Sex': 'Male'}, '2': {'Name': 'AK', 'Age': '32'}}
from collections import defaultdict
result = defaultdict(dict)
a =[{ "id":"1", "Name":'BK', "Age":'56' }, { "id":"1", "Sex":'Male' }, { "id":"2", "Name":"AK", "Age":"32" }]
for b in a:
result[b['id']].update(b)
print(result)
d = {}
for p in a:
id = p["id"]
if id not in d.keys():
d[id] = p
else:
d[id] = {**d[id], **p}
d is the result dictionary you want.
In the for loop, if you encounter an id for the first time, you just store the incomplete value.
If the id is in the existing keys, update it.
The combination happens in {**d[id], **p}
where ** is unpacking the dict.
It unpacks the existing incomplete dict associated withe the id and the current dict, then combine them into a new dict.
There are two lists:
customer_list = ["A7", "A8", "A9", "A10", "A11"]
customer_index = ["8", "9", "10", "11", "12"]
The goal is to create the following:
final_list = [
{
"kind": "report#variable",
"type": "A7",
"value": line[8]}
,
{
"kind": "report#variable",
"type": "A8",
"value": line[9]}
,
{
"kind": "report#variable",
"type": "A9",
"value": line[10]}
,
{
"kind": "report#variable",
"type": "A10",
"value": line[11]}
,
{
"kind": "report#variable",
"type": "A11",
"value": line[12]}
]
I tried to use the following Python code, but it did not work:
def create_final_list(list_1, list_2):
new_list = []
list_prefix = '{"kind": "report#variable",'
for num in list_1:
for val in list_2:
list_1_num = ' "type": ' + num
list_2_val = ' "value": ' + val
new_list.append(list_prefix + list_1_num + list_2_val)
return new_list
How does one automatically create a list of Dictionaries based upon two lists of equal length and the desired format as in the above example?
This is not a JSON; but a list of dictionaries which you create in a list-comprehension with zip():
customer_list = ["A7", "A8", "A9", "A10", "A11"]
customer_index = ["8", "9", "10", "11", "12"]
line = [1,2,3,4,5,6,7,8,9,101,11,12,13,14] # assume this `line` list
res = [{"kind": "report#variable", "type": x, "value": line[int(y)]} for x, y in zip(customer_list, customer_index)]
As is in the comments, you can then do:
json.dumps(res)
..to convert res to a JSON string.
Since pandas is tagged, adding another way using a dataframe and groupby:
df = pd.DataFrame({"kind": "report#variable","type":customer_list,"value":customer_index})
final = [g.droplevel(0).to_dict() for _,g in df.stack().groupby(level=0)]
[{'kind': 'report#variable', 'type': 'A7', 'value': '8'},
{'kind': 'report#variable', 'type': 'A8', 'value': '9'},
{'kind': 'report#variable', 'type': 'A9', 'value': '10'},
{'kind': 'report#variable', 'type': 'A10', 'value': '11'},
{'kind': 'report#variable', 'type': 'A11', 'value': '12'}]
Try
lis = []
for i in range(len(customer_index)):
dic = {"type" : customer_list[i], "value" : customer_index[i]}
lis.append(dic)
This outputs
[{'type': 'A7', 'value': '8'},
{'type': 'A8', 'value': '9'},
{'type': 'A9', 'value': '10'},
{'type': 'A10', 'value': '11'},
{'type': 'A11', 'value': '12'}]
As in your code, if you want line[8], do line[customer_index[i]] instead of customer_index[i] during dictionary initialization. Also, add 1 more key of kind in the dictionary, as per your requirement.
The above code works only if both customer_list and customer_index are of equal length, because the loop iterates n number of times, where n is the equal length of the list.
I tried to find the solution everywhere but I couldn't find the way to solve this problem. Suppose I have multiple dictionaries in a list:
[
{"Type": "A", "Name": "Sam"},
{"Type": "A", "Name": "Apple"},
{"Type": "B", "Name": "Sam"},
{"Type": "C", "Name": "Apple"},
{"Type": "C"}
]
What I need are the dictionaries that have 'Type' == 'A'.
The result I am trying to get is:
[{"Type": "A", "Name": "Sam"}, {"Type": "A", "Name": "Apple"}]
Is there any way I could achieve this? Any help or any direction into solving this problem would be great.
Go through your list and take all dictionaries with a Type of A:
>>> data = [{"Type": "A", "Name": "Sam"},{"Type":"A", "Name":"Apple"},{"Type": "B", "Name": "Sam"},{"Type":"C", "Name":"Apple"},{"Type":"C"}]
>>> [d for d in data if d.get('Type') == 'A']
[{'Name': 'Sam', 'Type': 'A'}, {'Name': 'Apple', 'Type': 'A'}]
Using dict.get() ensures that it works for dicts without the key Type:
data = [{"Type": "A", "Name": "Sam"},
{"Type":"A", "Name":"Apple"},
{"Type": "B", "Name": "Sam"},
{"Type":"C", "Name":"Apple"},
{"Type":"C"},
{}]
>>> [d for d in data if d.get('Type') == 'A']
[{'Name': 'Sam', 'Type': 'A'}, {'Name': 'Apple', 'Type': 'A'}]
because:
get(key[, default])
Return the value for key if key is in the dictionary, else default. If default is not given, it defaults to None, so that this method never raises a KeyError.
>>> a
[{'Type': 'A', 'Name': 'Sam'}, {'Type': 'A', 'Name': 'Apple'}, {'Type': 'B', 'Name': 'Sam'}, {'Type': 'C', 'Name': 'Apple'}, {'Type': 'C'}]
>>> b = [x for x in a if x['Type']=='A']
>>> b
[{'Type': 'A', 'Name': 'Sam'}, {'Type': 'A', 'Name': 'Apple'}]
[d for d in d_list if d.get('Type') == 'A']
This is almost definitely not the most pythonic way of doing it, but if you need a quick and dirty solution, I believe it works.
def filterDictionaries(dictionaries, type):
filteredDicts = []
for dict in dictionaries:
if 'Type' in dict:
if dict['Type] == type:
filteredDicts += dict
return filteredDicts
I'm trying to create what I think is a 'projection' from a larger dictionary space onto a smaller dimension space. So, if I have:
mine = [
{"name": "Al", "age": 10},
{"name": "Bert", "age": 15},
{"name": "Charles", "age": 17}
]
I'm trying to find a functional expression to return only:
[
{"name": "Al"},
{"name": "Bert"},
{"name": "Charles"}
]
I've tried...
>>> filter(lambda x: x['name'],mine)
[{'age': 10, 'name': 'Al'}, {'age': 15, 'name': 'Bert'}, {'age': 17, 'name': 'Charles'}]
>>> map(lambda x : x['name'],mine)
['Al', 'Bert', 'Charles']
But seem to still be missing the right function. I know how to do it with a list comprehension, but would like to do learn how to do this functionally.
Sounds like a job for list comprehensions, whether you like them or not.
>>> [{"name": d["name"]} for d in mine]
[{'name': 'Al'}, {'name': 'Bert'}, {'name': 'Charles'}]
The solution without a list comprehension would require an additional function definition:
def project(key, d):
return {k: d[k]}
map(partial(project, "name"), mine)
Or a lambda (yuck):
map(lambda d: {"name": d["name"]}, mine)
CODE:
print([{'name': d['name']} for d in mine])
OUTPUT:
[{'name': 'Al'}, {'name': 'Bert'}, {'name': 'Charles'}]
In case we want to preserve more than one key:
input_dicts = [
{"name": "Al", "age": 40, "level": "junior"},
{"name": "Bert", "age": 30, "level": "mid"},
{"name": "Charles", "age": 20, "level": "senior"}
]
selected_keys = ("name", "level")
[
{key: value for key, value in a_dict.items() if key in selected_keys}
for a_dict in input_dicts
]
[{'name': 'Al', 'level': 'junior'},
{'name': 'Bert', 'level': 'mid'},
{'name': 'Charles', 'level': 'senior'}]