Python, Delete Json Element Having Specific Key from a Loop

Python, delete JSON element having specific key from a loop

Use a (nested) dict/list comprehension. Never try to delete elements of an object while iterating over it

>>> [x for x in myData['myArray'] if x['name'] != 'bad']
[{'name': 'good', 'value': '1'}]

Assign the result to myData['myArray'], or whatever you want.

Loop through json file and delete key if it matches

Try

data['channels'].remove(channel)

instead of the for loop.

This will automatically search the array and remove any key matching your variable. If you need help saving the results to a file I would open another question.

Python: Iterate JSON and remove items with specific criteria

users_test = ['Ahmad Wickert', 'Dick Weston', 'Gerardo Salido', 'Rosendo Dewey', 'Samual Isham']

solution = []

for user in users_test:
print(user)
for value in data['result']:
if user == value['assigned_to']['display_value']:
solution.append(value)
print(solution)

for more efficient code, as asked by @NomadMonad

solution = list(filter(lambda x:  x['assigned_to']['display_value'] in users_test, data['result']))

How to delete an item from json while iterating it?

No hackery is needed if you iterate in reverse and delete:

key_set = {60, 70, 80, 90}  
values = jsonData['values'] # hold reference, less typing

for i in reversed(range(len(values))):
if values[i]['key'] not in key_list:
del values[i]

Or, you may use a list comprehension to re-create the list if your data is reasonably sized:

jsonData['values'] = [d for d in jsonData['values'] if d['key'] in key_set]

PS, use a set when checking for keys because set lookup is constant time.

How to remove an element from a JSON array using Python?

First question

However, whenever there's more than two elements and I enter anything higher than two, it doesn't delete anything. Even worse, when I enter the number one, it deletes everything but the zero index(whenever the array has more than two elements in it).

Inside delete_data() you have two lines reading i = + 1, which just assignes +1 (i.e., 1) to i. Thus, you're never increasing your index. You probably meant to write either i = i+1 or i += 1.

def delete_data():    # Deletes an element from the array
view_data()
new_data = []
with open(filename, "r") as f:
data = json.load(f)
data_length = len(data) - 1
print("Which index number would you like to delete?")
delete_option = input(f"Select a number 0-{data_length}: ")
i = 0
for entry in data:
if i == int(delete_option):
i += 1 # <-- here
else:
new_data.append(entry)
i += 1 # <-- and here

with open(filename, "w") as f:
json.dump(new_data, f, indent=4)


Second question: further improvements

Is there a better way to implement that in my Python script?

First, you can get rid of manually increasing i by using the builtin enumerate generator. Second, you could make your functions reusable by giving them parameters - where does the filename in your code example come from?

# view_data() should probably receive `filename` as a parameter
def view_data(filename: str): # Prints JSON Array to screen
with open(filename, "r") as f:
data = json.load(f)
# iterate over i and data simultaneously
# alternatively, you could just remove i
for i, item in enumerate(data):
name = item["name"]
chromebook = item["chromebook"]
check_out = item["time&date"]
print(f"Index Number: {i}")
print(f"Name : {name}")
print(f"Chromebook : {chromebook}")
print(f"Time Of Checkout: {check_out} ")
print("\n\n")
# not needed anymore: i = i + 1

# view_data() should probably receive `filename` as a parameter
def delete_data(filename: str): # Deletes an element from the array
view_data()
new_data = []
with open(filename, "r") as f:
data = json.load(f)
data_length = len(data) - 1
print("Which index number would you like to delete?")
delete_option = input(f"Select a number 0-{data_length}: ")
# iterate over i and data simultaneously
for i, entry in enumerate(data):
if i != int(delete_option):
new_data.append(entry)

with open(filename, "w") as f:
json.dump(new_data, f, indent=4)

Furthermore, you could replace that for-loop by a list comprehension, which some may deem more "pythonic":

new_data = [entry for i, entry in enumerate(data) if i != int(delete_option)]

