2

I am trying to use array.reduce on an array representing a single binary value. For instance [1,0,1] in binary would convert to 5 in decimal.

I have been able to succesfully convert between binary and decimal using a while loop, but would like to upgrade my code to use the reduce method.

What I have implemented so far is accurate up to 6 elements in the array. I am not sure why, but after 6 digts, the conversion fails.

In addition, I am using a formula to make the conversion. For example: to convert 111001 to decimal, you would have to do (1*2^5) + (1*2^4) (1*2^3) + (0*2^2) + (0*2^1) + (1*2^0).

const getDecimalValue = function (head) {

     let total = head.reduce(
         (sum) =>
         sum + (head.shift() * Math.pow(2, head.length))
     )
     return total
}

console.log(getDecimalValue([1, 0, 1]) == 5)
console.log(getDecimalValue([1, 1, 1, 0, 0, 1]) == 57)
console.log(getDecimalValue([1, 1, 1, 0, 0, 1, 1]) == 115)
console.log(getDecimalValue([0, 1, 1, 1, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0]) == 7392)
console.log(getDecimalValue([1, 0, 0, 1, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0]) == 18880)

This was my code using the while loop

    let sum = 0
    while ((i = head.shift()) !== undefined) {
        sum += (i * Math.pow(2, head.length))
        console.log(i * Math.pow(2, head.length))
    }
    return sum
2
  • You are mutating the array as you're iterating over it. Just...don't do that, since you're making the whole operation work wrong after you shift out the indeces. Commented Jan 10, 2020 at 20:36
  • 1
    I wish all questions asked here were so clear in scope and came with their own tests. +1 for that! Commented Jan 10, 2020 at 20:40

3 Answers 3

4

You could reduce the array and multiply last value and add the actual value.

const getDecimalValue = array => array.reduce((r, v) => r * 2 + v, 0);

console.log(getDecimalValue([1, 0, 1]) == 5)
console.log(getDecimalValue([1, 1, 1, 0, 0, 1]) == 57)
console.log(getDecimalValue([1, 1, 1, 0, 0, 1, 1]) == 115)
console.log(getDecimalValue([0, 1, 1, 1, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0]) == 7392)
console.log(getDecimalValue([1, 0, 0, 1, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0]) == 18880)

Sign up to request clarification or add additional context in comments.

Comments

1

The problem is that you are mutating the array as reduce is iterating over it. This changes the array underneath, so the operation gets out of sync with the underlying values. Here is a (somewhat loose) illustration of how reduce normally walks the array:

arr =       [1, 2, 3]
             ^  ^  ^
             |  |  |
iteration 1 --  |  |
iteration 2 -----  |
iteration 3 --------        

Here is what happens when you modify it each iteration:

//start
arr =       [1, 2, 3]

//at iteration 1
            [2, 3] _
             ^
             |
iteration 1 --

//at iteration 2
            [3] _ _
                ^
                |
iteration 2 -----

//at iteration 3
            [] _ _
                 ^
                 |
iteration 3 ------        

Instead, the straight forward way to get your functionality is to make each item a power of 2 that is equal to the reverse index of the item

//index:            0   1   2   3
arr =              [1,  0,  1,  0]
//reverse index:    3   2   1   0

And conveniently, to get that, you simply need to subtract 1 from the array length (because indeces are 0-based and length = 1 only has index = 0) and then subtract the normal index. This gives you the powers of two each value represents:

//reverse index:    3   2   1   0
arr =              [1,  0,  1,  0]
//power of 2:       8   4   2   1
//multiply and sum: 8 + 0 + 2 + 0 = 10

And here is the code using reduce:

const getDecimalValue = function (head) {

     let total = head.reduce(
         (sum, item, index, array) =>
        sum + item * Math.pow(2, (array.length - index - 1)),
// reverse index                  ^^^^^^^^^^^^^^^^^^^^^^^^
        0
     )
     
     return total
}

console.log(getDecimalValue([1, 0, 1]) == 5)
console.log(getDecimalValue([1, 1, 1, 0, 0, 1]) == 57)
console.log(getDecimalValue([1, 1, 1, 0, 0, 1, 1]) == 115)
console.log(getDecimalValue([0, 1, 1, 1, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0]) == 7392)
console.log(getDecimalValue([1, 0, 0, 1, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0]) == 18880)

1 Comment

Thanks, I was very close to what you suggested in my original attempts. I appreciate the clear and succinct explanation
0

I find it way more readable using the following function with Array.prototype.reduceRight().

function binaryToDecimal(arr) {
  let decimal = 0;
  arr.reduceRight((base, binaryNum) => {
    if (binaryNum === 1) {
      decimal += base;
    }
    base = base * 2;
    return base;
  }, 1);
  return decimal;
}

binaryToDecimal([1, 1, 0, 1, 1, 0, 0, 0, 0, 1, 1, 0])===3462

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.