-3

I'm having some problems with my code below. I have my two lists names and scores. These lists, correspond with each other as seen below. My goal is to print out the first three greatest items in both lists. I've attempted to sort them together from greatest to least and then print out the first three items, but I'm getting some unbounderror. Any thoughts? Thanks.

names = ['Xander', 'Spec', 'Meng', 'Sparc', 'Jones', 'Nick', 'Link']
scores = [120, 450, 300, 200, 66, 183, 80]

scores, names = (list(t) for t in zip(*sorted(zip(scores, names))))
print(names[:3] + " " + scores[:3])

Example Output:

Spec 450
Meng 300
Sparc 200
  • 3
    What's the exact error? There shouldn't be anything unbound here. – Carcigenicate Mar 11 '19 at 19:15
  • 1
    You have not included the error. You are trying to concatenate str with list which is not possible. Try:`" ".join(map(str,scores[:3])` – mad_ Mar 11 '19 at 19:18

8 Answers8

2

the only issue with your code is the print part (and you'd have to reverse the sort):

scores, names = (list(t) for t in zip(*sorted(zip(scores, names), reverse=True)))

for name, score, _i in zip(scores, names, range(3)):
    print(name, score)

# 450 Spec
# 300 Meng
# 200 Sparc

i'd suggest you use collections.Counter:

from collections import Counter

names = ['Xander', 'Spec', 'Meng', 'Sparc', 'Jones', 'Nick', 'Link']
scores = [120, 450, 300, 200, 66, 183, 80]

counter = Counter({name: score for name, score in zip(names, scores)})
print(counter.most_common(3))
# [('Spec', 450), ('Meng', 300), ('Sparc', 200)]

you could then format the result the way you prefer.

hiro protagonist
  • 44,693
  • 14
  • 86
  • 111
2

You can use heapq.nlargest:

from heapq import nlargest
for score, name in nlargest(3, zip(scores, names)):
    print(name, score)

This outputs:

Spec 450
Meng 300
Sparc 200
blhsing
  • 91,368
  • 6
  • 71
  • 106
0

If your problem is in the print part:

for i in range(3):
    print(names[i], scores[i])
Daniel Möller
  • 84,878
  • 18
  • 192
  • 214
0

Your print in the last line is wrong. you can not concatenate list object with str like that. do this instead:

scores, names = (list(t) for t in zip(*sorted(zip(scores, names), reverse=True)))

for i in range(3):
    print(names[i], scores[i])

NOTE: reverse=True is for sort the lists in reverse order (DESC).

Mojtaba Kamyabi
  • 3,440
  • 3
  • 29
  • 50
0

It looks like you're trying to concatenate two lists and a string within your print statement. Daniel Möller's answer is correct. Also you may need to pass True to the reverse= keyword argument, otherwise you'll get the smallest three:

names = ['Xander', 'Spec', 'Meng', 'Sparc', 'Jones', 'Nick', 'Link']
scores = [120, 450, 300, 200, 66, 183, 80]

scores, names = (list(t) for t in zip(*sorted(zip(scores, names), reverse=True)))

for i in range(3):
    print(names[i], scores[i]) 

Spec 450
Meng 300
Sparc 200
scratchpad
  • 276
  • 1
  • 6
0

here is the solution

names = ['Xander', 'Spec', 'Meng', 'Sparc', 'Jones', 'Nick', 'Link']
scores = [120, 450, 300, 200, 66, 183, 80]
data = list(zip(names, scores))
print(data)
# output [('Xander', 120), ('Spec', 450), ('Meng', 300), ('Sparc', 200), ('Jones', 66), ('Nick', 183), ('Link', 80)]
data.sort(key=lambda x:x[1], reverse=True)
print(data)
# output [('Spec', 450), ('Meng', 300), ('Sparc', 200), ('Nick', 183), ('Xander', 120), ('Link', 80), ('Jones', 66)]


for name, score in data:
    print(name,score,sep='\t')

""" output 
Spec    450
Meng    300
Sparc   200
Nick    183
Xander  120
Link    80
Jones   66
"""

as changes suggested, this can be done in a more elegant way like this.

names = ['Xander', 'Spec', 'Meng', 'Sparc', 'Jones', 'Nick', 'Link']
scores = [120, 450, 300, 200, 66, 183, 80]
data = list(zip(scores, names))
print(data)
# output [(120, 'Xander'), (450, 'Spec'), (300, 'Meng'), (200, 'Sparc'), (66, 'Jones'), (183, 'Nick'), (80, 'Link')]
data.sort(reverse=True)
print(data)
# output [(450, 'Spec'), (300, 'Meng'), (200, 'Sparc'), (183, 'Nick'), (120, 'Xander'), (80, 'Link'), (66, 'Jones')]

for score, name in data:
    print(name,score,sep='\t')

""" output 
Spec    450
Meng    300
Sparc   200
Nick    183
Xander  120
Link    80
Jones   66
"""

using itemgetter as suggested by @Jab

names = ['Xander', 'Spec', 'Meng', 'Sparc', 'Jones', 'Nick', 'Link']
scores = [120, 450, 300, 200, 66, 183, 80]
data = list(zip(names, scores))
print(data)
# output [('Xander', 120), ('Spec', 450), ('Meng', 300), ('Sparc', 200), ('Jones', 66), ('Nick', 183), ('Link', 80)]
from operator import itemgetter
data.sort(key=itemgetter(1), reverse=True)
print(data)
# output [('Spec', 450), ('Meng', 300), ('Sparc', 200), ('Nick', 183), ('Xander', 120), ('Link', 80), ('Jones', 66)]


for name, score in data:
    print(name,score,sep='\t')

""" output 
Spec    450
Meng    300
Sparc   200
Nick    183
Xander  120
Link    80
Jones   66
"""
sahasrara62
  • 10,069
  • 3
  • 29
  • 44
  • You can change the order inside the `zip` to (scores,names) and then you need not to pass the key argument in `sort`. Nothing fancy but will be much more elegant – mad_ Mar 11 '19 at 19:32
  • Also `operator.itemgetter(1)` is more prefered than `lambda x: x[1]` It's more efficient and reads better – Jab Mar 11 '19 at 19:35
  • @mad_ yeah that was helpful. – sahasrara62 Mar 11 '19 at 19:45
  • @Jab operator.itemgetter(1) is more readable(cann't say about efficiency), i don't want to include extra library , that is why i stick with lambda approach. – sahasrara62 Mar 11 '19 at 19:47
  • `operator` is a builtin library and it is more efficient and powerful. See: [operator.itemgetter or lambda](https://stackoverflow.com/questions/17243620/operator-itemgetter-or-lambda/17243726) – Jab Mar 11 '19 at 19:53
  • @Jab yeah, you are right, didn't know this performance difference, thanks for suggesting. – sahasrara62 Mar 11 '19 at 20:33
  • Not that it's a huge difference, but it's good to get in the habit of using something more readable and better especially when it's included as a builtin. `lambda` may be faster/easier to type in but readability counts. And the performace impact will be there when it's needed – Jab Mar 11 '19 at 20:36
  • @Jab yeah readability counts, if u see the solution by jdharo [operator.itemgetter or lambda](https://stackoverflow.com/questions/17243620/operator-itemgetter-or-lambda/17243726) then I think it's great performance gap. – sahasrara62 Mar 11 '19 at 20:37
0

You can zip and sort the data using operator.itemgetter then print the data like so:

from operator import itemgetter

names = ['Xander', 'Spec', 'Meng', 'Sparc', 'Jones', 'Nick', 'Link']
scores = [120, 450, 300, 200, 66, 183, 80]

data = sorted(zip(names, scores), key=itemgetter(1), reverse=True)
for name, score in data[:3]:
    print(f"{name}: {score}")

This outputs:

Spec: 450
Meng: 300
Sparc: 200
Jab
  • 26,853
  • 21
  • 75
  • 114
0

If names are unique I suggest usage of dict, following way:

names = ['Xander', 'Spec', 'Meng', 'Sparc', 'Jones', 'Nick', 'Link']
scores = [120, 450, 300, 200, 66, 183, 80]
high = sorted([i for i in d.items()],key=lambda x:x[1],reverse=True)[:3]
for i in high:
    print(i[0],i[1])

Output:

Spec 450
Meng 300
Sparc 200

key in sorted is used to point that it should sort by value (2nd one, as indexing start at 0) and reverse is meaning desceding order.

Daweo
  • 31,313
  • 3
  • 12
  • 25