How to delete one json item when each object has the same key name

You already made a list containing the keys you want to delete. Now, move its declaration to inside the for customer in customer_data loop, because you want to delete a fresh set of keys for every customer.

with open ('customers.json') as f:  
customer_data = json.load(f)


return_book_input = "Ulysses"

for customer in customer_data['customers']:
keys_to_delete = []
for key, value in customer.items():
if return_book_input == value:
keys_to_delete.append(key)

for key in keys_to_delete:
del customer[key]

print(customer_data)

Now, the customer_data dictionary doesn't contain the book1 key for the first customer.

{
"customers": [
{
"id": "1234",
"book2": "War and Peace",
"book3": "Memoirs of Hadrian",
"book5": "Season of Migration to the North"
},
{
"id": "4321",
"book": "Mrs Dalloway",
"book2": "Great Expectations"
},
{
"id": "1973",
"book": "The Aeneid"
}
]
}

This doesn't seem like a great way to structure your data, though. If you have the ability to change it, I strongly suggest you do. Each customer dictionary will have a key "id" for their customer id, and a key "books" for the books they borrowed. The value of the books key will be a list. This way, your object structure doesn't change when a customer borrows multiple books -- you simply add more entries to the list.

customers.json:

{
"customers": [
{
"id": "1234",
"books": ["Ulysses", "War and Peace", "Memoirs of Hadrian", "Season of Migration to the North"]
},
{
"id": "4321",
"books": ["Mrs Dalloway", "Great Expectations"]
},
{
"id": "1973",
"books": ["The Aeneid"]
}
]
}

Then, you'd use list.remove() to remove the book -- no explicit iterating required, list.remove() handles it for you. If the book doesn't exist in the list, a ValueError is thrown that we can catch to detect when this happens:

with open ('customers.json') as f:  
customer_data = json.load(f)

for customer in customer_data["customers"]:
try:
customer["books"].remove(return_book_input)
print(f"Thank you for returning {return_book_input}, Customer {customer['id']}")
except ValueError:
print(f"Customer {customer['id']} hasn't borrowed the book {return_book_input}")

This gives the output:

Thank you for returning Ulysses, Customer 1234
Customer 4321 hasn't borrowed the book Ulysses
Customer 1973 hasn't borrowed the book Ulysses

And once we're done, customer_data is:

{
"customers": [
{
"id": "1234",
"books": [ "War and Peace", "Memoirs of Hadrian", "Season of Migration to the North" ]
},
{
"id": "4321",
"books": [ "Mrs Dalloway", "Great Expectations" ]
},
{
"id": "1973",
"books": [ "The Aeneid" ]
}
]
}

In fact, you don't even need to iterate over the customers! Since you probably know your customer's ID already (it's presumably on their library card), customer_data["customers"] could be a dict. The keys of this dict are the customer ID. The values are the dictionaries for each customer, same as before.

customer.json:

{
"customers": {
"1234": {
"id": "1234",
"books": [ "War and Peace", "Memoirs of Hadrian", "Season of Migration to the North" ]
},
"4321": {
"id": "4321",
"books": [ "Mrs Dalloway", "Great Expectations" ]
},
"1973": {
"id": "1973",
"books": [ "The Aeneid" ]
}
}
}

Then, after reading the json you'd simply do:

customer_id = "1234" # input("Enter Customer ID: ")
return_book_input = "Ulysses" # input("Enter book: ")

try:
# Find the correct customer
customer = customer_data["customers"][customer_id] # If fail throws KeyError

# Remove book
customer["books"].remove(return_book_input) # If fail throws ValueError

print(f"Thank you for returning {return_book_input}, Customer {customer['id']}")
except KeyError: # Handle no customer
print(f"Customer {customer_id} does not exist")
except ValueError: # Handle no book
print(f"Customer {customer['id']} hasn't borrowed the book {return_book_input}")


Related Topics



Leave a reply



Submit