Looping using the reduce operator

This page shows how to express JavaScript for loops using the Array operator reduce().

The examples used here came from a stackoverflow page, and involve converting binary numbers to and from byte arrays.

The JavaScript code to produce an array of bytes, given a long integer is reproduced here:

longToByteArray = function(/*long*/long) {
    // we want to represent the input as a 8-bytes array
    var byteArray = [0, 0, 0, 0, 0, 0, 0, 0];

    for ( var index = 0; index < byteArray.length; index ++ ) {
        var byte = long & 0xff;
        byteArray [ index ] = byte;
        long = (long - byte) / 256 ;
    }

    return byteArray;
};

The loop control will have us iterate 8 times, and each time through the loop we will append a byte-sized integer to an array and reduce the value in the incoming integer.

This could be written this way in KRL, using the Array operator reduce():

    toByteArray = function(str){
      1.range(8)
        .reduce(function(a,i){
          [a[0].append(a[1]%256),math:int(a[1]/256)]
        },[[]                   ,str.as("Number")  ])
        .head().reverse()
    }

The iteration is performed by the reduce function called in line 3 and controlled by the array upon which it operates ([1, 2, 3, 4, 5, 6, 7, 8]) which is produced in line 2 using the Number operator range(). The actual numbers one through eight (represented by the argument i of the function which reduce applies to the array) are not used in the computation.

The inner (anonymous) function produces an array of two items as specified by the code of line 4. The reduction begins with the array provided in line 5, which is an initial array of two items. The first item is an empty array and the second item is the value coming into the function, coerced to a Number. For each item in the controlling array, line 4 is executed and computes a new array, appends the low order byte of the number (in the second item) to the array (of the first item), with the second item being the number divided by 256. 

This process will end up computing a new array of two items, the first of which is the desired byte array (in little endian order) and the second of which will be zero (assuming an integer that "fits" into 64 bits). So, in line 6, the function takes the first of these using the Array operator head() and then changes the bytes to big endian order using the Array operator reverse().

We can insert some logging into the function, as shown here:

    toByteArray = function(str){
      1.range(8)
        .reduce(function(a,i){
            {}.put(i,a).klog("step");
            [a[0].append(a[1]%256),math:int(a[1]/256)]
          },[[]                   ,str.as("Number")  ]
        )
        .klog("raw reduction")
        .head().reverse()
        .klog("answer")
    }

and the logs will then show the steps in the reduction for an input value of 1551127401:

2019-02-25T20:43:21.017Z [KLOG] step {"1":[[],1551127401]}
2019-02-25T20:43:21.017Z [KLOG] step {"2":[[105],6059091]}
2019-02-25T20:43:21.017Z [KLOG] step {"3":[[105,83],23668]}
2019-02-25T20:43:21.018Z [KLOG] step {"4":[[105,83,116],92]}
2019-02-25T20:43:21.018Z [KLOG] step {"5":[[105,83,116,92],0]}
2019-02-25T20:43:21.018Z [KLOG] step {"6":[[105,83,116,92,0],0]}
2019-02-25T20:43:21.019Z [KLOG] step {"7":[[105,83,116,92,0,0],0]}
2019-02-25T20:43:21.019Z [KLOG] step {"8":[[105,83,116,92,0,0,0],0]}
2019-02-25T20:43:21.019Z [KLOG] raw reduction [[105,83,116,92,0,0,0,0],0]
2019-02-25T20:43:21.019Z [KLOG] answer [0,0,0,0,92,116,83,105]

Here it is easy to see that at each step of the reduction the byte array grows by one and the number is reduced by a factor of 256.

From the same stackoverflow page, here is the inverse of the toByteArray function, as written in JavaScript:

byteArrayToLong = function(/*byte[]*/byteArray) {
    var value = 0;
    for ( var i = byteArray.length - 1; i >= 0; i--) {
        value = (value * 256) + byteArray[i];
    }

    return value;
};

This can be written in KRL as a one-liner:

    fromByteArray = function(byteArray) {
      byteArray
        .reduce(function(a,dig){a*256+dig})
    }

Copyright Picolabs | Licensed under Creative Commons.