How to modify a dict item in a list - python

I have a list made of dictionaries
bookLogger = [
{'BookName': 'Noise', 'Author': 'Daniel Kahneman', 'Process': 'Reading' },
{'BookName': 'Superintelligence', 'Author': 'Nick Bostrom', 'Process': 'Not Reading'}
]
Want a user to be able to input what they want to change the name to, so that 'BookName': 'Noise' turns to 'BookName': 'Testing'
What I've come up with
testing = input("Enter Book Name ")
def changeName(bookLogger, testing, Name):
for options in bookLogger:
if options['BookName'] == testing:
options['BookName'] = Name
changeName(bookLogger, "BookName", "Chicken")
EDIT: Got it to work by doing
Updated = input("Enter Book Name ")
def changeName(Name):
for options in bookLogger:
if options['BookName'] == Updated:
options['BookName'] = Name
print(bookLogger)

You have many options. If you intend to modify the dict without returning a new dict, you can modify like this:
def rename(books: list[dict], old: str, new: str) -> None:
for book in books:
if book["name"] == old:
book["name"] = new
if __name__ == "__main__":
books = [{"name": "BookName"}, {"name": "A Book"}]
print(books)
rename(books, "BookName", "Chicken")
print(books)
Which yields:
[{'name': 'BookName'}, {'name': 'A Book'}]
[{'name': 'Chicken'}, {'name': 'A Book'}]
note: Type hints are used here but not required. I was simply specifying, for clarity in this case, that the inputs needed to be a list of dicts and two strings. In addition, these features can be enabled in some older versions of python using future.
from __future__ import annotations

Related

Read List from stringname append

I have the following problem, I want to reference a variable from a string so that I can call up a list.
I enter the user into the function def fetch(user). e.g. name1
I would like from name1, read the list name1_skiplist
or from name2 read name2_skiplist
name1_skiplist = [('home', '/pic'),('home', '/jpg'),]
name2_skiplist = [('etc', '/pic'),('etc', '/jpg'),]
name3_skiplist = [('tmp', '/pic'),('tmp', '/jpg'),]
def fetch(user):
joinedlist = []
joinedlist = user + '_skiplist'
if joinedlist:
....
Dict is more suited for you use case to retrieve list based on your key.
data = {'name1_skiplist': [('home', '/pic'), ('home', '/jpg'), ],
'name2_skiplist': [('etc', '/pic'), ('etc', '/jpg'), ],
'name3_skiplist': [('tmp', '/pic'), ('tmp', '/jpg'), ]}
def fetch(user):
joinedlist = user + '_skiplist'
result = data.get(joinedlist)
return result
Organize related information in collections -- data structures like dicts, lists,
tuples, namedtuples, dataclasses, etc. In your case, assuming I understand
your goal, a dict is probably a decent choice. For example:
skips = {
'home': [('home', '/pic'), ('home', '/jpg')],
'etc': [('etc', '/pic'), ('etc', '/jpg')],
'tmp': [('tmp', '/pic'), ('tmp', '/jpg')],
}
An illustrated usage:
for name in skips:
sks = skips[name]
print(name, sks)

Additional key: values not being added to Python Dictionary

Summary problem: Building an API endpoint and trying to push new key:values to the existing API. Not knowing if I am correctly adding key value pairs or not. Familiar with Ruby but first time Python user!
Context:
I currently have a method that will format given information into a Python Dictionary to be used as a JSON for my API. I have one method that pushes information to this method but another that is not functioning. Can anybody spot why?
Things I've tried:
Feature test using command line environment
Getting visibility - Printing
Environment:
MacOS 11.1, python 3.9.1, VSCode
Code:
METHOD THAT IS FORMATTING
class Database(object):
def __init__(self):
self.data = {}
def insert_entity(self, kind, entity):
kind_dict = self.data.get(kind, {})
entity_id = entity.get('id', str(uuid4()))
if not isinstance(entity_id, str):
raise Exception('Entity `id` must be a string')
entity['id'] = entity_id
kind_dict[entity_id] = entity
self.data[kind] = kind_dict
return entity
def get_entity(self, kind, entity_id):
entities = self.data.get(kind, {})
return entities.get(entity_id, None)
def get_all_entities(self, kind):
return list(self.data.get(kind, {}).values())
METHOD THAT IS WORKING:
def initialise_user_data():
first_names = ['Ron', 'Paul', 'Simon', 'David', 'Phil', 'Ada', 'Julia']
last_names = [
'Legend', 'Mac', 'Stuartson', 'Sili', 'Word', 'Nine',
'Smith'
]
for index in range(len(first_names)):
first_name = first_names[index]
last_name = last_names[index]
email = str(random.randint(0, 9999)) + "#email.com"
user_data = {
'firstName': first_name,
'lastName': last_name,
'email': email
}
database.insert_entity('User', user_data)
METHOD THAT IS NOT WORKING:
def initialise_event_data():
users = database.get_all_entities('User')
for user in users:
for _ in range(random.randint(0, 10)):
database.insert_entity(
'Event', {
'userId': user['id'],
'points': 100,
'eventName': 'levels_completed'
})
ALL METHODS ARE INVOKED AS SUCH:
database = InMemoryDatabase()
initialise_data()
def initialise_data():
initialise_user_data()
initialise_event_data()
initialise_follow_data()

