cancel
Showing results for 
Search instead for 
Did you mean: 

Project Euler #6

SJT
Valued Contributor
Valued Contributor

6. Sum square difference

https://projecteuler.net/problem=6

The sum of the squares of the first ten natural numbers is 385. The square of the sum of the first ten natural numbers is 3025. Hence the difference between the sum of the squares of the first ten natural numbers and the square of the sum is 3025 − 385 = 2640 .

Find the difference between the sum of the squares of the first one hundred natural numbers and the square of the sum.

Solutions

This is close to trivial in q.

nnt:1+til@  / natural numbers to x
sqr:{x*x}
{(sqr sum x)-sum sqr x} nnt 100

Alternatives

We can explore some alternatives.

The square of the sums, the sum of the squares – two compositions?

(-).(sqr sum@;sum sqr@)@\:nnt 100

We can factor out the repetitions. The Zen monks will give us sqr and sum both reversed and not; 1 reverse\(sqr;sum), a 2×2 matrix.

q)1 reverse\(sqr;sum)
{x*x} sum
sum   {x*x}

Compose '[;] is binary (composes two functions) so can be applied by Apply Each Right ./: to each row of the matrix to produce the two compositions.

q)'[;]./:1 reverse\(sqr;sum)
{x*x}sum
sum{x*x}

It remains only to Apply At Each Left @\: the compositions to the vector and take the difference.

.[-] ('[;] ./: 1 reverse\(sqr;sum) ) @\: nnt 100

Composition rocks – and opens the way for cases where the functions (here sqr and sum) are determined at runtime.

Improving readability here… not so much.


Contributors

  • Stephen Taylor
  • Alex Unterrainer

From https://github.com/qbists/studyq/blob/main/euler/06.md

1 ACCEPTED SOLUTION

psaris
New Contributor II

though less well-known, i prefer to build compositions with :: instead of @.

@ adds an extra operator in the train of functions:

q)1+til@
+[1]@[k){$[0>@x;!x;'`type]}]
q)1+til::
+[1]k){$[0>@x;!x;'`type]}

your solution introduces many new concepts. but as you indicate, it reduces readability.

a shorter, faster and more readable solution would be:

ssd:{(x*x:sum x)-sum x*x:1+til x} / sum square difference

View solution in original post

5 REPLIES 5

LeahS
Moderator Moderator
Moderator

Great work! Thanks, Stephen and Alex. 👏

psaris
New Contributor II

though less well-known, i prefer to build compositions with :: instead of @.

@ adds an extra operator in the train of functions:

q)1+til@
+[1]@[k){$[0>@x;!x;'`type]}]
q)1+til::
+[1]k){$[0>@x;!x;'`type]}

your solution introduces many new concepts. but as you indicate, it reduces readability.

a shorter, faster and more readable solution would be:

ssd:{(x*x:sum x)-sum x*x:1+til x} / sum square difference

SJT
Valued Contributor
Valued Contributor

Two practices I try to avoid!

  • setting a variable twice (I know, the clue is in the name, but I find it better to treat them as immutable) – A man with two watches never knows what time it is.
  • destroying the function argument value

And yet – what an elegant outcome. Only goes to show, whether writing code or writing English:

I’ve found many useful rules, but none so useful that I haven’t also found an occasion when it seemed right to break it.
— “Three Principles of Coding Clarity

psaris
New Contributor II

great quote and great article!

by adding an explicit function argument and introducing two new variables, we avoid setting a variable twice and destroying the function argument -- in the process improving code clarity.

ssd:{[n](si*si:sum i)-sum i*i:1+til n} / sum square difference

SJT
Valued Contributor
Valued Contributor

Oooooh… I don’t know. Nothing wrong with implicit arguments to simple functions. And listing the natural number sequence could stand aside from the rest of it…

ssd:{(s*s:sum x)-sum x*x} 1+til::  / sum square difference

Glad you liked the article. Arthur seems to mention it whenever I (rarely) see him. Something about the concept of ‘code distance’ seems to have struck a chord.