making an application where I need to get field 'workers' from an API request and pass those to another dict.. dictionary is behaving strangely and I cannot seem to append through += or .update like a normal list or tupple.
main.py
# worker_detail - contains a list of filtered workers
# workers - contains a list of all workers
information = {}
reported_workers = []
for person in workers:
if person['id'] in worker_detail:
reported_workers += person
print(reported_workers)
If I use the above logic it will only print the fields in a dictionary without and workers..
['id', 'first_name', 'last_name', 'email', 'phone_number', 'hire_date', 'job_id', 'salary', 'commission_pct', 'manager_id', 'department_id', 'id', 'first_name', 'last_name', 'email', 'phone_number', 'hire_date', 'job_id', 'salary', 'commission_pct', 'manager_id', 'department_id']
If I print(person) output will be a dictionary containing all the neccessary fields and it's details
{'id': 1, 'first_name': 'Steven', 'last_name': 'King', 'email': 'SKING', 'phone_number': 5151234567, 'hire_date': '2021-06-17', 'job_id': 'AD_PRES', 'salary': 24000, 'commission_pct': 0, 'manager_id': 0, 'department_id': 0}
{'id': 2, 'first_name': 'Neena', 'last_name': 'Kochhar', 'email': 'NKOCHHAR', 'phone_number': 5151234568, 'hire_date': '2020-06-17', 'job_id': 'AD_VP', 'salary': 17000, 'commission_pct': 0, 'manager_id': 100, 'department_id': 90}
{'id': 5, 'first_name': 'Bruce', 'last_name': 'Ernst', 'email': 'BERNST', 'phone_number': 5151234571, 'hire_date': '2016-07-17', 'job_id': 'IT_PROG', 'salary': 6000, 'commission_pct': 0, 'manager_id': 103, 'department_id': 60}
{'id': 9, 'first_name': 'Inbal', 'last_name': 'Amor', 'email': 'IMOR', 'phone_number': 5151234575, 'hire_date': '2013-08-23', 'job_id': 'IT_PROG', 'salary': 5000, 'commission_pct': 0, 'manager_id': 104, 'department_id': 60}
Try using a list comprehension:
reported_workers = [person for person in workers if person in worker_detail]
If you find yourself looping over a list to make a new list, often you can replace it with this really nifty structure. It will let you abstract away your criteria also. If you want your worker_detail to be a more specific tuning, you can create a function for it and just call that in the list comprehension
def is_worker(person_id):
for worker in worker_detail:
if worker['id'] == person_id: return True
return False
reported_workers = [person for person in workers if is_worker(person['id'])]
append, dont +=
information = {}
reported_workers = []
for person in workers:
if person in worker_detail:
reported_workers.append(person)
print(reported_workers)
Related
I am working on a coding challenge for self-development and I came across a question where I am given an input like this:
add {"id":1,"last":"Doe","first":"John","location":{"city":"Oakland","state":"CA","postalCode":"94607"},"active":true}
add {"id":2,"last":"Doe","first":"Jane","location":{"city":"San Francisco","state":"CA","postalCode":"94105"},"active":true}
add {"id":3,"last":"Black","first":"Jim","location":{"city":"Spokane","state":"WA","postalCode":"99207"},"active":true}
add {"id":4,"last":"Frost","first":"Jack","location":{"city":"Seattle","state":"WA","postalCode":"98204"},"active":false}
get {"location":{"state":"WA"},"active":true}
get {"id":1}
get {"active":true}
delete {"active":true}
get {}
And what I am doing is adding the entries that start with add to a list called database = []:
json_input = []
database = []
for line in sys.stdin:
json_input.append(line.split("', "))
for i in range(0, len(json_input)):
if json_input[i][0] == 'add':
database.append(json_input[i][1])
What I want to do is to print out every entry that matches what follows get and delete every entry that matches what follows delete. This is where I am stuck. Currently, this is what json_input() looks like. database is empty:
[
['add {"id":1,"last":"Doe","first":"John","location":{"city":"Oakland","state":"CA","postalCode":"94607"},"active":true}\n'],
['add {"id":2,"last":"Doe","first":"Jane","location":{"city":"San Francisco","state":"CA","postalCode":"94105"},"active":true}\n'],
['add {"id":3,"last":"Black","first":"Jim","location":{"city":"Spokane","state":"WA","postalCode":"99207"},"active":true}\n'],
['add {"id":4,"last":"Frost","first":"Jack","location":{"city":"Seattle","state":"WA","postalCode":"98204"},"active":false}\n'],
['get {"location":{"state":"WA"},"active":true}\n'], ['get {"id":1}\n'],
['get {"active":true}\n'], ['delete {"active":true}\n'],
['get {}']
]
Perhaps an easy-to-read way to handle this would be a simple class that maintains a list of records. You can add methods for the various commands you want to handle. Then it's just a matter of defining the methods and processing the input to pass to the methods. Here's a possible way (without any frills like error checking):
import json
raw_data = '''add {"id":1,"last":"Doe","first":"John","location":{"city":"Oakland","state":"CA","postalCode":"94607"},"active":true}
add {"id":2,"last":"Doe","first":"Jane","location":{"city":"San Francisco","state":"CA","postalCode":"94105"},"active":true}
add {"id":3,"last":"Black","first":"Jim","location":{"city":"Spokane","state":"WA","postalCode":"99207"},"active":true}
add {"id":4,"last":"Frost","first":"Jack","location":{"city":"Seattle","state":"WA","postalCode":"98204"},"active":false}
get {"location":{"state":"WA"},"active":true}
get {"id":1}
get {"active":true}
delete {"active":true}
get {}'''
class Data:
#staticmethod
def matches(obj, query):
if not isinstance(query, dict):
return obj == query
return all(Data.matches(obj.get(key), q) for key, q in query.items())
def __init__(self):
self.data = []
def add(self, record):
self.data.append(record)
def get(self, query):
for item in self.data:
if (Data.matches(item, query)):
print(item)
def delete(self, query):
self.data = [record for record in self.data if not Data.matches(record, query)]
data = Data()
for line in raw_data.split('\n'):
command, line = line.split(None, 1)
command = getattr(data, command)
command(json.loads(line))
This will print the records from WA then the active:True records. Then after deleting the True records it will print everything (the result of the {} query), which is the only one left -- the active:False record:
{'id': 3, 'last': 'Black', 'first': 'Jim', 'location': {'city': 'Spokane', 'state': 'WA', 'postalCode': '99207'}, 'active': True}
{'id': 1, 'last': 'Doe', 'first': 'John', 'location': {'city': 'Oakland', 'state': 'CA', 'postalCode': '94607'}, 'active': True}
{'id': 1, 'last': 'Doe', 'first': 'John', 'location': {'city': 'Oakland', 'state': 'CA', 'postalCode': '94607'}, 'active': True}
{'id': 2, 'last': 'Doe', 'first': 'Jane', 'location': {'city': 'San Francisco', 'state': 'CA', 'postalCode': '94105'}, 'active': True}
{'id': 3, 'last': 'Black', 'first': 'Jim', 'location': {'city': 'Spokane', 'state': 'WA', 'postalCode': '99207'}, 'active': True}
{'id': 4, 'last': 'Frost', 'first': 'Jack', 'location': {'city': 'Seattle', 'state': 'WA', 'postalCode': '98204'}, 'active': False}
If this were a test or a serious coding challenge, you would probably want to look carefully at matches() to make sure it properly handles edge cases (I didn't do that).
So I have a list that looks like this:
users = [{'id': 11, 'name': 'First'}, {'id': 22, 'name': 'Second'}, {'id':33, 'name': 'Third'}]
What I want to do is to update a users name by passing id, creating new user, and replacing old one with new user.
I want to get list of updated users, like this:
updated_users = list(map(update, users))
If I could send id to update func as argument, what I want to do, would look something like this:
def update(id):
if user['id'] == id:
new_user = some_fun()
user = new_user
return user
How should my update function look like?
I don't know why you want to use map and I think it's a wrong approach because map isn't for this kind of things (you could make it work for sure but it wouldn't be the way to go)
You can do something like that:
users = [{'id': 11, 'name': 'First'}, {'id': 22, 'name': 'Second'}, {'id':33, 'name': 'Third'}]
def update(id, new_name):
for user in users:
if user["id"] == id:
user["name"] = new_name
return
users.append({'id':id,'name':new_name}) # if not exist add user
print(users)
update(11,"Last")
update(1, "New_First")
print(users)
Output:
[{'id': 11, 'name': 'First'}, {'id': 22, 'name': 'Second'}, {'id': 33, 'name': 'Third'}]
[{'id': 11, 'name': 'Last'}, {'id': 22, 'name': 'Second'}, {'id': 33, 'name': 'Third'}, {'id': 1, 'name': 'New_First'}]
I have the following dict
{'returnData': [{'eMail': None,
'firstName': 'Peter',
'id': '1234',
'name': 'Parker'},
{'eMail': 'lucky#mail.example',
'firstName': 'Lucky',
'id': '123',
'name': 'Luke'},
{'eMail': 'micky#mail.example',
'firstName': 'Micky',
'id': '3456',
'name': 'Mouse'}],
'status': {'errorCode': 0,
'message': None,
'subErrorCode': None,
'success': True}}
How would i search the dict for the values of eMail, firstName and name and return all found matches in a new dict.
For example, i search for mail.example it should return only two entries.
Python3
Solution 1:
list(filter(lambda profile: '#mail.example' in str(profile['eMail']), data['returnData']))
to search in all values of dict
list(filter(lambda profile: '#mail.example' in str(
profile.items()), data['returnData']))
Solution 2:
Create a search function.
data = {'returnData': [{'eMail': None,
'firstName': 'Peter',
'id': '1234',
'name': 'Parker'},
{'eMail': 'lucky#mail.example',
'firstName': 'Lucky',
'id': '123',
'name': 'Luke'},
{'eMail': 'micky#mail.example',
'firstName': 'Micky',
'id': '3456',
'name': 'Mouse'}],
'status': {'errorCode': 0,
'message': None,
'subErrorCode': None,
'success': True}}
def search(search_term, field, data):
result = []
for item in data:
if search_term in str(item[field]):
result.append(item)
return result
print(search("#mail.example", "eMail", data['returnData']))
You may want to use re module here
import re
d = {'returnData': [{'eMail': None,
'firstName': 'Peter',
'id': '1234',
'name': 'Parker'},
{'eMail': 'lucky#mail.example',
'firstName': 'Lucky',
'id': '123',
'name': 'Luke'},
{'eMail': 'micky#mail.example',
'firstName': 'Micky',
'id': '3456',
'name': 'Mouse'}],
'status': {'errorCode': 0,
'message': None,
'subErrorCode': None,
'success': True}}
out = []
for entry in d['returnData']:
pattern = 'mail.example'
email = entry.get('eMail', None)
if email and re.search(pattern, email):
out.append(email)
print(out)
Iterate over dict_['returnData'] to look for the eMail:
dict_ = {'returnData': [{'eMail': None,
'firstName': 'Peter',
'id': '1234',
'name': 'Parker'},
{'eMail': 'lucky#mail.example',
'firstName': 'Lucky',
'id': '123',
'name': 'Luke'},
{'eMail': 'micky#mail.example',
'firstName': 'Micky',
'id': '3456',
'name': 'Mouse'}],
'status': {'errorCode': 0,
'message': None,
'subErrorCode': None,
'success': True}}
for elem in dict_['returnData']:
print(elem['eMail'])
Note: use if elem['firstName']: print(elem['eMail']) for only two
enteries
OUTPUT:
None
lucky#mail.example
micky#mail.example
EDIT:
even better, using lists:
firstNames = []
names = []
emails = []
for elem in dict_['returnData']:
if elem['firstName']:
firstNames.append(elem['firstName'])
if elem['name']:
names.append(elem['name'])
if elem['eMail']:
emails.append(elem['eMail'])
print("First Names: {}".format(firstNames))
print("Names: {}".format(names))
print("Emails: {}".format(emails))
OUTPUT:
First Names: ['Peter', 'Lucky', 'Micky']
Names: ['Parker', 'Luke', 'Mouse']
Emails: ['lucky#mail.example', 'micky#mail.example']
Here‘s a simplified example of some data I have:
{"id": "1234565", "fields": {"name": "john", "email":"john#example.com", "country": "uk"}}
The wholeo nested dictionary is a bigger list of address data. The goal is to create pairs of people from the list with randomized partners where partners from the same country should be preferd. So my first real issue is to find a good way to group them by that country value.
I‘m sure there‘s a smarter way to do this than iterating through the dict and writing all records out to some new list/dict?
I think this is close to what you need:
result = {key:[i for i in value] for key, value in itertools.groupby(people, lambda item: item["fields"]["country"])}
What this does is use itertools.groupby to group all people in the people list by their specified country. The resulting dictionary has countries as keys, and the unpacked groupings (matching people) as values. Input is expected as a list of dictionaries like the one in your example:
people = [{"id": "1234565", "fields": {"name": "john", "email":"john#example.com", "country": "uk"}},
{"id": "654321", "fields": {"name": "sam", "email":"sam#example.com", "country": "uk"}}]
Sample output:
>>> print(result)
>>> {'uk': [{'fields': {'name': 'john', 'email': 'john#example.com', 'country': 'uk'}, 'id': '1234565'}, {'fields': {'name': 'sam', 'email': 'sam#example.com', 'country': 'uk'}, 'id': '654321'}]}
For a cleaner result, the looping construct can be tweaked so that only the ID of each person is included in the result dict:
result = {key:[i["id"] for i in value] for key, value in itertools.groupby(people, lambda item: item["fields"]["country"])}
>>> print(result)
>>> {'uk': ['1234565', '654321']}
EDIT: Sorry, I forgot about the sorting. Simply sort the list of people by country before putting it through groupby. It should now work properly:
sort = sorted(people, key=lambda item: item["fields"]["country"])
Here is another one that uses defaultdict:
import collections
def make_groups(nested_dicts, nested_key):
default = collections.defaultdict(list)
for nested_dict in nested_dicts:
for value in nested_dict.values():
try:
default[value[nested_key]].append(nested_dict)
except TypeError:
pass
return default
To test the results:
import random
COUNTRY = {'af', 'br', 'fr', 'mx', 'uk'}
people = [{'id': i, 'fields': {
'name': 'name'+str(i),
'email': str(i)+'#email',
'country': random.sample(COUNTRY, 1)[0]}}
for i in range(10)]
country_groups = make_groups(people, 'country')
for country, persons in country_groups.items():
print(country, persons)
Random output:
fr [{'id': 0, 'fields': {'name': 'name0', 'email': '0#email', 'country': 'fr'}}, {'id': 1, 'fields': {'name': 'name1', 'email': '1#email', 'country': 'fr'}}, {'id': 4, 'fields': {'name': 'name4', 'email': '4#email', 'country': 'fr'}}]
br [{'id': 2, 'fields': {'name': 'name2', 'email': '2#email', 'country': 'br'}}, {'id': 8, 'fields': {'name': 'name8', 'email': '8#email', 'country': 'br'}}]
uk [{'id': 3, 'fields': {'name': 'name3', 'email': '3#email', 'country': 'uk'}}, {'id': 7, 'fields': {'name': 'name7', 'email': '7#email', 'country': 'uk'}}]
af [{'id': 5, 'fields': {'name': 'name5', 'email': '5#email', 'country': 'af'}}, {'id': 9, 'fields': {'name': 'name9', 'email': '9#email', 'country': 'af'}}]
mx [{'id': 6, 'fields': {'name': 'name6', 'email': '6#email', 'country': 'mx'}}]
I have below json as input from the client
[
{'id': 0, 'name': 'Housing', 'value': 3},
{'id': 1, 'name': 'Bank', 'value': 8},
{'id': 2, 'name': 'Entertainment', 'value': 3}
]
It is being assigned to inputV_wc object in my view like below
View:
def savemore(request):
if request.method == "POST":
data=json.loads(request.body.decode())
inputV_wc = data['wc']
else:
response_data = 'You have not saved any data!'
return HttpResponse(response_data, content_type="text/plain")
try:
if not inputV_wc:
test=''
else:
# WC - Insert wc again on each save rather update - time consuming
if js_wex.objects.filter(pid = request.session.get('pid')).exists():
js_wex.objects.filter(pid=request.session.get('pid')).delete()
wc = js_wex(pid=request.session.get('pid'), wcname=inputV_wc[0]['name'],rating=inputV_wc[0]['value'],ordernum=inputV_wc[0]['id'])
wc.save()
wc = js_wex(pid=request.session.get('pid'), wcname=inputV_wc[1]['name'],rating=inputV_wc[1]['value'],ordernum=inputV_wc[1]['id'])
wc.save()
wc = js_wex(pid=request.session.get('pid'), wcname=inputV_wc[2]['name'],rating=inputV_wc[2]['value'],ordernum=inputV_wc[2]['id'])
wc.save()
except Exception as e:
response_data = 'Ouch! Something went wrong!'+str(e)
return HttpResponse(response_data, content_type="text/plain")
Currently if my input json has 5 rows, certainly the above view fails with Index out of range..
and if input json has 2 rows it again fails with missing entry - model cannot be saved.
How can I write my view such that if json has varied number of objects like
input from one user -
[
{'id': 0, 'name': 'Housing', 'value': 14},
{'id': 1, 'name': 'Bank', 'value': 18}
]
input from other user -
[
{'id': 0, 'name': 'Housing', 'value': 3},
{'id': 1, 'name': 'Bank', 'value': 18},
{'id': 2, 'name': 'Housing1', 'value': 14},
{'id': 3, 'name': 'Bank1', 'value': 12}
]
can be handled ?
Json rows could be from 1 to 15 maximum for each input.
I read about using **kwargs, for handling similar scenario.. but I couldn't figure out how to apply for saving my model for varied json input.
If I understand you correctly, I think you just want to use a for statement:
for row in inputV_wc:
wc = js_wex(pid=request.session.get('pid'), wcname=row['name'], rating=row['value'], ordernum=row['id'])
wc.save()
If you want to insert all the objects at once, based on what you have shown you could probably use bulk_create:
rows = []
for row in inputV_wc:
wc = js_wex(pid=request.session.get('pid'), wcname=row['name'], rating=row['value'], ordernum=row['id'])
rows.append(wc)
js_wex.objects.bulk_create(rows)