Creating dictionaries inside dictionaries based on user input

New to programming, and teaching myself by making a to-do list app that stores things to do in a dictionary called ThingsToDo, based on user input. I'm using the dict.update function, which is working, but I want to add a feature so that in the dictionary ThingsToDo, every time a user inputs a new thing to do, it stores the new item as a dictionary inside ThingsToDo, with things like Due Date, and Status inside that sub-dictionary. How can I do this?
Here is the code so far (just started):
ThingsToDo = {}
while True:
item = input("What do you need to do? ")
DueDate = input("When do you need to do it by? ")
status = "Not done."
ThingsToDo.update({
"Item": item,
"Due Date": DueDate,
"Status": status,
})
print(ThingsToDo)
First I suggest you to think about what will be the key(s) of your dictionary(ies). I can suggest you this simple solution using "what you need to do" as a key. It works well:
ThingsToDo = {}
while True:
item = input("What do you need to do? ")
DueDate = input("When do you need to do it by? ")
status = "Not done."
ThingsToDo.update({item: {"Due Date": DueDate, "Status": status}})
print(ThingsToDo)
Output example:
What do you need to do? Wash the car
When do you need to do it by? 2018/09/01
{'Wash the car': {'Due Date': '2018/09/01', 'Status': 'Not done.'}}
What do you need to do? Sort papers
When do you need to do it by? 2018/08/23
{'Wash the car': {'Due Date': '2018/09/01', 'Status': 'Not done.'},
'Sort papers': {'Due Date': '2018/08/23', 'Status': 'Not done.'}}
You have "many" things to do, so you can put that dict in a list, or a dict.
You cannot put that in a set beacuse it has to be hashable.
If you chose a dict, you have to chose a "key" for each element, right?
You can read about "data structures" here .
Let's try list :
thingsToDo = []
newThingToDo = {
'Item': 'I need a haircut',
'DueDate': 'Right now',
'Status': 'Done'
}
thingsToDo.append(newThingToDo)
Using a dict would allow you to order your tasks, but I'm not sure it is your question. Let's try ordering your tasks by adding a number.
thingsToDo = {}
newThingToDo = {
'Item': 'I need a haircut',
'DueDate': 'Right now',
'Status': 'Done'
}
thingsToDo[5] = newThingToDo
So your haircut is task number 5.
If you choose the dict way, your code could look like this :
# -*- coding: utf-8 -*-
thingsToDo = {}
while True:
n = int(input("How many tasks do you want to add?"))
for i in range(n):
item = input("What do you need to do? ")
duedate = input("When do you need to do it by? ")
status = "Not done."
newThingToDo = {
'Item': item,
'DueDate': duedate,
'Status': status
}
thingsToDo[i] = newThingToDo
print(thingsToDo)

How to select particular JSON object with specific value?

I have List of multiple dictionaries inside it(as JSON ).I have a list of value and based on that value I want that JSON object for that particular value. For eg.
[{'content_type': 'Press Release',
'content_id': '1',
'Author':John},
{'content_type': 'editorial',
'content_id': '2',
'Author': Harry
},
{'content_type': 'Article',
'content_id': '3',
'Author':Paul}]
I want to to fetch complete object where author is Paul.
This is the code I have made so far.
import json
newJson = "testJsonNewInput.json"
ListForNewJson = []
def testComparision(newJson,oldJson):
with open(newJson, mode = 'r') as fp_n:
json_data_new = json.load(fp_n)
for jData_new in json_data_new:
ListForNewJson.append(jData_new['author'])
If any other information required, please ask.
Case 1
One time access
It is perfectly alright to read your data and iterate over it, returning the first match found.
def access(f, author):
with open(file) as f:
data = json.load(f)
for d in data:
if d['Author'] == author:
return d
else:
return 'Not Found'
Case 2
Repeated access
In this instance, it would be wise to reshape your data in such a way that accessing objects by author names is much faster (think dictionaries!).
For example, one possible option would be:
with open(file) as f:
data = json.load(f)
newData = {}
for d in data:
newData[d['Author']] = d
Now, define a function and pass your pre-loaded data along with a list of author names.
def access(myData, author_list):
for a in author_list:
yield myData.get(a)
The function is called like this:
for i in access(newData, ['Paul', 'John', ...]):
print(i)
Alternatively, store the results in a list r. The list(...) is necessary, because yield returns a generator object which you must exhaust by iterating over.
r = list(access(newData, [...]))
Why not do something like this? It should be fast and you will not have to load the authors that wont be searched.
alreadyknown = {}
list_of_obj = [{'content_type': 'Press Release',
'content_id': '1',
'Author':'John'},
{'content_type': 'editorial',
'content_id': '2',
'Author': 'Harry'
},
{'content_type': 'Article',
'content_id': '3',
'Author':'Paul'}]
def func(author):
if author not in alreadyknown:
obj = get_obj(author)
alreadyknown[author] = obj
return alreadyknown[author]
def get_obj(auth):
return [obj for obj in list_of_obj if obj['Author'] is auth]
print(func('Paul'))

