I previusly asked about adding, and someone helped me out with append. My new problem is trying to delete a key with a nested list, e.g.:
JSON:
data = {"result":[{"name":"Teddy","list":{"0":"24","1":"43","2":"56"}},
{"name":"Barney","list":{"0":"24","1":"43","2":"56"}]}
Python:
name = input("Input a key to delete") #Must hold a value.
data["result"].pop(name)
E.g. Barney => then delete Barney etc.
I use the method below to find a key, but I am not sure this is the correct approach.
Finding Barney:
for key in data['result']:
if key['name'] == name:
print("Found!!!!")
I am not sure. This surely does not work, maybe I should loop through each key or? Any suggestion or code example is worth.
After Delete: Now that barney was deleted the dictionary remains like this.
data = {"result":[{"name":"Teddy","list":{"0":"24","1":"43","2":"56"}}]}
If the goal is to remove list items from the JSON document, you'll want to:
Convert the JSON document into a Python data structure
Manipulate the Python data structure
Convert the Python data structure back to a JSON document
Here is one such program:
import json
def delete_keys(json_string, name):
data = json.loads(json_string)
data['result'][:] = [d for d in data['result'] if d.get('name') != name]
json_string = json.dumps(data)
return json_string
j = '''
{"result":[{"name":"Teddy",
"list":{"0":"24","1":"43","2":"56"}},
{"name":"Barney","list":{"0":"24","1":"43","2":"56"}}]}'''
print delete_keys(j, 'Barney')
Result:
$ python x.py
{"result": [{"list": {"1": "43", "0": "24", "2": "56"}, "name": "Teddy"}]}
Note this list comprehension:
data['result'][:] = [d for d in data['result'] if d.get('name') != name]
The form l[:] = [item in l if ...] is one way to delete several items from a list according to the indicated condition.
Since data['result'] is a list, you'll have to go to the index and delete the key. If you're looking to delete the key across all indices in the list, you could quickly write a function that iterates through the list and deletes the matching key
def delete_key(list_obj, key):
for value in list_obj:
if key in value:
value.pop(key)
return list_obj
result = delete_key(data["result"], 'key1')
You can convert the JSON into a JavaScript object.
var resultString = '{'result':[{'key1':'value1','key2':'value2'}, {'key1':'value3','key2':'value4'}]}';
var result = JSON.parse(resultString);
Once you do, you should be more aware that this is an array of objects. You need to know which index you want to remove. You can use the .find method for arrays
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/find
if you don't know the index.
var inventory = [
{name: 'apples', quantity: 2},
{name: 'bananas', quantity: 0},
{name: 'cherries', quantity: 5}
];
function findCherries(fruit) {
return fruit.name === 'cherries';
}
console.log(inventory.find(findCherries));
// { name: 'cherries', quantity: 5 }
Realize though that find does not work in IE. Once you know the index, you can split the array.
var myFish = ["angel", "clown", "drum", "mandarin", "surgeon"];
var removed = myFish.splice(3, 1);
// removed is ["mandarin"]
// myFish is ["angel", "clown", "drum", "surgeon"]
from https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/splice
Related
I want to replace items in a list based on another list as reference.
Take this example lists stored inside a dictionary:
dict1 = {
"artist1": ["dance pop","pop","funky pop"],
"artist2": ["chill house","electro house"],
"artist3": ["dark techno","electro techno"]
}
Then, I have this list as reference:
wish_list = ["house","pop","techno"]
My result should look like this:
dict1 = {
"artist1": ["pop"],
"artist2": ["house"],
"artist3": ["techno"]
}
I want to check if any of the list items inside "wishlist" is inside one of the values of the dict1. I tried around with regex, any.
This was an approach with just 1 list instead of a dictionary of multiple lists:
check = any(item in artist for item in wish_list)
if check == True:
artist_genres.clear()
artist_genres.append()
I am just beginning with Python on my own and am playing around with the SpotifyAPI to clean up my favorite songs into playlists. Thank you very much for your help!
The idea is like this,
dict1 = { "artist1" : ["dance pop","pop","funky pop"],
"artist2" : ["house","electro house"],
"artist3" : ["techno","electro techno"] }
wish_list = ["house","pop","techno"]
dict2={}
for key,value in dict1.items():
for i in wish_list:
if i in value:
dict2[key]=i
break
print(dict2)
A regex is not needed, you can get away by simply iterating over the list:
wish_list = ["house","pop","techno"]
dict1 = {
"artist1": ["dance pop","pop","funky pop"],
"artist2": ["chill house","electro house"],
"artist3": ["dark techno","electro techno"]
}
dict1 = {
# The key is reused as-is, no need to change it.
# The new value is the wishlist, filtered based on its presence in the current value
key: [genre for genre in wish_list if any(genre in item for item in value)]
for key, value in dict1.items() # this method returns a tuple (key, value) for each entry in the dictionary
}
This implementation relies a lot on list comprehensions (and also dictionary comprehensions), you might want to check it if it's new to you.
I have a JSON with a dict of keys which are not always present, at least not all of them all the time at the same position. For example, "producers" is not always on array dict [2] present or "directors" not always on [1] at the JSON, it fully depends on the JSON I pass into my function. Depending on what is available at ['plist']['dict']['key'] the content is mapped to dict 0,1,2,3 (except of studio) ...
How can I find the corresponding array for cast, directors, producers etc. as each of them is not always located at the same array number?!
In the end I always want to be able to pull out the right data for the right field even if ['plist']['dict']['key'] may vary sometimes according to the mapped dict.
...
def get_plist_meta(element):
if isinstance(element, dict):
return element["string"]
return ", ".join(i["string"] for i in element)
...
### Default map if all fields are present
# 0 = cast
# 1 = directors
# 2 = producers
# 3 = screenwriters
plist_metadata = json.loads(dump_json)
### make fields match the given sequence 0 = cast, 1 = directors etc. ()
if 'cast' in plist_metadata['plist']['dict']['key']:
print("Cast: ", get_plist_meta(plist_metadata['plist']['dict']['array'][0]['dict']))
if 'directors' in plist_metadata['plist']['dict']['key']:
print("Directors: ", get_plist_meta(plist_metadata['plist']['dict']['array'][1]['dict']))
if 'producers' in plist_metadata['plist']['dict']['key']:
print("Producers: ", get_plist_meta(plist_metadata['plist']['dict']['array'][2]['dict']))
if 'screenwriters' in plist_metadata['plist']['dict']['key']:
print("Screenwriters: ", get_plist_meta(plist_metadata['plist']['dict']['array'][3]['dict']))
if 'studio' in plist_metadata['plist']['dict']['key']:
print("Studio: ", plist_metadata['plist']['dict']['string'])
JSON:
{
"plist":{
"#version":"1.0",
"dict":{
"key":[
"cast",
"directors",
"screenwriters",
"studio"
],
"array":[
{
"dict":[
{
"key":"name",
"string":"Martina Piro"
},
{
"key":"name",
"string":"Ralf Stark"
}
]
},
{
"dict":{
"key":"name",
"string":"Franco Camilio"
}
},
{
"dict":{
"key":"name",
"string":"Kai Meisner"
}
}
],
"string":"Helix Films"
}
}
}
JSON can also be obtained here: https://pastebin.com/JCXRs3Rw
Thanks in advance
If you prefer a more pythonic solution, try this:
# We will use this function to extract the names from the subdicts. We put single items in a new array so the result is consistent, no matter how many names there were.
def get_names(name_dict):
arrayfied = name_dict if isinstance(name_dict, list) else [name_dict]
return [o["string"] for o in arrayfied]
# Make a list of tuples
dict = plist_metadata['plist']['dict']
zipped = zip(dict["key"], dict["array"])
# Get the names from the subdicts and put it into a new dict
result = {k: get_names(v["dict"]) for k, v in zipped}
This will give you a new dict that looks like this
{'cast': ['Martina Piro', 'Ralf Stark'], 'directors': ['Franco Camilio'], 'screenwriters': ['Kai Meisner']}
The new dict will only have the keys present in the original dict.
I'd advise to check out things like zip, map and so on as well as list comprehensions and dict comprehensions.
I think this solves your problem:
import json
dump_json = """{"plist":{"#version":"1.0","dict":{"key":["cast","directors","screenwriters","studio"],"array":[{"dict":[{"key":"name","string":"Martina Piro"},{"key":"name","string":"Ralf Stark"}]},{"dict":{"key":"name","string":"Franco Camilio"}},{"dict":{"key":"name","string":"Kai Meisner"}}],"string":"Helix Films"}}}"""
plist_metadata = json.loads(dump_json)
roles = ['cast', 'directors', 'producers', 'screenwriters'] # all roles
names = {'cast': [], 'directors': [], 'producers': [], 'screenwriters': []} # stores the final output
j = 0 # keeps count of which array entry we are looking at in plist_metadata['plist']['dict']['array']
for x in names.keys(): # cycle through all the possible roles
if x in plist_metadata['plist']['dict']['key']: # if a role exists in the keys, we'll store it in names[role_name]
y = plist_metadata['plist']['dict']['array'][j]['dict'] # keep track of value
if isinstance(plist_metadata['plist']['dict']['array'][j]['dict'], dict): # if its a dict, encase it in a list
y = [plist_metadata['plist']['dict']['array'][j]['dict']]
j += 1 # add to our plist-dict-array index
names[x] = list(map(lambda x: x['string'], y)) # map each of the entries from {"key":"name","string":"Martina Piro"} to just "Martina Piro"
print(names)
def list_names(role_name):
if role_name not in names.keys():
return f'Invalid list request: Role name "{role_name}" not found.'
return f'{role_name.capitalize()}: {", ".join(names[role_name])}'
print(list_names('cast'))
print(list_names('audience'))
Output:
{'cast': ['Martina Piro', 'Ralf Stark'], 'directors': ['Franco Camilio'], 'producers': [], 'screenwriters': ['Kai Meisner']}
Cast: Martina Piro, Ralf Stark
Invalid list request: Role name "audience" not found.
here is the json: (FYI, the '0' to '2' is the index of the original pd.Series([1,1,1])
json1 = {
'hi':[
{'0':1},
{'1':1},
{'2':1}
]
}
I want to get [1,1,1] from json1.
I tried:
records = [v for v in json1['hi']]
emt=[]
for rec in records:
for i in rec.keys():
value = rec[i]
emt.append(value)
is there a simple and easy way like one line of code to achieve it? Thanks
You can use dict.values:
list(map(next, map(iter, map(dict.values, json1['hi']))))
Although this will only work if there's one key in each dict. Otherwise you can use itertools.chain:
list(chain(*map(dict.values, json1['hi'])))
json1['hi'] returns a list
From that list, you have dictionaries.
In each dictionary, you want the first and only value, which can be done with next(iter(iterable))
[next(iter(x.values())) for x in json1['hi']]
If your data type is inconvenient:
json1 = {
'hi':[
{'0':1},
{'1':1},
{'2':1}
]
}
then the code to extract the data you want will also be inconvenient:
[next(iter(d.values())) for d in json1["hi"]]
If your data type is convenient:
json1 = {
'hi':{'0':1,
'1':1,
'2':1}
}
then the code will also be convenient:
list(json1['hi'].values())
Moral of the story: use a dictionary, not a list of one-element dictionaries.
Since you like short code:
[*map(lambda x: list(x.values())[0], json1['hi'])]
[1, 1, 1]
I'm using this as a reference: Elegant way to remove fields from nested dictionaries
I have a large number of JSON-formatted data here and we've determined a list of unnecessary keys (and all their underlying values) that we can remove.
I'm a bit new to working with JSON and Python specifically (mostly did sysadmin work) and initially thought it was just a plain dictionary of dictionaries. While some of the data looks like that, several more pieces of data consists of dictionaries of lists, which can furthermore contain more lists or dictionaries with no specific pattern.
The idea is to keep the data identical EXCEPT for the specified keys and associated values.
Test Data:
to_be_removed = ['leecher_here']
easy_modo =
{
'hello_wold':'konnichiwa sekai',
'leeching_forbidden':'wanpan kinshi',
'leecher_here':'nushiyowa'
}
lunatic_modo =
{
'hello_wold':
{'
leecher_here':'nushiyowa','goodbye_world':'aokigahara'
},
'leeching_forbidden':'wanpan kinshi',
'leecher_here':'nushiyowa',
'something_inside':
{
'hello_wold':'konnichiwa sekai',
'leeching_forbidden':'wanpan kinshi',
'leecher_here':'nushiyowa'
},
'list_o_dicts':
[
{
'hello_wold':'konnichiwa sekai',
'leeching_forbidden':'wanpan kinshi',
'leecher_here':'nushiyowa'
}
]
}
Obviously, the original question posted there isn't accounting for lists.
My code, modified appropriately to work with my requirements.
from copy import deepcopy
def remove_key(json,trash):
"""
<snip>
"""
keys_set = set(trash)
modified_dict = {}
if isinstance(json,dict):
for key, value in json.items():
if key not in keys_set:
if isinstance(value, dict):
modified_dict[key] = remove_key(value, keys_set)
elif isinstance(value,list):
for ele in value:
modified_dict[key] = remove_key(ele,trash)
else:
modified_dict[key] = deepcopy(value)
return modified_dict
I'm sure something's messing with the structure since it doesn't pass the test I wrote since the expected data is exactly the same, minus the removed keys. The test shows that, yes it's properly removing the data but for the parts where it's supposed to be a list of dictionaries, it's only getting returned as a dictionary instead which will have unfortunate implications down the line.
I'm sure it's because the function returns a dictionary but I don't know to proceed from here in order to maintain the structure.
At this point, I'm needing help on what I could have overlooked.
When you go through your json file, you only need to determine whether it is a list, a dict or neither. Here is a recursive way to modify your input dict in place:
def remove_key(d, trash=None):
if not trash: trash = []
if isinstance(d,dict):
keys = [k for k in d]
for key in keys:
if any(key==s for s in trash):
del d[key]
for value in d.values():
remove_key(value, trash)
elif isinstance(d,list):
for value in d:
remove_key(value, trash)
remove_key(lunatic_modo,to_be_removed)
remove_key(easy_modo,to_be_removed)
Result:
{
"hello_wold": {
"goodbye_world": "aokigahara"
},
"leeching_forbidden": "wanpan kinshi",
"something_inside": {
"hello_wold": "konnichiwa sekai",
"leeching_forbidden": "wanpan kinshi"
},
"list_o_dicts": [
{
"hello_wold": "konnichiwa sekai",
"leeching_forbidden": "wanpan kinshi"
}
]
}
{
"hello_wold": "konnichiwa sekai",
"leeching_forbidden": "wanpan kinshi"
}
I'm running through an excel file reading line by line to create dictionaries and append them to a list, so I have a list like:
myList = []
and a dictionary in this format:
dictionary = {'name': 'John', 'code': 'code1', 'date': [123,456]}
so I do this: myList.append(dictionary), so far so good. Now I'll go into the next line where I have a pretty similar dictionary:
dictionary_two = {'name': 'John', 'code': 'code1', 'date': [789]}
I'd like to check if I already have a dictionary with 'name' = 'John' in myList so I check it with this function:
def checkGuy(dude_name):
return any(d['name'] == dude_name for d in myList)
Currently I'm writing this function to add the guys to the list:
def addGuy(row_info):
if not checkGuy(row_info[1]):
myList.append({'name':row_info[1],'code':row_info[0],'date':[row_info[2]]})
else:
#HELP HERE
in this else I'd like to dict.update(updated_dict) but I don't know how to get the dictionary here.
Could someone help so dictionary appends the values of dictionary_two?
I would modify checkGuy to something like:
def findGuy(dude_name):
for d in myList:
if d['name'] == dude_name:
return d
else:
return None # or use pass
And then do:
def addGuy(row_info):
guy = findGuy(row_info[1])
if guy is None:
myList.append({'name':row_info[1],'code':row_info[0],'date':[row_info[2]]})
else:
guy.update(updated_dict)
This answer suggestion is pasted on the comments where it was suggested that if "name" is the only criteria to search on then it could be used as a key in a dictionary instead of using a list.
master = {"John" : {'code': 'code1', 'date': [123,456]}}
def addGuy(row_info):
key = row_info[1]
code = row_info[0]
date = row_info[2]
if master.get(key):
master.get(key).update({"code": code, "date": date})
else:
master[key] = {"code": code, "date": date}
If you dict.update the existing data each time you see a repeated name, your code can be reduced to a dict of dicts right where you read the file. Calling update on existing dicts with the same keys is going to overwrite the values leaving you with the last occurrence so even if you had multiple "John" dicts they would all contain the exact same data by the end.
def read_file():
results = {name: {"code": code, "date": date}
for code, name, date in how_you_read_into_rows}
If you actually think that the values get appended somehow, you are wrong. If you wanted to do that you would need a very different approach. If you actually want to gather the dates and codes per user then use a defauldict appending the code,date pair to a list with the name as the key:
from collections import defaultdict
d = defaultdict(list)
def read_file():
for code, name, date in how_you_read_into_rows:
d["name"].append([code, date])
Or some variation depending on what you want the final output to look like.