Comparing 2 lists and appending the differences into a 3rd - python

I have an issue and I can't for the life of me get anything to return past ()
exam_solution = ['B', 'D', 'A', 'A', 'C', 'A', 'B', 'A', 'C', 'D', 'B', 'C',\
'D', 'A', 'D', 'C', 'C', 'B', 'D', 'A']
student_answers = ['B', 'D', 'B', 'A', 'C', 'A', 'A', 'A', 'C', 'D', 'B', 'C',\
'D', 'B', 'D', 'C', 'C', 'B', 'D', 'A']
I need to compare the 2 lists and append the differences into questions_missed = []
I haven't found anything remotely close to working. Any help would be appreciated
edit: In python been stroking out over it all day.

use python list comprehensions to check list diff:
print [(index, i, j) for index, (i, j) in enumerate(zip(exam_solution, student_answers)) if i != j]
[(2, 'A', 'B'), (6, 'B', 'A'), (13, 'A', 'B')]

You can modify this solution to fit your needs:
exam_solution = ['B', 'D', 'A', 'A', 'C', 'A', 'B', 'A', 'C', 'D', 'B', 'C', 'D', 'A', 'D', 'C', 'C', 'B', 'D', 'A']
student_answers = ['B', 'D', 'B', 'A', 'C', 'A', 'A', 'A', 'C', 'D', 'B', 'C', 'D', 'B', 'D', 'C', 'C', 'B', 'D', 'A']
results = []
correct = 0
incorrect = 0
index = 0
while index < len(student_answers):
if student_answers[index] == exam_solution[index]:
results.append(True)
correct += 1
else:
results.append(False)
incorrect += 1
index += 1
print("You answered " + correct + " questions correctly and " + incorrect + " questions incorrectly.")

Using list comprehensions:
[x for i, x in enumerate(exam_solution) if exam_solution[i] != student_answers[i] ]
['A', 'B', 'A']

Assuming you want an output in common English like this -
Question 3 A != B
Question 7 B != A
Question 14 A != B
You could try -
from array import *
exam_solution = ['B', 'D', 'A', 'A', 'C', 'A', 'B', 'A', 'C', 'D', 'B', 'C',\
'D', 'A', 'D', 'C', 'C', 'B', 'D', 'A']
student_answers = ['B', 'D', 'B', 'A', 'C', 'A', 'A', 'A', 'C', 'D', 'B', 'C',\
'D', 'B', 'D', 'C', 'C', 'B', 'D', 'A']
questions_missed = []
count = 0
for answer in exam_solution:
if (answer != student_answers[count]):
questions_missed.append(count)
count = count + 1
for question in questions_missed:
print str.format("Question {0} {1} != {2}", question+1,
exam_solution[question], student_answers[question]);

Using the KISS design principle, that's how I'd do it:
exam_solution = ['B', 'D', 'A', 'A', 'C', 'A', 'B', 'A', 'C', 'D', 'B', 'C',\
'D', 'A', 'D', 'C', 'C', 'B', 'D', 'A']
student_answers = ['B', 'D', 'B', 'A', 'C', 'A', 'A', 'A', 'C', 'D', 'B', 'C',\
'D', 'B', 'D', 'C', 'C', 'B', 'D', 'A']
questions_missed = []
for index in range(len(exam_solution)):
# this assumes exam_solution and student_answers have the same size!
if exam_solution[index] != student_answers[index]:
questions_missed.append(index)
print (questions_missed)
And the output is:
[2, 6, 13]

L = [(a, b) for a, b in zip(exam_solution, student_answers) if a != b]
print(L)
Mybe you can use zip function.
The output is:
[('A', 'B'), ('B', 'A'), ('A', 'B')]

