Hacker Newsnew | past | comments | ask | show | jobs | submitlogin

the a:b notation for JS is still in proposal phase https://github.com/tc39/proposal-slice-notation/pull/32, but I'll use it below to create ranges

I don't understand your `+0.5`, I've written below the transcription for your description

    [...1:30].map(a => 
      [...a+1:30].filter(b => gcd(a,b)==1).map(b => 
        [...b+1:30].filter(c => gcd(a,c)==1
          && gcd(b,c)==1 
          && Number.isInteger((a**3+b**3+c**3)**(1/3))
        .map(c => [a, b, c])
      )
    ).flat(2)
Or another equivalent way:

    [...1:30].flatMap(a => 
      [...a+1:30].filter(b => gcd(a,b)==1).flatMap(b => 
        [...b+1:30].filter(c => gcd(a,c)==1 
          && gcd(b,c)==1 
          && Number.isInteger((a**3+b**3+c**3)**(1/3)))
        .flatMap(c => [[a, b, c]])
Or another way (generating first all the triples):

    [...1:30].flatMap(a => [...a+1:30].flatMap(b => [...b+1:30].flatMap(c => [[a, b, c]])))
      .filter(([a, b, c]) => gcd(a,b)==1 && gcd(a,c)==1
                          && gcd(b,c)==1 && Number.isInteger((a**3+b**3+c**3)**(1/3)))
with https://github.com/tc39/proposal-iterator-helpers, which would allow lazy evaluation, and make more sense than above

    (1:30).flatMap(a => (a+1:30).flatMap(b => (b+1:30).flatMap(c => [[a, b, c]])))
      .filter(([a, b, c]) => gcd(a,b)==1 && gcd(a,c)==1
                          && gcd(b,c)==1 && Number.isInteger((a**3+b**3+c**3)**(1/3)))
without the slice-notation, it's really ugly (hence the proposal in the first link)

    Array.from({length: 30},(_,a)=>a+1)
      .flatMap(a=>Array.from({length: 30-a-1},(_,b)=>a+b+1)
        .flatMap(b => Array.from({length: 30-b-1},(_,c)=>b+c+1).flatMap(c => [[a, b, c]])))
    .filter(([a, b, c]) => gcd(a,b)==1 && gcd(a,c)==1
                          && gcd(b,c)==1 && Number.isInteger((a**3+b**3+c**3)**(1/3)))



Now that I think of it, even the flatMap version builds a lot of unnecessary arrays. The comprehension isn't just more readable, it's also more efficient. (Unless you're using a fancy compiler like GHC that does deforestation, in which case the flatMap/filter version should be as efficient as the list comprehension.)


Those 2 solutions below, that currently work in JS, are equivalent to the python solution in terms of complexity

But, yes I'm not satisfied in terms of readability, I linked to a proposal for iteration helpers, which would do this lazy-evaluation, I don't know if it can do it deeply like you say, interesting thing to see

    function gcd(a, b) {
      return b ? gcd(b, a % b) : Math.abs(a);
    }

    function isInteger(n) {
      return Math.abs(Math.floor(n + .5) - n) <= Number.EPSILON;
    }

    const range = (start, end) => Array.from({length: end-start}, (_,i) => start+i)

    console.log(
      range(1, 30)
      .flatMap(a => range(a+1, 30).filter(b => gcd(a,b)==1)
        .flatMap(b => range(b+1, 30).filter(c => gcd(a,c)==1 && gcd(b,c)==1
                  && isInteger((a**3+b**3+c**3)**(1/3)))
          .flatMap(c => [[a, b, c]])
        )
      )
    )

    function* tripleSortedRelPrimeCubes(start, end) {
      for (let a=start; a<end; a++) {
        for (let b=a+1; b<end; b++) {
          for (let c=b+1; c<end; c++) {
            if (
              gcd(a,b)==1
              && gcd(a,c)==1
              && gcd(b,c)==1
              && isInteger((a**3+b**3+c**3)**(1/3))
            )
              yield [a, b, c];
          }
        }
      }
    }

    console.log(
      [...tripleSortedRelPrimeCubes(1, 30)]
    )


I think this looks about as clean as I expected, I definitely like the look of the list comprehension better. (But of course, this is just a superficial syntactic matter: there is no essential difference.)

Does JavaScript not come with a .flatmap or similar method? I'm not sure I like having to count the nesting to pass the appropriate number to .flat. Also building up a nested list and then flattening is less efficient than the comprehension which builds the flattened version directly.

The +0.5 is to deal with floating point. Sadly the cube root isn't always exact enough to be an integer when it should, so I used floor(cube root + 0.5) to round to the near integer and then checked if that rounded integer really was the cube root.

Have you tried running this? Is Number.isInteger lenient enough to actually find the solution?




Consider applying for YC's Fall 2025 batch! Applications are open till Aug 4

Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: