Accessing Elements in a nested list in python - python-3.x

I am a newbie in python and I have data in a nested list in this format. I want to do something if the value of age in the dictionaries are equal.
[
[
{
"name":"AAAAA",
"age":"12",
"class":"box"
}
],
[
{
"name":"DDDD",
"age":"10",
"class":"space"
}
],
[
{"name":"BBBB"},
{"age":"16"},
{"class":"cage"}
],
[
{
"name":"EEEE",
"age":"20",
"class":"sage"
}
],
]

The main idea is to store all the ages in a list, get list of duplicate ages and access the dictionary using that list
age_list = []
for l in dict_list:
temp_dict = l[0]
age_list.append(temp_dict["age"])
# get set of duplicates in age list
dup_ages = set([x for x in l if l.count(x) > 1])
for index, age in enumerate(age_list):
for dup_age in dup_ages: # do something for a given duplicate age
if dup_age == age:
dict_list[index] # do something in the dict

Related

Replace value of a specific key in json file for multiple files

I am preparing a test data for the feature testing .
I have 1000 json file with same below structure in local folder .
I need to replace two key from all the places and create 1000 different json .
Key that needs to be replaced is
"f_ID": "80510926" and "f_Ctb": "10333"
"f_ID": "80510926" appears in all the array but "f_Ctb": "10333" appear only once .
The replaced value can be running number 1 to 100 in all files .
Can some one suggest how we can do this python to create 1000 files
{
"t_A": [
{
"f_ID": "80510926",
"f_Ctb": "10333",
"f_isPasswordProtected": "False"
}
],
"t_B": [
{
"f_ID": "80510926",
"f_B_Company_ID": "10333",
"f_B_ID": "1",
"f_ArriveDate": "20151001 151535.775"
},
{
"f_ID": "80510926",
"f_B_Company_ID": "10333",
"f_B_ID": "1700",
"f_ArriveDate": "20151001 151535.775"
}
],
"t_C": [
{
"f_ID": "80510926",
"f_Set_Code": "TRBC ",
"f_Industry_Code": "10 ",
"f_InsertDate": "20151001 151535.775"
},
],
"t_D": [
{
"f_ID": "80510926",
"f_Headline": "Global Reinsurance: Questions and themes into Monte Carlo",
"f_Synopsis": ""
}
]
}
here is the solution run in the folder where you have 1000 json files.
It will read all the json files and replace the f_ID and f_Ctb with the count and write the file with same file name in output folder.
import os
import json
all_files = os.listdir()
json_files = {f: f for f in all_files if f.endswith(".json")}
json_files_keys = list(json_files.keys())
json_files_keys.sort()
OUTPUT_FOLDER = "output"
if not os.path.exists(OUTPUT_FOLDER):
os.mkdir(OUTPUT_FOLDER)
for file_name in json_files_keys:
f_read = open(file_name, "r").read()
data = json.loads(f_read)
output_data = {}
count = 1
for key, val_list in data.items():
for nest_dict in val_list:
if "f_ID" in nest_dict:
nest_dict["f_ID"] = count
if "f_Ctb" in nest_dict:
nest_dict["f_Ctb"] = count
if key in output_data:
output_data[key].append(nest_dict)
else:
output_data[key] = [nest_dict]
else:
output_data[key] = val_list
count += 1
output_file = open(f"{OUTPUT_FOLDER}/{file_name}", "w")
output_file.write(json.dumps(output_data))
output_file.close()

Find values from the Nested Dict