Solution (use set):
>>> def result(solution, answers):
... return set(str(n)+s for n, s in enumerate(solution)) - \
... set(str(n)+r for n, r in enumerate(answers))
...
>>> result(exam_solution, student_answers)
... set(['6B', '13A', '2A'])
>>>
The result are wrong responses (you can convert to list list(result(student_answers)).

Related

Iterating through a list for specific instances

I have the following code:
paths = [['E', 'D', 'A', 'B'], ['E', 'D', 'A', 'C', 'B'], ['E', 'D', 'B'], ['E', 'D', 'C', 'B'], ['E', 'B'], ['E', 'C', 'B']]
Now, the lists inside a list represent node paths from start to end which were made using Networkx, however that is some background information. My question is more specific.
I am trying to derive the lists that only have every letter from A-E, aka it would return only the list:
paths_desired = [['E', 'D', 'A', 'C', 'B']]
If I were to have another path:
paths = [['E', 'D', 'A', 'B'], ['E', 'D', 'A', 'C', 'B'], ['D', 'B', 'A','C','E'], ['A', 'D', 'C', 'B']]
It would return:
paths_desired = [['E', 'D', 'A', 'C', 'B'],['D', 'B', 'A', 'C', 'E']]
My idea is a for loop that iterates through each list:
for i in pathways:
counter = 0
for j in letters:
if j in i:
counter = counter + 1;
if counter == 5:
desired_paths.append(i)
print(desired_paths)
This works, however, I want to make the loop more specific, meaning I want only lists that have the following order: ['E','D','A','C','B'], even if all the letters are present in a different list, within the paths list.
Additionally, is there a way I can upgrade my for loop, so that I wouldn't count, rather check if the letters are in there, and not more than 1 of each letter? Meaning no multiple Es, no multiple D, etc.
You can use a use a set and .issubset() like this:
def pathways(letters, paths):
ret = []
letters = set(letters)
for path in paths:
if letters.issubset(path):
ret.append(path)
return ret
letters = ['A', 'B', 'C', 'D', 'E']
paths = [['E', 'D', 'A', 'B'], ['E', 'D', 'A', 'C', 'B'],
['D', 'B', 'A','C','E'], ['A', 'D', 'C', 'B']]
print(pathways(letters, paths)) # => [['E', 'D', 'A', 'C', 'B'], ['D', 'B', 'A', 'C', 'E']]
Also, as a comment by ShadowRanger pointed out, the pathways() function could be shortened using filter(). Like this:
def pathways(letters, paths):
return list(filter(set(letters).issubset, paths))
letters = ['A', 'B', 'C', 'D', 'E']
paths = [['E', 'D', 'A', 'B'], ['E', 'D', 'A', 'C', 'B'],
['D', 'B', 'A','C','E'], ['A', 'D', 'C', 'B']]
print(pathways(letters, paths))

Python global variable doesnt change

Example code:
podbor_dict = {}
def change(lst, sz):
lst_r = [lst[i:i+sz] for i in range(0, len(lst), sz)]
return lst_r
def qq():
global podbor_dict
if podbor_dict.get(
'podbor_'):
podbor = podbor_dict[
'podbor_']
podbor.clear()
else:
podbor_dict.update(
{'podbor_': []})
podbor = podbor_dict[
'podbor_']
podbor = ['a', 'b', 'c', 'd', 'a', 'b', 'c', 'd', 'a', 'b', 'c', 'd', 'a', 'b', 'c', 'd', 'a', 'b', 'c', 'd', 'a', 'b', 'c', 'd', 'a', 'b', 'c', 'd', ]
podbor = change(podbor, 10)
print(podbor)
def zz():
global podbor_dict
podbor = podbor_dict[
'podbor_']
print(podbor)
print(podbor_dict)
qq()
zz()
Function 'change' adds every ten elements to a new array.
Expected output:
[['a', 'b', 'c', 'd', 'a', 'b', 'c', 'd', 'a', 'b'], ['c', 'd', 'a', 'b', 'c', 'd', 'a', 'b', 'c', 'd'], ['a', 'b', 'c', 'd', 'a', 'b', 'c', 'd']]
[['a', 'b', 'c', 'd', 'a', 'b', 'c', 'd', 'a', 'b'], ['c', 'd', 'a', 'b', 'c', 'd', 'a', 'b', 'c', 'd'], ['a', 'b', 'c', 'd', 'a', 'b', 'c', 'd']]
{'podbor_': [['a', 'b', 'c', 'd', 'a', 'b', 'c', 'd', 'a', 'b'], ['c', 'd', 'a', 'b', 'c', 'd', 'a', 'b', 'c', 'd'], ['a', 'b', 'c', 'd', 'a', 'b', 'c', 'd']]}
Real output:
[['a', 'b', 'c', 'd', 'a', 'b', 'c', 'd', 'a', 'b'], ['c', 'd', 'a', 'b', 'c', 'd', 'a', 'b', 'c', 'd'], ['a', 'b', 'c', 'd', 'a', 'b', 'c', 'd']]
[]
{'podbor_': []}
Several times changed function 'change' but nothing helped.
Really looking forward your answer.
Hey I found a solution
podbor_dict = {}
def change(lst, sz):
lst_r = [lst[i:i+sz] for i in range(0, len(lst), sz)]
return lst_r
def qq():
global podbor_dict
global podbor
if podbor_dict.get(
'podbor_'):
podbor = podbor_dict[
'podbor_']
podbor.clear()
else:
podbor_dict.update(
{'podbor_': []})
podbor = podbor_dict[
'podbor_']
podbor = ['a', 'b', 'c', 'd', 'a', 'b', 'c', 'd', 'a', 'b', 'c', 'd', 'a', 'b', 'c', 'd', 'a', 'b', 'c', 'd', 'a', 'b', 'c', 'd', 'a', 'b', 'c', 'd', ]
podbor = change(podbor, 10)
print("fda" , podbor)
def zz():
global podbor_dict
global podbor
podbor_dict = {'podbor_': podbor}
print(podbor)
print(podbor_dict)
qq()
zz()
I made the variable podbor global and with the building from the dictionary you had an error
This is because you don't actually adding anything to it except for the 'podbor_' with empty list as value. Change the else block to
else:
podbor = ['a', 'b', 'c', 'd', 'a', 'b', 'c', 'd', 'a', 'b', 'c', 'd', 'a', 'b', 'c', 'd', 'a', 'b', 'c', 'd', 'a', 'b', 'c', 'd', 'a', 'b', 'c', 'd']
podbor = change(podbor, 10)
podbor_dict.update({'podbor_': podbor})
podbor = podbor_dict['podbor_']
# Output: [['a', 'b', 'c', 'd', 'a', 'b', 'c', 'd', 'a', 'b'], ['c', 'd', 'a', 'b', 'c', 'd', 'a', 'b', 'c', 'd'], ['a', 'b', 'c', 'd', 'a', 'b', 'c', 'd']]
# [['a', 'b', 'c', 'd', 'a', 'b', 'c', 'd', 'a', 'b'], ['c', 'd', 'a', 'b', 'c', 'd', 'a', 'b', 'c', 'd'], ['a', 'b', 'c', 'd', 'a', 'b', 'c', 'd']]
# {'podbor_': [['a', 'b', 'c', 'd', 'a', 'b', 'c', 'd', 'a', 'b'], ['c', 'd', 'a', 'b', 'c', 'd', 'a', 'b', 'c', 'd'], ['a', 'b', 'c', 'd', 'a', 'b', 'c', 'd']]}
podbor_dict = {}
def change(lst, sz):
lst_r = [lst[i:i+sz] for i in range(0, len(lst), sz)]
return lst_r
def qq():
global podbor_dict
if podbor_dict.get(
'podbor_'):
podbor_dict['podbor_'].clear()
# i also removed local variable declarations as they will be dropped at the end of the block anyway
else:
podbor_dict.update(
{'podbor_': []})
# we can say that if you assing value of dictionary to a variable, it will keep a reference to the list
# fi we then assign to this variable, we do not change a value in dictionary, but only the reference
# it is holding, thus dirrect assignment is needed
podbor = ['a', 'b', 'c', 'd', 'a', 'b', 'c', 'd', 'a', 'b', 'c', 'd', 'a', 'b', 'c', 'd', 'a', 'b', 'c', 'd', 'a', 'b', 'c', 'd', 'a', 'b', 'c', 'd', ]
podbor_dict["podbor_"] = change(podbor, 10)
print(podbor_dict["podbor_"])
def zz():
global podbor_dict
podbor = podbor_dict[
'podbor_']
print(podbor)
print(podbor_dict)
qq()
zz()

Need to permute list with order mattering after first two elements

Suppose l = ['a', 'b', 'c', 'd'] ...
I need to generate the following combinations/permutations from this list (in general, the list could have. more elements):
['a', 'b', 'c', 'd']
['a', 'b', 'd', 'c']
['a', 'c', 'b', 'd']
['a', 'c', 'd', 'b']
['a', 'd', 'b', 'c']
['a', 'd', 'c', 'b']
['b', 'c', 'a', 'd']
['b', 'c', 'd', 'a']
['b', 'd', 'a', 'c']
['b', 'd', 'c', 'a']
['c', 'd', 'a', 'b']
['c', 'd', 'b', 'a']
So, for the first two positions in the list order does not matter, although I need to take all combinations of list elements, while in the last two (or n) positions of the list order does matter. I've tried various combinations of using permutations and combinations from itertools, all with no success (I dare not post my code for fear of embarrassment).
The most direct solution using the existing itertools library functions is to select the first two elements as a combination, and then the rest as a permutation of the remaining elements:
import itertools
def partly_unordered_permutations(lst, k):
elems = set(lst)
for c in itertools.combinations(lst, k):
for d in itertools.permutations(elems - set(c)):
yield c + d
Usage:
>>> for p in partly_unordered_permutations('abcd', 2):
... print(p)
...
('a', 'b', 'c', 'd')
('a', 'b', 'd', 'c')
('a', 'c', 'b', 'd')
('a', 'c', 'd', 'b')
('a', 'd', 'b', 'c')
('a', 'd', 'c', 'b')
('b', 'c', 'a', 'd')
('b', 'c', 'd', 'a')
('b', 'd', 'a', 'c')
('b', 'd', 'c', 'a')
('c', 'd', 'a', 'b')
('c', 'd', 'b', 'a')

how to display students in increasing order based on correct answers in python

okay so I'm writing this code but am not sure how to put the students in order of least to greatest correct answers. The out put should be "Student 3's number of correct answers is 4" and so on.
Here's my current code:
def main():
answers = [
['A', 'B', 'A', 'C', 'C', 'D', 'E', 'E', 'A', 'D'],
['D', 'B', 'A', 'B', 'C', 'A', 'E', 'E', 'A', 'D'],
['E', 'D', 'D', 'A', 'C', 'B', 'E', 'E', 'A', 'D'],
['C', 'B', 'A', 'E', 'D', 'C', 'E', 'E', 'A', 'D'],
['A', 'B', 'D', 'C', 'C', 'D', 'E', 'E', 'A', 'D'],
['B', 'B', 'E', 'C', 'C', 'D', 'E', 'E', 'A', 'D'],
['B', 'B', 'A', 'C', 'C', 'D', 'E', 'E', 'A', 'D'],
['E', 'B', 'E', 'C', 'C', 'D', 'E', 'E', 'A', 'D']]
key = ['D', 'B', 'D', 'C', 'C', 'D', 'A', 'E', 'A', 'D']
for i in range(len(answers)):
correctCount = 0
for j in range(len(answers[i])):
if answers[i][j] == key[j]:
correctCount +=1
print("Student", i, "'s correct count is", correctCount)
main()
I think is best you split the problem in steps:
Determine the number of correct answers
Sort the output
Given the previous steps, you could do the following:
answers = [
['A', 'B', 'A', 'C', 'C', 'D', 'E', 'E', 'A', 'D'],
['D', 'B', 'A', 'B', 'C', 'A', 'E', 'E', 'A', 'D'],
['E', 'D', 'D', 'A', 'C', 'B', 'E', 'E', 'A', 'D'],
['C', 'B', 'A', 'E', 'D', 'C', 'E', 'E', 'A', 'D'],
['A', 'B', 'D', 'C', 'C', 'D', 'E', 'E', 'A', 'D'],
['B', 'B', 'E', 'C', 'C', 'D', 'E', 'E', 'A', 'D'],
['B', 'B', 'A', 'C', 'C', 'D', 'E', 'E', 'A', 'D'],
['E', 'B', 'E', 'C', 'C', 'D', 'E', 'E', 'A', 'D']]
def number_of_correct_answers(answers, golden=['D', 'B', 'D', 'C', 'C', 'D', 'A', 'E', 'A', 'D']):
"""Return the number of correct answers given a gold standard"""
return sum(g == a for g, a in zip(golden, answers))
for student_answer in sorted(answers, key=number_of_correct_answers, reverse=True): # the best come first
print(student_answer, 'Number of correct', number_of_correct_answers(student_answer))
Output
['A', 'B', 'D', 'C', 'C', 'D', 'E', 'E', 'A', 'D'] Number of correct 8
['A', 'B', 'A', 'C', 'C', 'D', 'E', 'E', 'A', 'D'] Number of correct 7
['B', 'B', 'E', 'C', 'C', 'D', 'E', 'E', 'A', 'D'] Number of correct 7
['B', 'B', 'A', 'C', 'C', 'D', 'E', 'E', 'A', 'D'] Number of correct 7
['E', 'B', 'E', 'C', 'C', 'D', 'E', 'E', 'A', 'D'] Number of correct 7
['D', 'B', 'A', 'B', 'C', 'A', 'E', 'E', 'A', 'D'] Number of correct 6
['E', 'D', 'D', 'A', 'C', 'B', 'E', 'E', 'A', 'D'] Number of correct 5
['C', 'B', 'A', 'E', 'D', 'C', 'E', 'E', 'A', 'D'] Number of correct 4
The key of the functionaly above relies on the functions: sum and sorted. In the example above the better students come first, if you want the other way around just remove the reverse=True parameter.
See:
Sorting - HOWTO

using lambda or list comprehesion to create list with loop

for the following code, how I can write into one line using lambda function or using python list comprehension?
def f():
lst=[]
for i in range(1, 101):
if i < 50:
lst.append('A')
else:
lst.append('B')
return lst
You can use a ternary conditional in a list comprehension:
lst = ['A' if i < 50 else 'B' for i in range(1, 101)]
Note that your function outputs 49 'A's and 51 'B's. I'm not sure if that's intentional.
The easiest way to get 50/50 would be :
['A'] * 50 + ['B'] * 50
If you want to define a lambda:
>>> a_or_b = lambda x: 'AB'[x>50]
>>> [a_or_b(x) for x in range(1,101)]
['A', 'A', 'A', 'A', 'A', 'A', 'A', 'A', 'A', 'A', 'A', 'A', 'A', 'A', 'A', 'A', 'A', 'A', 'A', 'A', 'A', 'A', 'A', 'A', 'A', 'A', 'A', 'A', 'A', 'A', 'A', 'A', 'A', 'A', 'A', 'A', 'A', 'A', 'A', 'A', 'A', 'A', 'A', 'A', 'A', 'A', 'A', 'A', 'A', 'B', 'B', 'B', 'B', 'B', 'B', 'B', 'B', 'B', 'B', 'B', 'B', 'B', 'B', 'B', 'B', 'B', 'B', 'B', 'B', 'B', 'B', 'B', 'B', 'B', 'B', 'B', 'B', 'B', 'B', 'B', 'B', 'B', 'B', 'B', 'B', 'B', 'B', 'B', 'B', 'B', 'B', 'B', 'B', 'B', 'B', 'B', 'B', 'B', 'B', 'B']
As a one-liner :
['AB'[x>50] for x in range(1,101)]
or
['AB'[x>=50] for x in range(100)]
Those comprehensions use the fact that False is 0 and True is 1, and that 'AB'[0] is 'A' and 'AB'[1]is'B'`.
The code, mirroring yours, would be like this:
def f():
return ['A' if i < 50 else 'B' for i in range(1,101)]

Categories

Resources