简体   繁体   中英

How to write the following in list comprehension in python

Can I write the following in list comprehension way in python

for row in candidates:
    sum=0
    for i in range(1,len(candidates)):
        if(row[i]!='NA')
            sum+=int(row[i])
    row.append(sum)

Here candidates is the list of list of candidates where each inner list contains candidate marks. What I am trying to do is

"I am increasing a member in each inner list which will keep the total marks of each candidate" like candidate=[[143050023,5,7,6,8],[14305678,3,4,5,6]] (0 index in the inner has roll number of the candidate)

I want answer as

[[143050023,5,7,6,8,26],[14305678,3,4,5,6,18]]

I am able to do the same without using list comprehension but facing difficulty while trying with list comprehension The difficulty that I am facing in writing is how to sum the value and append it to the row after each inner loop.

When using a list comprehension is better as compared to the normal for loop structure?

Let's start with your final question:

When using a list comprehension is better as compared to the normal for loop structure?

Two things have to be true:

  • The purpose of your loop is to build a list.
  • It's more readable as a comprehension than as an explicit loop.

Notice that you have two nested loop. That might be transformable into a comprehension with two for clauses, or into a nested comprehension, but it's not going to transform into a single flat comprehension.

Your inner loop has a problem: a comprehension shouldn't try to mutate anything, and can't mutate anything with an assignment or other statement. So you need to find a way to rewrite it so that it does its work immutably.

In this case, the obvious answer is to create the values to be summed, and then pass the resulting iterable to a function that sums them, like the builtin sum function:

sum(int(row[i]) for i in range(1, len(row)) if row[i] != 'NA')

I used a generator expression instead of a list comprehension because we don't actually need the list for anything except to loop over it.

Notice that you can simplify this further. The only thing you're ever using i for is in the (repeated) expression row[i] . So why iterate over the range of indexes, when you can iterate over the row directly?

sum(int(value) for value in row if value != 'NA')

Your outer loop has a similar problem: you're trying to mutate each row inside the loop, not build up a new structure. And it's hard to come up with a good alternative that accomplishes the same thing by building a new structure instead.

Sure, you could always do things in two passes:

sums = [sum(int(row[i]) for i in range(1, len(candidates)) if row[i] != 'NA')
        for row in candidates]
candidates[:] = [row + [sum] for row, sum in zip(candidates, sums)]

And you can collapse those two passes into one by again changing sums into a generator expression instead of a list comprehension, and you could even turn it into a one-liner by doing it in-place instead of using a named temporary variable:

candidates[:] = [row + [total] for row, total in zip(candidates, (sum(
    int(row[i]) for i in range(1, len(candidates)) if row[i] != 'NA')
    for row in candidates))]

But it's hard to argue that's more readable, or even remotely close to as readable, as your original version.

Also, notice that I called the variable that holds each sum total , not sum . The sum function is a pretty important builtin in Python (and one we're actually using in this answer), so hiding it by creating a variable of the same name is a bad idea. Even in this case, where it's only alive within the scope of a list comprehension that doesn't use the builtin, so it's not ambiguous to the interpreter, it's still ambiguous and confusing to a human reader. (Thanks to Padraic Cunningham for pointing this out.)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM