Hacker Read top | best | new | newcomments | leaders | about | bookmarklet login

I get that the point is Copilot and not the code but

    sum([arr[i] > arr[i - 3] for i in range(3, len(arr))])
will solve part 2. Similarly for the first part, subtract 1 and start the range at 1.

You don't need functions (but that's kind of an opinion, so whatever).

More importantly, to check if a rolling sum is increasing you don't need to compute that sum. I wonder if Copilot can ever figure that out.



sort by: page size:

It's much simpler, if there's an increasing run of length k, it contains k(k+1)/2 subruns. So you can just do one pass over the array, keeping track of the length of the current run.

    function f(arr) {
      var j=0, ret=0;
      for (var i=1; i<=arr.length; i++) {
        if (i==arr.length || arr[i]<=arr[i-1]) {
          ret += (i-j)*(i-j+1)/2;
          j = i;
        }
      }
      return ret;
    }

I don't get it. Why not just test for net sum of the directions for a finite number of iterations? If the net sum is zero, there is a loop and if not, the program halts. Am I missing something?

He's adding i, not 1, to j on every inner loop. Basically he's incrementing any array element that is a multiple of 2, then of 3, etc.

That code is exactly equivalent to:

int sum = 0; for (Integer x: Arrays.asList(1, 2, 3, 4, 5, 6, 7)) { int x2 = x * x; if (x2 % 2 == 0) sum += x2; }

No threads, no weirdness. It's just a different syntax for a loop, really.


I got that, but I don't understand why it should gain the value 3 before a single execution of the loop.

Unrelated to your question, but your code doesn't traverse array. All it does is:

      for i := 0; i < len(ints); i++ {
        sum += i
      }

One can also break out of the LOOP and return the so far accumulated value:

  CL-USER> (loop for i from 1 below 10
                 sum i
                 when (= i 6)
                   do (loop-finish))
  21

> If the array index range is [-1, 4[, but the client sums over [1, 4[, then this is wrong.

So you cannot loop over a subset of the indices? That seems restrictive.


But that can't be tail call optimized, so you should write something like

    sum(n, acc=0) = n == 0 ? acc : sum(n-1, acc+1)
To me that negates much of the 'declarative' character of a functional style. I don't feel it's really clearer than the imperative for-loop

    acc = 0
    for i = 1 to n
        acc += 1

if order does not matter:

var sum=0,i=list.length; while(i--) sum += list[i].amount;

if it does: var sum=0,i=0,ln=list.length; while (ln-- && (sum += list[i++].amount));

but the for in syntax is nicer indeed.


>"or unroll the (fixed iteration) shift-and-add loop"

Can you elaborate on this? I understand the shifting but didn't understand the "loop unrolling fixed iteration part"


Ok, so because i never reaches 4, it assumes the loop doesn't exit due to the 'for' condtion, so it must return true.

That makes sense, but still feels like a broken way to do optimizations.


There is a nugget buried at the bottom of this: you will get different output for different kinds of for ... range or for i ... loops. You'd think these are equivalent:

        for i = range arr {
                sum += arr[i]
        }
        for _, c = range arr {
                sum += c
        }
... but the latter is 4 bytes shorter in x86. The compiler takes things literally.

OK, here's a C version. Had to add a parameter, of course:

  void add1(int arr[], int length, int val, int n)
  {
    int direction  = n >= 0;
    int counter    = n == 0 ? length : abs(n);
    int index;
    
    for(int i = 0; (i < length) && (counter != 0) ; i++)
    {
      index = direction ? i : length - i;
      if(arr[index] == val)
      {
        arr[index]++;
        counter--;
      }
    }
  }
Verified with test vectors.

Ew, how inefficient. Here is the Smalltalk code:

    detectSum: aBlock
        "Evaluate aBlock with each of the receiver's elements as the argument. 
        Return the sum of the answers."
        | sum |
        sum := 0.
        self do: [:each | 
            sum := (aBlock value: each) + sum].  
        ^ sum
Anyway, my point still stands. Better to accept a block than to use a sum method that assumes the Array consists of numbers

Here's my cheating version that uses a third-party library:

    add1_cheating = (arr, val, n) ->
      n = arr.length if n is 0
      start = if n < 0 then arr.length else 0
      end = if n < 0 then 0 else arr.length
      step = n/(Math.abs n)
      n = Math.abs n
      count = 0
      for i in _.range start, end, step
        break if count > n
        arr[i]++ if arr[i] is val
        count++
      return arr

You're welcome. In the second edition, which is what I happen to have, it's column 9 (because the old column 4 got split into two) and the code is in a pseudocode that's much more like C with the semicolons deleted than like any version of BASIC.

I wasn't quite right to say that the inner loop is very tight; rather, the code assumes a particular size of array and unrolls the loop completely. But, indeed, the size doesn't need to be a power of 2.

Here's the (pseudo)code, in case anyone cares. It's for an array of size 1000. I've changed a variable name from "l" to "m" because of the usual l1I| thing. I've removed a couple of helpful comments because anyone who cares enough to bother reading them will probably have more fun figuring everything out on their own. I've also elided some obvious repetitive code and formatted it slightly differently from Bentley. Any errors in the code were probably introduced by me.

  m = -1
  if (x[  511] < t) m = 1000-512
  if (x[m+256] < t) m += 256
  if (x[m+128] < t) m += 128
  /* ... */
  if (x[m+  2] < t) m +=   2
  if (x[m+  1] < t) m +=   1
  p = m+1
  if (p>1000 || x[p]!=t) p = -1 /* i.e., not found */
Bentley says this is "not for the faint of heart". I agree, but I do think it's lovely. Though personally I'd be inclined to use a value of m offset by 1 from what Bentley does (initialize to 0, look up m+255, m+127, etc.) and save a line of code and a couple of cycles.

  sum = 0
  for i in range(0, 10000000):
    sum += 0.1
  print(round(sum*1000, 2))
what should this code print? what does it print?

I mean, sure, this is a contrived example. But can you guarantee that your code doesn't do anything similarly bad? Maybe the chance is tiny, but still: wouldn't you like to know for sure?


What I can't understand is what would J do if I tell it to sum these two arrays:

    1 2 3 4 5
    6 7 8 
I.e. 5 elements and 3 elements
next

Legal | privacy