20

I have a list which has the number of marks students have.

s = [50,62,15,76,57,97,82,99,45,23]

I want to grade students according to marks:

<40 - Fail
>50 - A Grade
>75 - A++ Grade

I can do this with iterating loops or I can find every list using lambda. for example :

>>> filter(lambda x:x>=50, s)
[50, 62, 76, 57, 97, 82, 99]

But, in the filter, I can work with only one function at a time (for example : marks greater than 50). Is there way where I can use filter and lambda and get required result in one line? Expecting the output as marks with grade. (ex : 50 - A, 62 - A, 76 - A++ ...)

sashkello
  • 17,306
  • 24
  • 81
  • 109
sam
  • 18,509
  • 24
  • 83
  • 116

4 Answers4

21

Define a function that takes a mark and returns a human readable representation, you can use larsmans's expression or this one:

def grade(i):
    if i<40: return "Fail"
    if i>75: return "A++"
    if i>50: return "A"

Use string.format to format each entry and map to iterate over all of them:

li = map(lambda x: "{0} - {1}".format(x, grade(x)), s)

The resulting list now contains strings in the desired format.

for i in li: print i

# output

50 - None
62 - A
15 - Fail
76 - A++
57 - A
97 - A++
82 - A++
99 - A++
45 - None
23 - Fail
Community
  • 1
  • 1
Mizipzor
  • 51,151
  • 22
  • 97
  • 138
15

Forget lambda, forget filter; the following does the grading in one expression, assuming there's a B grade between A and "fail".

["fail" if g < 40 else "B" if g < 60 else "A" if g < 75 else "A++" for g in s]

You can zip the result of this with s to get marks and grades in one list.

Fred Foo
  • 355,277
  • 75
  • 744
  • 836
  • Or you can use map, `map(lambda x: (x, 'F' if x<40 else 'A++' if x>70 else 'A'), s)`. Or just lose the `(x,` (and `)` of course) if you want just grades. List is ordered so you can match it later on. – rplnt Mar 15 '12 at 11:01
  • You comprehension is at 78 characters. You get free line breaks in them. I know it goes against Google Python style rules, but I prefer to break them over multiple lines, possibly at the end of each `else`. – yurisich Aug 31 '12 at 23:37
  • @Droogans: I'm not aware of Google style rules, but in a practical program I would indeed put some linebreaks in. http://stackoverflow.com/a/5809080/166749 – Fred Foo Sep 01 '12 at 10:54
2
s = [50,62,15,76,57,97,82,99,45,23]
x = dict([(a, 'A++' if a>75 else 'A' if a>55 else 'F') for a in s])

print x

{97: 'A++', 45: 'F', 99: 'A++', 76: 'A++', 82: 'A++', 15: 'F', 50: 'F', 23: 'F', 57: 'A', 62: 'A'}

Use x.items() to do filter, for example

filter(lambda x: x[1] == 'A', x.items())

the result is

[(57, 'A'), (62, 'A')]
Jack
  • 10,943
  • 13
  • 50
  • 65
bill
  • 21
  • 1
  • 2 scopes on one line where the `x` name is something different. Not very different from other answer, so if you had the edit privilege, an edit might have been a better fit than an answer. – Chris Wesseling Sep 29 '12 at 10:19
1

You can write your own filter-like function:

def filter_n(n, f, lst):
    result = tuple([[] for i in range(n)])
    for elem in lst:
        result[f(elem)].append(elem)
    return result

The answer is now looking as following:

grades = filter_n(3, lambda x: (x < 40) * 0 +
                               (60 < x <= 75) * 1 +
                               (75 < x) * 2, s)
citxx
  • 2,525
  • 17
  • 40