Languages
[Edit]
EN

JavaScript - positive and negative around index wrapping / overlapping to address items in array

4 points
Created by:
Marcin
18790

In this article, we're going to have a look at how properly in JavaScript calculate index number when we try to address index by negative value or we exceed index to overlap range to normal index.

Quick solution:

// ONLINE-RUNNER:browser;

var array = ['first', 'middle', 'last'];

var index = -1;
var value = array[(index % array.length + array.length) % array.length];

console.log(value); // last

1. Double modulo example

This section present solution that is based on fact if we will use two times modulo we are able to escape negative calues too.

// ONLINE-RUNNER:browser;

function escapeIndex(index, count) {
	return (index % count + count) % count;
}

// Usage example:

var arraySize = 10;

console.log(  escapeIndex(  0, arraySize ) ); // 0
console.log(  escapeIndex(  1, arraySize ) ); // 1
console.log(  escapeIndex(  2, arraySize ) ); // 2
console.log(  escapeIndex(  9, arraySize ) ); // 9

console.log( escapeIndex(  10, arraySize ) ); // 0
console.log( escapeIndex(  11, arraySize ) ); // 1
console.log( escapeIndex(  19, arraySize ) ); // 9
console.log( escapeIndex(  20, arraySize ) ); // 0
console.log( escapeIndex(  21, arraySize ) ); // 1

console.log( escapeIndex(  -1, arraySize ) ); // 9
console.log( escapeIndex(  -9, arraySize ) ); // 1
console.log( escapeIndex( -10, arraySize ) ); // 0
console.log( escapeIndex( -11, arraySize ) ); // 9
console.log( escapeIndex( -19, arraySize ) ); // 1
console.log( escapeIndex( -20, arraySize ) ); // 0
console.log( escapeIndex( -21, arraySize ) ); // 9

/*
  ----------------[ Calculations map ]--------------------

  normal index       0   1   2   3   4   5   6   7   8   9

  index exceeded    10  11  12  13  14  15  16  17  18  19
                    20  21  22  23  24  25  26  27  28  29
                    ...

  index negative   -10  -9  -8  -7  -6  -5  -4  -3  -2  -1
                   -20 -19 -18 -17 -16 -15 -14 -13 -12 -11
                   -30 -29 -28 -27 -26 -25 -24 -23 -22 -21
                    ...

                     |   |   |   |   |   |   |   |   |   |  
                     |   |   |   |   |   |   |   |   |   |  
                     
  result:            0   1   2   3   4   5   6   7   8   9

*/

2. Modulo with 2 cases example

This section shows solution which uses if statement to split calculations for two cases: negative indesxes and positive.

Used cases are based on:

  1. modulo for positive indexes:
    itemIndex % arraySize,
  2. adding decreased with 1 maximal integer number in JavaScript and later use modulo for negative indexes:
    (itemIndex + 0x1FFFFFFFFFFFFE) % arraySize.

Maximum integer number in JavaScript:

ExponentalHexadecimalDecimal
2^53 - 10x1FFFFFFFFFFFFF9007199254740991

Runnabe examples are presented is below: 

// ONLINE-RUNNER:browser;

function escapeIndex(itemIndex, arraySize) {
    if (itemIndex < 0) {
        return (itemIndex + 0x1FFFFFFFFFFFFE) % arraySize;
    }
    return itemIndex % arraySize;
}

// Usage example:

var arraySize = 10;

console.log(  escapeIndex(  0, arraySize ) ); // 0
console.log(  escapeIndex(  1, arraySize ) ); // 1
console.log(  escapeIndex(  2, arraySize ) ); // 2
console.log(  escapeIndex(  9, arraySize ) ); // 9

console.log( escapeIndex(  10, arraySize ) ); // 0
console.log( escapeIndex(  11, arraySize ) ); // 1
console.log( escapeIndex(  19, arraySize ) ); // 9
console.log( escapeIndex(  20, arraySize ) ); // 0
console.log( escapeIndex(  21, arraySize ) ); // 1

console.log( escapeIndex(  -1, arraySize ) ); // 9
console.log( escapeIndex(  -9, arraySize ) ); // 1
console.log( escapeIndex( -10, arraySize ) ); // 0
console.log( escapeIndex( -11, arraySize ) ); // 9
console.log( escapeIndex( -19, arraySize ) ); // 1
console.log( escapeIndex( -20, arraySize ) ); // 0
console.log( escapeIndex( -21, arraySize ) ); // 9

3. Wrapped array class example

In this section simple class for array wraping is presented.

// ONLINE-RUNNER:browser;

function escapeIndex(index, count) {
  	if(index < 0) {
      	return (index + 0x1FFFFFFFFFFFFE) % count;
  	}
  	return index % count;
}

function WrappedArray(array) {
  	this.getValue = function(index) {
        var safeIndex = escapeIndex(index, array.length);
            return array[safeIndex];
        };
  	this.setValue = function(index, value) {
    	var safeIndex = escapeIndex(index, array.length);
      		array[safeIndex] = value;;
    	};
  	this.iterate = function(start, stop, callback) {
    	var safeStart = escapeIndex(start, array.length);
      	var safeStop = escapeIndex(stop, array.length);
      	if (safeStart < safeStop) {
        	for (var i = safeStart; i < safeStop; ++i) {
            	var result = callback(i, array[i]);
              if (result !== undefined) {
                array[i] = result;
              }
            }
        } else {
          	for (var i = safeStart; i < array.length; ++i) {
            	var result = callback(i, array[i]);
            	if (result !== undefined) {
              		array[i] = result;
            	}
          	}
          	for (var i = 0; i < safeStop; ++i) {
            	var result = callback(i, array[i]);
            	if (result !== undefined) {
              		array[i] = result;
            	}
          	}
        }
    };
}

// Usage example:

var array = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
var wrapper = new WrappedArray(array);

// Example 1
console.log( wrapper.getValue(  0 ) ); //  1
console.log( wrapper.getValue(  9 ) ); // 10
console.log( wrapper.getValue( -1 ) ); // 10
console.log( wrapper.getValue( 10 ) ); //  1

// Example 2
console.log( 'Iterating: <0, 9>' );
wrapper.iterate(0, 10, function(index, value) {
  // 1 2 3 4 5 6 7 8 9 10
console.log( index + ': ' + value );
});

// Example 3
console.log( 'Iterating: <-1, 1>' );
wrapper.iterate(-1, 2, function(index, value) {
    // 10 1 2
	console.log( index + ': ' + value );
});

// Example 4
console.log( 'Iterating: <7, 6>' );
wrapper.iterate(7, 7, function(index, value) {
  	// 8 9 10 1 2 3 4 5 6 7
	console.log( index + ': ' + value );
});

// Example 5
console.log( 'Iterating with zero setting: <-2, 1> = 8, 9, 0, 1' );
wrapper.iterate(-2, 2, function(index, value) {
  	// sets 10 9 1 2 to 0
  	return 0;
});
wrapper.iterate(0, 10, function(index, value) {
  // 0 0 3 4 5 6 7 8 0 0
  console.log( index + ': ' + value );
});

 

Native Advertising
🚀
Get your tech brand or product in front of software developers.
For more information Contact us
Dirask - we help you to
solve coding problems.
Ask question.

❤️💻 🙂

Join