Tell me more ×
Code Review Stack Exchange is a question and answer site for peer programmer code reviews. It's 100% free, no registration required.

I'm a rank beginner in Python, and I am working my way through various relevant OpenCourseware modules. In response to the prompt

Write a procedure that takes a list of numbers, nums, and a limit, limit, and returns a list which is the shortest prefix of nums the sum of whose values is greater than limit. Use for. Try to avoid using explicit indexing into the list.

I wrote the following simple procedure

def numberlist(nums,limit):   
    sum=0  
    i=0  
    for i in nums:  
        sum=sum+i  
        if sum>limit:  
            return i  
        else:  
            print i

It gets the job done, but the division of labor between if and else seems inelegant, as does the use of both return and print. Is there a better way to structure this basic loop?

share|improve this question
I see now that this version was cobbling together a numberlist from the output of print and return, which would be problematic if I tried to pass the result into another function. Thanks to the commenters pointing this out! – K. Olivia Jun 22 '12 at 7:24

4 Answers

up vote 5 down vote accepted

So, a couple things:

  1. The problem statement says nothing about printing data, so you can omit the print statement, and thus the entire else: clause, entirely.

  2. The problem statement says to return a list, and you're just returning the last item in that list, not the entire list.

Here's a short but inefficient way to do it:

def numberlist(nums, limit):
    i = 0
    while sum(nums[:i]) < limit:
        i += 1
    return nums[:i]

or a more efficient but longer way:

def numberlist(nums, limit):
    prefix = []
    sum = 0
    for num in nums:
        sum += num
        prefix.append(num)
        if sum > limit:
            return prefix
share|improve this answer
I didn't realize that the question was asking for the subset. Have an upvote :) – rahul Jun 20 '12 at 2:48
This, like blufox’ solution, uses indexing which we’ve been told to avoid. – Konrad Rudolph Jun 20 '12 at 12:26
Konrad: the inefficient way does, the other way doesn't. – pjz Jun 20 '12 at 15:46
pjz: what makes the second method more efficient, in your estimation? – K. Olivia Jun 22 '12 at 7:27
K. Olivia: the first one runs a sum on the whole slice every time through the loop. The second only adds the newest number to the sum, which is much faster. – pjz Jun 22 '12 at 14:07

The others have discussed how you aren't quite doing what the problem asks, I'll just look at your code:

def numberlist(nums,limit): 

When the name of a function has two words it in, we recommend separate it with an _, in this case use number_list. Its easier to understand the name

    sum=0  

sum is the name of a built-in function, you should probably avoid using it

    i=0  

This does nothing. You don't need to pre-store something in i, just use the for loop

    for i in nums:  

I really recommend against single letter variable names, it makes code hard to read

        sum=sum+i  

I'd write this as sum += i

        if sum>limit:  

I'd put space around the >

            return i  
        else:  
            print i

Your instinct is right, using both return and print is odd. As the others have noted, you shouldn't be printing at all.

share|improve this answer
I generally agree about the one-letter variable names but there’s a broad consensus that they’re OK as simple loop variables (among others) – even though i is conventionally reserved for indices … – Konrad Rudolph Jun 20 '12 at 12:33
@KonradRudolph, I disagree with the consensus. But yes, there is one. – Winston Ewert Jun 20 '12 at 15:16

Try to avoid using explicit indexing into the list.

This part in the question was ignored in the other (good) answers. Just to fix this small shortcoming, you can write a generator which avoids indexing completely:

def numberlist(nums, limit):
    sum = 0
    for x in nums:
        sum += x
        yield x
        if sum > limit:
            return

This will return an iterator that, when iterated over, will consecutively yield the desired output:

>>> for x in numberlist([2, 4, 3, 5, 6, 2], 10):
...     print x,
... 
2 4 3 5

However, strictly speaking this violates another requirement, “returns a list” – so we need to wrap this code into another method:

def numberlist(nums, limit):
    def f(nums, limit):
        sum = 0
        for x in nums:
            sum += x
            yield x
            if sum > limit:
                return

    return list(f(nums, limit))
share|improve this answer
Thanks or introducing me to the generator method. I'll add it to my toolbox. – K. Olivia Jun 22 '12 at 7:16

Welcome to programming :) I did not understand your question first, then I realized that python might be your first language. In that case congratulations on picking a very nice language as your first language.

Your question seems to ask for the list which is the shortest prefix of nums the sum of which is greater than the limit. Here, you might notice that it does not care about the intermediate values. Alls that the function asks is that the return value be greater than the limit. That is, this should be the output

>>> numberlist([1,2,3,4,5], 5)
[1,2,3]

No output in between. So for that goal, you need to remove the print statement in your code, and without the print, there is no need for the else. In languages like python, it is not required that there be an else section to an if-else conditional. Hence you can omit it. We can also use enumerate to iterate on both index and the value at index. Using all these we have,

def numberlist(nums,limit):   
    sum=0  
    for index,i in enumerate(nums):  
        sum += i
        if sum>limit:  
            return nums[:index+1]

Note that if you are unsatisfied with omitting the else part, you can turn it back by using pass. i.e

    if sum>limit:  
        return nums[:index+1]
    else:
        pass

Note also that I used an array slice notation nums[:index+1] that means all the values from 0 to index+1 in the array nums This is a rather nice for loop. If you are feeling more adventurous, you might want to look at list comprehensions. That is another way to write these things without using loops.

edit: corrected for enumeration

share|improve this answer
sum=sum+i is more idiomatic as sum += i – pjz Jun 20 '12 at 3:43
@pjz true, thanks, updated :) – rahul Jun 20 '12 at 4:15

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.