How to avoid repetitive if statements in python dictionaries

I am trying to create a new dictionary out of html form data that was submitted by the user. I end up writing repetitive if statements, checking if xyz key is in the dictionary in the form data. I know this is a quite suboptimal approach though I am not quite sure how to implement this using python.
This is the form data dictionary:
form_data = {
'urls': ['www.google.com', 'www.bing.com'],
'useremail': ['my#email.com'],
'emailfield': ['1'],
'addressfield': ['1'],
'addressfield_info':['Company'],
'addressfield_instruction': ['Please only if the company is a LLC'],
'phonefield': ['1'],
'phonefield_instruction': ['please include area code']
}
and I want to create a dictionary that looks like this:
new_dic = {
'urls': ['www.google.com', 'www.bing.com'],
'useremail': ['my#email.com'],
'infofield': [
{'field': 'email'},
{'field': 'address', 'info':'Company', 'instruction': 'Please only if the company is a LLC'},
{'field':'phone', 'instruction': 'please include area code'}
]
}
Important note: The 'xyzfield' is mandatory and the 'xyzfield_info' and 'xyzfield_instruction' are both optional. Also: the user can add more fields and create for instance an 'agefield', 'agefield_info' and 'agefield_instruction'.
The problem I have is about how to efficiently check if xyzfield (email, phone, etc) is in the dictionary. If it is in there, check also if any of the optional fields are in there as well. This looks currently something like this:
if 'emailfield' in form_data:
infofield = {'field': 'email'}
if 'emailfield_info' in form_data:
infofield['info'] = form_data['emailfield_info']
if 'emailfield_instruction' in form_data:
infofield['instruction'] = form_data['emailfield_instruction']
cleaned_data['infofields'].append(infofield)
...
and I do this for every field, hence I have 4-5 of this. Additional, I will not be able to process any of the fields that the user has created himself since I don't know the name upfront.
Long story short: How can I make this more efficient and dynamic?
The standard answer to how to avoid repeated code applies here --- extract the repeated code to a function:
def extract_field(form_data, clean, fieldname, optional=('info', 'instruction')):
if fieldname+'field' in form_data:
infofield = { 'field': fieldname }
for opt in optional:
optname = '{}field_{}'.format(fieldname, opt)
if optname in form_data:
infofield[opt] = form_data[optname]
clean.append(infofield)
extract_field(form_data, cleaned_data['infofields'], 'email')
extract_field(form_data, cleaned_data['infofields'], 'address')
extract_field(form_data, cleaned_data['infofields'], 'phone')
This assumes you just want to clean whatever is actually submitted. If you are looking for specific things to be there, I suggest making a list of things to look for, and iterating over the list and checking to see if the things are there.
form_data = {
'urls': ['www.google.com', 'www.bing.com'],
'useremail': ['my#email.com'],
'emailfield': ['1'],
'addressfield': ['1'],
'addressfield_info':['Company'],
'addressfield_instruction': ['Please only if the company is a LLC'],
'phonefield': ['1'],
'phonefield_instruction': ['please include area code']
}
def make_field_dict(form_data, base):
field_dict = {}
name_field = base + "field"
name_info = base + "field_info"
name_inst = base + "field_instruction"
if name_field not in form_data:
raise KeyError, "%s not found in form_data" % name_field
if form_data[name_field] != ['1']:
raise ValueError, "%s not valid in form_data" % name_field
field_dict["field"] = base
if name_info in form_data:
lst = form_data[name_info]
if len(lst) != 1:
raise ValueError, "%s not valid in form_data" % name_info
field_dict["info"] = lst[0]
if name_inst in form_data:
lst = form_data[name_inst]
if len(lst) != 1:
raise ValueError, "%s not valid in form_data" % name_inst
field_dict["instruction"] = lst[0]
return field_dict
def parse_form_data(form_data):
cleaned_data = {}
cleaned_data["infofield"] = []
seen = set()
for key, value in form_data.items():
if "field" not in key:
cleaned_data[key] = value
else:
base, _, tail = key.partition("field")
if base in seen:
continue
cleaned_data["infofield"].append(make_field_dict(form_data, base))
seen.add(base)
return cleaned_data
new_dic = {
'urls': ['www.google.com', 'www.bing.com'],
'useremail': ['my#email.com'],
'infofield': [
{'field': 'email'},
{'field': 'address', 'info':'Company', 'instruction': 'Please only if the company is a LLC'},
{'field':'phone', 'instruction': 'please include area code'}
]
}
clean_data = parse_form_data(form_data)
new_dic['infofield'].sort()
clean_data['infofield'].sort()
assert(new_dic == clean_data)

Categories