0

Suppose I have two lists, one is student ID studentID=[1,4,2,3,5,10], the other is related scores for each individual student in the same index of the list studentScore=[1.0, 2.5, 3.0, 2.1, 5.0, 4.5] (which means student with ID 1 has score 1.0, student with ID 4 has score 2.5, etc.), I want to order student ID by score (ascending order), which expected output is #[1,3,4,2,10,5].

My current solution is a bit naive, which setup a student class. In Python 2.7, wondering if any other ways to get sorted result of student ID based on related scores without using an additional class to setup their (two lists) relationship?

Post my current code below,

class Student:
    def __init__(self, ID, score):
        self.ID = ID
        self.score = score
    def __cmp__(self, other):
        return cmp(self.score, other.score)

studentID=[1,4,2,3,5,10]
studentScore=[1.0, 2.5, 3.0, 2.1, 5.0, 4.5]

students = []
for i in range(len(studentID)):
    students.append(Student(studentID[i], studentScore[i]))

sorted(students)
for i in students:
    print i.ID

# expect output: sorted student ID by student score
#[1,3,4,2,10,5]
Lin Ma
  • 9,739
  • 32
  • 105
  • 175
  • 2
    `sorted(students)` -> `students.sort()` or maybe `for i in sorted(students)`. – Łukasz Rogalski Sep 27 '16 at 07:29
  • 1
    Actually, the solution linked above (about ``sorted()`` vs ``.sort()``) does not answer this question. It's rather this one: http://stackoverflow.com/questions/6618515/sorting-list-based-on-values-from-another-list – jbndlr Sep 27 '16 at 07:36

3 Answers3

2

Solution

sid = [1, 4, 2, 3, 5, 10]
scores = [1.0, 2.5, 3.0, 2.1, 5.0, 4.5]

print([stid for (score, stid) in sorted(zip(scores, sid))])

yields

[1, 3, 4, 2, 10, 5]

Explanation

The call zip(scores, sid) joins the two lists based on the items' positions into a list of tuples:

[(1.0, 1), (2.5, 4), (3.0, 2), (2.1, 3), (5.0, 5), (4.5, 10)]

The call to sorted(...) sorts the zipped tuple-list by the first item of each tuple:

[(1.0, 1), (2.1, 3), (2.5, 4), (3.0, 2), (4.5, 10), (5.0, 5)]

The enclosing list comprehension [stid for (score, stid) in ...] then only pulls the second argument (here referred to as stid) from each tuple and creates a new list while maintaining the new order:

[1, 3, 4, 2, 10, 5]
jbndlr
  • 4,965
  • 2
  • 21
  • 31
  • Cool, I do not know `zip` is so powerful! – Lin Ma Sep 27 '16 at 07:31
  • BTW jbndir, debugged my original code, my original code output is `1 4 2 3 5 10`, the right result should be `1,3,4,2,10,5`, what is wrong with my code? – Lin Ma Sep 27 '16 at 07:37
  • 1
    You used ``sorted()``, which does not sort the list in-place. You have to assign its result to a variable: ``students = sorted(students)`` or ``students.sort()``. – jbndlr Sep 27 '16 at 07:39
  • Mark your reply as answer. BTW. – Lin Ma Sep 27 '16 at 07:39
1

The solution is actually ok, but for smaller tasks like this, instead of declaring a new class, you can use sorted's key kwarg:

studentID=[1,4,2,3,5,10]
studentScore=[1.0, 2.5, 3.0, 2.1, 5.0, 4.5]
combined = zip(studentID, studentScore)
comb_sorted = sorted(combined, key=lambda pair: pair[1])
sortedID, sortedScore = list(zip(*comb_sorted))

You tell sorted that the key is the second item from each pair, which is the score.

alexpeits
  • 847
  • 8
  • 18
  • Thanks Alex, debugged my original code, my original code output is `1 4 2 3 5 10`, the right result should be `1,3,4,2,10,5`, what is wrong with my code? – Lin Ma Sep 27 '16 at 07:36
1

This one liner would sort the scores and ids by the score:

studentScore,studentID=zip(*sorted(zip(studentScore,studentID)))
Uri Goren
  • 13,386
  • 6
  • 58
  • 110
  • Thanks Uri, debugged my original code, my original code output is `1 4 2 3 5 10`, the right result should be `1,3,4,2,10,5`, what is wrong with my code? – Lin Ma Sep 27 '16 at 07:36