Something I'm doing incorrect, but I got data with list of nested dict, I need to pull the value and store in the output dict.
Data:
[{
"encoding":"json",
"result": {
"aclList":[
{
"chipName":"",
"countersEnabled":true,
"countersIncomplete":false,
"dynamic":false,
"name":"FW-RULE-IN",
"readonly":false,
"sequence":[
{
"convertSymbols":true,
"sequenceNumber":1,
"text":"TEST: RULE 1"
},
{
"convertSymbols":true,
"sequenceNumber":2,
"text":"TEST: RULE 2"
},
{
"convertSymbols":true,
"sequenceNumber":3,
"text":"TEST: RULE 3"
},]}]}}]
Like to put sequenceNumber, text values in to output result in Dict.
here is the code I got, but not working, how to fix it?
def parse_data(data):
rules = {}
acllist = []
for k, v in data[0].items():
for h, j in k['result'].items():
for i in h['aclList'][0]:
for l in i[0]['sequence']:
rules['NUM'] = int(j['sequenceNumber'])
rules['TEXT_RULES'] = j['text']
acllist.append(rules.copy())
print (j['sequenceNumber'], j['text'])
return acllist
I'm assuming there can be multiple elements to these lists. If there aren't you could simplify to.
for dct in data[0]['result']['aclList'][0]['sequence']:
rules['NUM'] = int(dct['sequenceNumber'])
rules['TEXT_RULES'] = dct['text']
acllist.append(rules.copy())
print (inner['sequenceNumber'], dct['text'])
However if you want to iterate through every list and gather the elements for each version, it would look more like this:
def parse_data(data):
acllist = []
# for each dict in the initial list
for dct in data:
# for each list in the ['aclList'] key of the ['result'] key
for lst in dct['result']['aclList']:
# for each inner dict in the ['sequence'] key
for inner in lst['sequence']:
rules = {}
rules['NUM'] = int(inner['sequenceNumber'])
rules['TEXT_RULES'] = inner['text']
acllist.append(rules.copy())
print (inner['sequenceNumber'], inner['text'])
return acllist
data =[{
"encoding":"json",
"result": {
"aclList":[
{
"chipName":"",
"countersEnabled":True,
"countersIncomplete":False,
"dynamic":False,
"name":"FW-RULE-IN",
"readonly":False,
"sequence":[
{
"convertSymbols":True,
"sequenceNumber":1,
"text":"TEST: RULE 1"
},
{
"convertSymbols":True,
"sequenceNumber":2,
"text":"TEST: RULE 2"
},
{
"convertSymbols":True,
"sequenceNumber":3,
"text":"TEST: RULE 3"
},]}]}}]
print(parse_data(data))
Where you went wrong is that you are iterating through the key/values of you dicts.
for k, v in data[0].items():
k here would contain "encoding" and "result".
And then you are trying to iterate through those keys.
for h, j in k['result'].items():
But what you are essentially doing here is saying:
k = "result"
for h, j in k['result'].items():
Or:
for h, j in "result"['result'].items():
You can see why this would throw an error.

List comprehension to dynamically populate attribute of object

What’s the correct way to dynamically populate the list given to the attribute Value? At the moment its its fixed to 3 (0-2), but would be more useful if it was based on INSTANCE_PARAMS[i]["instances"].
I was thinking along the lines of list comprehension but unsure how to write it into the code.
for i in INSTANCE_PARAMS:
output = template.add_output([
Output(
str(INSTANCE_PARAMS[i]["name"]).capitalize() + "Ips",
Description="IPs for " + str(INSTANCE_PARAMS[i]["name"]),
Value=Join(",", [
GetAtt(ec2.Instance(INSTANCE_PARAMS[i]["name"] + "0"), "PrivateIp"),
GetAtt(ec2.Instance(INSTANCE_PARAMS[i]["name"] + "1"), "PrivateIp"),
GetAtt(ec2.Instance(INSTANCE_PARAMS[i]["name"] + "2"), "PrivateIp"),
],
),
)
],
)
INSTANCE_PARAMS = {
"masters": {
"name": "master",
"instances": 3,
"image_id": "ami-xxxxxxxxxx",
"instance_type": "t1.micro",
"security_group_id": [
"MasterSG",
"ClusterSG"
],
},
}
Achieved it with the following:
template = Template()
for i in INSTANCE_PARAMS:
# declared a new list
tag_value = []
# got the counter
for r in range(INSTANCE_PARAMS[i]["instances"]):
# added each one to the new list
tag_value.append(GetAtt(ec2.Instance(INSTANCE_PARAMS[i]["name"] + str(r)), "PrivateIP"))
output = template.add_output([
Output(
str(INSTANCE_PARAMS[i]["name"]).capitalize() + "Ips",
Description="IPs for " + str(INSTANCE_PARAMS[i]["name"]),
# passed in the list
Value=Join(",", tag_value,
),
)
],
)
print(template.to_yaml())

