I'm new to Python and looking to figure out how to code this properly. I have two lists of dictionaries and I'm trying to find if the student ID exists in a string that can contain the student ID and other information. My badly formed approach:
confirmed_students = [{'div_school_id': 'as-dh23d7ashdh'}, {'div_school_id': 'asdas-3sdfasd'}, {'div_school_id': 'i4-d9asjcg'}]
students = [{'student_id': 'dh23d7ashdh','name': 'First Last','student_grade': '4'}, {'student_id':'3sdfasd', 'name':...}]
bad_list = []
for student in students:
if student['student_id'] not in confirmed_students:
bad_list.append({"id": student['student_id'], "name": student['name'], "grade": student['student_grade']})
What would be the proper way to do this? Should I iterate through the list of dicts confirmed_students in the same loop? I only need to know if the student_id from the list of dicts called students exists at all in the list of dicts called confirmed_students and add the relevant info.
You can build the list using list comprehension:
bad_list = [{k: student[v] for k, v in zip(('id', 'name', 'grade'), ('student_id', 'name', 'student_grade'))} for student in students if student['student_id'] not in confirmed_students]
Sidenote: I suggest you define the students as a dictionary using the student_id as key (assuming it is unique, which it should). It will make it much more easier to perform comparisons like the one you want.
A brute force way of getting there (and probably not the most efficient) is to loop over both lists. Check if each element of students is in confirmed_students.
Firstly, you need a way of knowing if the student is in the confirmed_students list. There must be a key to match on. Looking at your data it seems as if confirmed_students has div_school_id that is some kind of composite of the student_id and some prefix.
# looking at one confirmed student as an example
confirmed_student = confirmed_students[0]
# confirmed_student = {'div_school_id': 'as-dh23d7ashdh'}
# we need to split the id on the '-' and keep the last part
confirmed_student_id = confirmed_student['div_school_id'].split("-")[1]
# gives us confirmed_student_id as 'dh23d7ashdh' which looks right?
# now we loop over your students and see if their id is in confirmed_students
bad_list = []
for student in students:
for confirmed_student in confirmed_students:
confirmed_student_id = confirmed_student['div_school_id'].split("-")[1]
if student["student_id"] == confirmed_student_id:
bad_list.append({"id": student['student_id'], "name": student['name'], "grade": student.get('student_grade', '')})
# break from the inner loop and continue the outer loop
# because we only need the first match
break
Related
This is my first time submitting here, so please bear with me on formatting.
So, I have a normal list of strings like:
name = ["Michael", "Helen", "Mike", "Joe", "Michael"]
I need to append these to another list if they don't repeat, and then later print out that list. So the next list would be like
norepeat_list = ["Michael", "Helen", "Mike", "Joe"]
Which I've already done and didn't have issues with. The problem is I'm not just appending those names, each name has another value associated with it in another list of times (also strings), and I need that too. So I've been appending both the name and the times at the same time in a list like
norepeat_list.append(name[i], time[i])
Which then makes the result a 2d list. So I don't know how to make it so that the program checks each list in the list for the original name value, and the only solution I've found is 'any' or some import stuff, and I can't do that.
So far I have:
name = ["Michael", "Helen", "Mike", "Joe", "Michael"]
time = ["08:42:39", "08:39:56", "08:58:43", "09:04:03", "05:32:54"]
norepeat_list = []
for i in range(len(name[i])):
if name[i] not in norepeat_list:
norepeat_list.append(name[i])
for i in norepeat_list:
print(i)
I've tried appending the timestamp at the same time and adding another layer of for j in ..., but I can't get anything to work.
The closest working code I can think of to your example is:
name = ["Michael", "Helen", "Mike", "Joe", "Michael"]
time = ["08:42:39", "08:39:56", "08:58:43", "09:04:03", "05:32:54"]
seen_names = []
norepeat_list = []
for i in range(len(name)):
if name[i] not in seen_names:
seen_names.append(name[i])
norepeat_list.append((name[i], time[i]))
for name_time in norepeat_list:
print(name_time)
but note that I've introduced an extra seen_names array to keep track of things you've already seen. Having this extra list is bad for maintenance as you need to make sure both lists stay in sync with each other. It's also bad for performance as checking whether an item is in a list takes time proportional to the length of the list, i.e. it gets slower for longer lists. It would be better to use a set to track the items you've seen, as this wouldn't slow down as more items get added.
A more significant improvement would be to use a dictionary/dict which allows you to associate arbitrary data (i.e. your times) with a set of items (i.e. your names). A naive translation of the above code would be:
names = ["Michael", "Helen", "Mike", "Joe", "Michael"]
times = ["08:42:39", "08:39:56", "08:58:43", "09:04:03", "05:32:54"]
names_and_times = {}
for i in range(len(names)):
if names[i] not in names_and_times:
names_and_times[names[i]] = times[i]
for name_time in names_and_times.items():
print(name_time)
Note that I've switched to a naming convention where plurals indicate a container of multiple values.
This could be improved by noticing that it repeats names[i] a lot. An way to reduce this would be to use enumerate:
names_and_times = {}
for i, name in enumerate(names):
if name not in names_and_times:
names_and_times[name] = times[i]
or alternatively, you could use zip as many other answers have suggested:
names_and_times = {}
for name, time in zip(names, times):
if name not in names_and_times:
names_and_times[name] = time
another variant would be to exploit the fact that dictionaries can't have duplicates, so setting a dictionary item with the same item multiple times would just change the value rather than adding a new entry:
names_and_times = {}
for name, time in zip(names, times):
names_and_times[name] = time
Note that this leaves the last time set for each name rather than the first. Your question doesn't seem to express a preference, but this could be changed by iterating in reverse order:
names_and_times = {}
for name, time in zip(reversed(names), reversed(times)):
names_and_times[name] = time
Next we could use a dictionary comprehension, which cleans the above up to:
names_and_times = {
name: time
for name, time in zip(names, time)
}
Finally we get to my original comment about things being magical, which exploits this usage of zip and the fact that passing an Iterable of pairs causes the constructor of a dict to build a dictionary where the first item of each pair is the key and the second item is the value:
names_and_times = dict(zip(names, times))
or if you want the first time for each name you could do:
names_and_times = dict(zip(reversed(names), reversed(times)))
All of my examples leave names_and_times as a dictionary, but if you wanted to convert back to a list you can just do:
names_and_times = list(names_and_times.items())
In this case I advise you use the "zip" function.
for n,t in zip(name,time):
print(n,t)
this will zip the two lists together and you have access to the values of both lists.
As you wrote "each name has another value associated with it in another list of times" I assume name and time has the same length, then something like this would work
zip produces a tuple of elements from both lists on the same position, so it will maintain the order, and skip elements with non-unique names (because they added to the seen):
seen = set()
result = []
for n, t in zip(name, time):
if n not in seen:
seen.add(n)
result.append((n, t))
print(result)
I have a list of dictionaries, which all have the same keys. I have a specific value of one key and want to access/print the dictionary, which contains this specific value. I couldn't think of any way, other than looping around the whole list, checking the corresponding value of the key and printing it out using if statement, that is if the given value matched the key.
for enrollment in enrollments:
if enrollment['account_key'] == a:
print(enrollment)
else:
continue
This does not really seem the most efficient way to handle the task. What would be a better solution?
Some options:
1- Use the loop like you do here, although this could be written simpler without the continue.
for enrollment in enrollments:
if enrollment['account_key'] == a:
print(enrollment)
2- Use a generator expression and next
enrollment = next(e for e in enrollments if e['account_key'] == a)
print(enrollment)
3- Convert the list of dictionaries into a dictionary of dictionaries. This is a good option if you have to do this operation many times and there is only one value for each account_key
accounts = {
enrollment['account_key']: enrollment
for enrollment in enrollments
}
print(accounts[a])
4- Same as above, but if there are multiple values for the same key, you can use a dict of lists of dicts.
accounts = defaultdict(list)
for enrollment in enrollments:
accounts[enrollment['account_key']].append(enrollment)
for enrollment in accounts[a]:
print(enrollment)
You can use a comprehension (iterator) to get the subset of dictionaries that match your criteria. In any case this will be a sequential search process.
enrolments = [ {'account_key':1, 'other':99},
{'account_key':2, 'other':98},
{'account_key':1, 'other':97},
{'account_key':1, 'other':96},
{'account_key':3, 'other':95} ]
a = 1
found = (d for d in enrolments if d['account_key']==a)
print(*found,sep="\n")
{'account_key': 1, 'other': 99}
{'account_key': 1, 'other': 97}
{'account_key': 1, 'other': 96}
New to python and for this example list
lst = ['<name>bob</name>', '<job>doctor</job>', '<gender>male</gender>', '<name>susan</name>', '<job>teacher</job>', '<gender>female</gender>', '<name>john</name>', '<gender>male</gender>']
There are 3 categories of name, job, and gender. I would want those 3 categories to be on the same line which would look like
<name>bob</name>, <job>doctor</job>, <gender>male</gender>
My actual list is really big with 10 categories I would want to be on the same line. I am also trying to figure out a way where if one of the categories is not in the list, it would print something like N/A to indicate that it is not in the list
for example I would want it to look like
<name>bob</name>, <job>doctor</job>, <gender>male</gender>
<name>susan</name>, <job>teacher</job>, <gender>female</gender>
<name>john</name>, N/A, <gender>male</gender>
What would be the best way to do this?
This is one way to do it. This would handle any length list, and guarantee grouping no matter how long the lists are as long as they are in the correct order.
Updated to convert to dict, so you can test for key existence.
lst = ['<name>bob</name>', '<job>doctor</job>', '<gender>male</gender>', '<name>susan</name>', '<job>teacher</job>', '<gender>female</gender>', '<name>john</name>', '<gender>male</gender>']
newlst = []
tmplist = {}
for item in lst:
value = item.split('>')[1].split('<')[0]
key = item.split('<')[1].split('>')[0]
if '<name>' in item:
if tmplist:
newlst.append(tmplist)
tmplist = {}
tmplist[key] = value
#handle the remaining items left over in the list
if tmplist:
newlst.append(tmplist)
print(newlst)
#test for existance
for each in newlst:
print(each.get('job', 'N/A'))
I have two values number and sys_id. I have made seperate list for both of the values. How can save it in any other data structure like dictionary, or something else because i those list of number and sys_id are related. I am doing it in Python
Below Is the code what i have done
ticket_num.append(resp['result'][idx]['number'])
sys_id.append(resp['result'][idx]['sys_id']) ```
This is making two list one for ticket_num and sys_id. As Ticket number and sys_id are related for example ticket_num = ['INC00012','INC00013','INC00014' ] ,
sys_id = ['644323432sfasesdf213', '644323432dfgdfkdskrwwr', 'f283044423fdldsf09']
As this list are related like ticket_num[0] is directly link with sys_id[0]
So can i make a dictionary that contains ticket_num, sys_id directly without creating lists(for e.g. : {ticket_num : '...' , sys_id = '....' , ..... }
Use zip with dict
Ex:
ticket_num = ['INC00012','INC00013','INC00014' ]
sys_id = ['644323432sfasesdf213', '644323432dfgdfkdskrwwr', 'f283044423fdldsf09']
print(dict(zip(ticket_num, sys_id)))
Output:
{'INC00012': '644323432sfasesdf213',
'INC00013': '644323432dfgdfkdskrwwr',
'INC00014': 'f283044423fdldsf09'}
Welcome to Stackoverflow.
Do you actually need the lists of ticket numbers and IDs? If not that you could instead consider building the structure you need instead of the lists.
You don't say whether you want to be able to look up IDs from ticket numbers or vice versa. This solution allows you to do either:
idx_from_ticket = {}
ticket_from_idx = {}
# In the loop that produces the values, instead of the current appends ...
temp = resp['result'][idx]
idx = temp['sys_id]
number = temp['number']
idx_from_ticket[number] = idx
ticket_from_idx[idx] = number
The two dictionaries can then be used to correlate the IDs and ticket numbers. If you want to actually do something else then I hope this code gives you enough clues.
If you do already have the lists and want to retain them then the zip function is your friend.
idx_from_ticket = dict(zip(ticket_num, sys_id))
ticket_from_idx = dict(zip(sys_id, ticket_num))
zip, when called with two argument, yields a sequence of two-element tuples, which the
dict function assumes are key/value pairs.
I am trying to create an automated python procedure that uses two separate lists to create a dictionary and so far I am failing. I have two sorted lists where the nth item in the fist list corresponds to the nth item in the second list and I want to combine them into a dictionary.
For example, a subset of the 2 lists are as follows;
name = ['Adam', 'Alfred', 'Amy', 'Andy', 'Bob']
year = [1972, 1968, 1985, 1991, 1989]
I would want my output to be:
birth_years = {'Adam':1972, 'Alfred':1968, 'Amy':1985, 'Andy':1991, 'Bob':1989}
I was trying to do this with a for loop, but I could not get it to work. I appreciate any help.
Use the zip and dict functions to construct a dictionary out of a list of tuples:
birth_years = dict(zip(name, year))
And if you're curious, this would be how I would try to do it with a for loop:
birth_years = {}
for index, n in enumerate(name):
birth_years[n] = years[index]
I think I like the first example more.
birth_years = {}
for i in range(len(name)):
birth_years[name[i]] = year[i]
Try a dictionary comprehension:
birth_years = {nm:year[idx] for idx, nm in enumerate(name)}
Your lists would be better named names and years. You got off to a good start by trying to do it with a for loop. Most practical data processing problems involve error checking, which is just a tad difficult with one-liners. Example:
birth_years = {}
for i, name in enumerate(names):
if name in birth_years:
log_duplicate(i, name, years[i]))
else:
birth_years[name] = years[i]