views:

109

answers:

4

I am trying to sum all the numbers up to a range, with all the numbers up to the same range.

I am using python:

limit = 10
sums = []
for x in range(1,limit+1):
    for y in range(1,limit+1):
        sums.append(x+y)

This works just fine, however, because of the nested loops, if the limit is too big it will take a lot of time to compute the sums.

Is there any way of doing this without a nested loop?

(This is just a simplification of something that I need to do to solve a ProjectEuler problem. It involves obtaining the sum of all abundant numbers.)

+2  A: 
[x + y for x in xrange(limit + 1) for y in xrange(x + 1)]

This still performs just as many calculations but will do it about twice as fast as a for loop.

from itertools import combinations

(a + b for a, b in combinations(xrange(n + 1, 2)))

This avoids a lot of duplicate sums. I don't know if you want to keep track of those or not.

If you just want every sum with no representation of how you got it then xrange(2*n + 2) gives you what you want with no duplicates or looping at all.

In response to question:

 [x + y for x in set set1 for y in set2]
aaronasterling
this will work if they are consecutive numbers right? But let's say that I have a list of 1000 random numbers, and I want the sum of all those numbers with each other... Is there a way to avoid a nested loop?
alexBrand
i guess this is the right way to do it, but its still taking a long time to compute... is this still in the order O(n^2)?
alexBrand
Alex: given n random numbers there will in the worst case be O(n^2) different sums. To compute all the sums, you'll need either a nested loop or something that does just as much work as a nested loop. If the problem is speed, the answer won't be to compute those O(n^2) sums in a different way; the answer will be to find a solution that doesn't involve computing O(n^2) different sums.
Peter Milley
yeap... that's what I am starting to think... maybe I should rethink my solution... thanks!
alexBrand
A: 

If a for comprehension isn't to your liking you can take a look at itertools and use:

map( sum, product( range( limit + 1 ), repeat=2 ) )

Here is the description of product, taken right from the online doc:

Equivalent to nested for-loops in a generator expression. For example, product(A, B) returns the same as ((x,y) for x in A for y in B).

The nested loops cycle like an odometer with the rightmost element advancing on every iteration. This pattern creates a lexicographic ordering so that if the input’s iterables are sorted, the product tuples are emitted in sorted order.

To compute the product of an iterable with itself, specify the number of repetitions with the optional repeat keyword argument. For example, product(A, repeat=4) means the same as product(A, A, A, A).

So that the function returns a list of the sums of two entries from the combinatorial product of range( limit + 1 ). You could substitute whatever you'd like in place of range( limit + 1), even supplying your own list/tuple/set of entries.

wheaties
+1  A: 

I am trying to sum all the numbers up to a range, with all the numbers up to the same range.

So you want to compute limit**2 sums.

because of the nested loops, if the limit is too big it will take a lot of time to compute the sums.

Wrong: it's not "because of the nested loops" -- it's because you're computing a quadratic number of sums, and therefore doing a quadratic amount of work.

Is there any way of doing this without a nested loop?

You can mask the nesting, as in @aaron's answer, and you can halve the number of sums you compute due to the problem's simmetry (though that doesn't do the same thing as your code), but, to prepare a list with a quadratic number of items, there's absolutely no way to avoid doing a quadratic amount of work.

However, for your stated purpose

obtaining the sum of all abundant numbers.

you're need an infinite amount of work, since there's an infinity of abundant numbers;-).

I think you have in mind problem 23, which is actually very different: it asks for the sum of all numbers that cannot be expressed as the sum of two abundant numbers. How the summation you're asking about would help you move closer to that solution really escapes me.

Alex Martelli
Thanks for the info. The only way (I am pretty sure there's a better way :P) that comes to my mind is to generate all the possible sums of the abundant numbers less than 28124, and then iterate over the list of sums with a limit of 28124, appending all the numbers that don't appear in the list of sums to an answer list.
alexBrand
@alexBrand, what would the purpose of project Euler if the naive brute-force solutions were good enough?-) I don't want to spoil your enjoyment by just giving the solution, of course, so, just a hint: what if you just needed the sum of pairwise sums of all pairs of abundant numbers up to N? Wouldn't that be faster to compute? And how could knowing it help in your quest...?
Alex Martelli
@AlexMartelli hmmm! I will think about that! thank's a lot for your help
alexBrand
A: 

I'm not sure if there is a good way not using nested loops.

If I put on your shoes, I'll write as following:

[x+y for x in range(1,limit+1) for y in range(1,limit+1)]

Sjoo