30

It seems so simple, but I cannot find out how to convert an Array filled with integers to an ArrayBuffer and back again to an Array. There are lots of examples where strings are converted to an ArrayBuffer like for example here.
Using these examples I created this:

/**
 * Convert string to array buffer.
 *
 * @param {Array.<int>} array
 * @returns {ArrayBuffer}
 */
self.arrayToArrayBuffer = function( array ) {
    var length = array.length;
    var buffer = new ArrayBuffer( length * 2 );
    var view = new Uint16Array(buffer);
    for ( var i = 0; i < length; i++) {
        view[i] = array[i];
    }
    return buffer;
}

Then the array also needs to converted back again. For this I use:

var array = new Uint16Array(arrayBuffer);

This solution seems to work, but is there no easier way to do this?

UPDATE

It should also work for an array like:

var array = [3,7426,78921]
Wilt
  • 41,477
  • 12
  • 152
  • 203

2 Answers2

58

Yes, there's a simple way without manually writing a loop (the loop still exists somewhere in background):

new Uint16Array([1,2,3]);

That's all. Of course, floating numbers will be rounded down and big numbers will overflow.

Converting typed array to buffer

The buffer of any typed array is accessible through .buffer property, as anyone can read on MDN:

new Uint16Array([1,2,3]).buffer;

Chosing the right typed array

Be warned that mentioned Uint16Array will only hold integers (no floating point) between zero and 65535. To hold any javascript Number1 you will want to use Float64Array - the bigest one, taking 8 bytes total.

1: Which is unrestricted double, which appears to be 64bit IEEE 754 number

Here's a map I have created that maps some of the important information related to number data types:

var NUMBER_TYPE = [
  {name: "uint8",   bytes:1, max:        255,       min: 0,                floating: false, array: Uint8Array},
  {name: "int8",    bytes:1, max:        127,       min: -128,             floating: false, array: Int8Array},
  {name: "uint16",  bytes:2, max:      65535,       min: 0,                floating: false, array: Uint16Array},
  {name: "int16",   bytes:2, max:      32767,       min: -32768,           floating: false, array: Int16Array},
  {name: "uint32",  bytes:4, max: 4294967295,       min: 0,                floating: false, array: Uint32Array},
  {name: "int32",   bytes:4, max: 2147483647,       min: -2147483648,      floating: false, array: Int32Array},
  {name: "float64", bytes:8, max: Number.MAX_VALUE, min: Number.MIN_VALUE, floating: true , array: Float64Array}
];

Float 32 is missing as I was unable to calculate necessary information for it. The map, as it is, can be used to calculate the smallest typed array you can fit a Number in:

function findNumberType(num) {
    // detect whether number has something after the floating point
    var float = num!==(num|0);
    // Prepare the return variable
    var type = null;
    for(var i=0,l=NUMBER_TYPE.length; i<l; i++) {
      // Assume this type by default - unless break is hit, every type ends as `float64`
      type = NUMBER_TYPE[i];
      // Comparison asserts that number is in bounds and disalows floats to be stored 
      // as integers
      if( (!float || type.floating) && num<=type.max && num>=type.min) {
          // If this breaks, the smallest data type has been chosen
          break;
      }
    }
    return type;
}

Used as:

var n = 1222;
var buffer = new (findNumberType(n).array)([n]);

Note that this only works if NUMBER_TYPE is properly ordered.

Community
  • 1
  • 1
Tomáš Zato
  • 50,171
  • 52
  • 268
  • 778
  • 3
    Any typed array has `.buffer` property – Tomáš Zato Dec 04 '15 at 14:21
  • Okay, I accepted your answer already, but while testing I found out it doesn't work for bigger integers... How to do that then? – Wilt Dec 04 '15 at 14:39
  • `Float64Array` in particular will contain any javascript number without errors. I actually already wanted to share an algorithm I created which calculates which type of array is necessary to contain any int (so that you can use the smallest necessary). But your rude attitude changed my mind. – Tomáš Zato Dec 04 '15 at 14:45
  • I tested the answer, and it seemed to work fine. But then I discovered it didn't work for larger integers. Since other people will not pay attention to a answered question I unaccepted it hoping I would get more solutions that could help me out. Rather think once more about your own hostile comments like *"you will soon find yourself mistaken"* or *"But your rude attitude changed my mind"*. I hope peace is with you my friend... Thank you for all your efforts. It is greatly appreciated. – Wilt Dec 04 '15 at 15:03
  • `Float64Array` worked fine. I will study the documentation for sure. I want to get my head around it, but for now I am just happy with a working solution. Thanks again... – Wilt Dec 04 '15 at 15:12
  • 1
    A added the information I was talking about, along with warning for other users. I apologize - my temper along with past bad experience has taken the better of me. – Tomáš Zato Dec 04 '15 at 15:44
  • 1
    Nice hat @TomášZato, I still get upvotes on this question for example again yesterday and seems your answer is also scoring well. Great holidays to you! – Wilt Dec 22 '18 at 09:15
4

You can't use an ArrayBuffer directly, but you can create a typed array from a normal array by using the from method:

let typedArray = Int32Array.from([-2, -1, 0, 1, 2])
Martin Wantke
  • 4,287
  • 33
  • 21