How to get all full paths to all child elements

Given a tree based of list of lists:
tree = [
"A",
[
"B1",
[
"C"
]
],
[
"B2",
[
"C",
[
"D1",
[
"E1"
],
[
"E2"
]
],
[
"D2"
]
]
]
]
I want to get the full path to all child elements as concatenated string in a list.
result = [
'A>B1>C',
'A>B2>C>D1>E1',
'A>B2>C>D1>E2',
'A>B2>C>D2'
]
The delimiter > is changeable.
I tried different things with recursion and yield. But my head is burning.
Try this it works.
def leave_paths(current):
if len(current) == 1:
return [current]
# Take all branches, get the paths for the branch, and prepend
return [[current[0]] + path for branch in current[1:] for path in leave_paths(branch)]
output = ['>'.join(sub_list) for sub_list in leave_paths(s)]
print(output)
Output
['A>B1>C', 'A>B2>C>D1>E1', 'A>B2>C>D1>E2', 'A>B2>C>D2']
Smth like this
def findLeaves(tree):
name=tree[0]
If len(tree)==1:
return [name]
else:
return [name+"->"+path for branch in tree[1:] for path in findLeaves(branch)]

Changing the values of a map nested in another map

Using HQL queries I've been able to generate the following map, where the keys represent the month number constant defined in java.util.Calendar, and every value is a map:
[
0:[ client_a:[order1, order2, order3]],
1:[ client_b:[order4], client_c:[order5, order6], client_d:[order7]],
2:[ client_e:[order8, order9], client_f:[order10]]
]
order1, order2, ... are instances of a domain class called Order:
class Order {
String description
Date d
int quantity
}
Now I've got that structure containing orders that belong to some specific year, but I don't really care about the Order object itself. I just want the sum of the quantities of all the orders of each month. So the structure should look something like this:
[
0:[ client_a:[321]],
1:[ client_b:[9808], client_c:[516], client_d:[20]],
2:[ client_e:[22], client_f:[10065]]
]
I don't mind if the values are lists of one element or not lists at all. If this is possible, it would be fine anyway:
[
0:[ client_a:321 ],
1:[ client_b:9808, client_c:516, client_d:20 ],
2:[ client_e:22, client_f:10065 ]
]
I know I have to apply something like .sum{it.quantity} to every list of orders to get the result I want, but I don't know how to iterate over them as they are nested within another map.
Thank you.
Here You go:
class Order {
String description
Date d
int quantity
}
def orders = [
0:[ client_a:[new Order(quantity:1), new Order(quantity:2), new Order(quantity:3)]],
1:[ client_b:[new Order(quantity:4)], client_c:[new Order(quantity:5), new Order(quantity:6)], client_d:[new Order(quantity:7)]],
2:[ client_e:[new Order(quantity:8), new Order(quantity:9)], client_f:[new Order(quantity:10)]]
]
def count = orders.collectEntries { k, v ->
def nv = v.collectEntries { nk, nv ->
[(nk): nv*.quantity.sum()]
}
[(k):(nv)]
}
assert count == [0:[client_a:6], 1:[client_b:4, client_c:11, client_d:7],2:[client_e:17, client_f:10]]
def map = [
0:[ client_a:[[q: 23], [q: 28], [q: 27]]],
1:[ client_b:[[q: 50]], client_c:[[q: 100], [q: 58]], client_d:[[q: 90]]],
2:[ client_e:[[q: 48], [q: 60]], client_f:[[q: 72]]]
]
map.collectEntries { k, v ->
[ k, v.collectEntries { key, val ->
[ key, val*.q.sum() ]
} ]
}
you can also use val.sum { it.q } instead of val*.q.sum()

Resources