Skip to content

Instantly share code, notes, and snippets.

@kosamari
Last active May 24, 2017 13:33
Show Gist options
  • Star 3 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save kosamari/2ca1ea6e92758966a00b to your computer and use it in GitHub Desktop.
Save kosamari/2ca1ea6e92758966a00b to your computer and use it in GitHub Desktop.
/*
What is the optimal way to print values of 2 arrays alternately? (every 5 sec)
* Items in both arrays could change at any given moment
* update to each array needs to be applied imminently
* if array is empty, it will not print any value (and move to the other array)
So if you start with following arrays
var arr0 = ['1','2','3']
var arr1 = ['a','b','c']
It would start printing
-> 1 (5sec)
-> a (5sec)
-> 2 (5sec)
-> b (5sec)
But if arr1 updates to following after printing 'b'
var arr1 = ['a','b','e','z']
Then it would continue printing
. (a)
. (2)
. (b)
-> 3 (5sec)
-> e (5sec)
-> 1 (5sec)
-> z (5sec)
--------
Background :
I am making sideshow application that displays text message and images (alternating every 5 seconds)
Messages and Images to be displayed are updated from UI and saved as arrays in localStorage
(for actual application console.log(array[n]) part is replaced with DOM manipulation )
* I'm limited to use localStorage as data storege
--------
Following code is what I currently have, and doing what I want the program to do.
BUT here is what I am not feeling good about...
- I feel like its too much if statements.
- Checking localStorage every time print() is called seems not optimal.
- maybe create some flag when localStorage is updated?
- or is it not that big of a deal?
- Currently when an array is empty, it will do nothing for 5sec till print() is called again.
- having empty array is a rare case, but I would still like to move to the other array imminently
*/
var arr0 = ['1','2','3','4','5','6','7','8','9','10']; // default val for arr0
var arr1 = ['a','b','c']; // default val for arr1
var state = 0; //state 0 : arr0's turn to print state 1 : arr1's turn to print
var p0 = 0; // pointer for arr0
var p1 = 0; // pointer for arr1
// DATA UPDATE
// Get contents of localStorage and assign to arrays.
// If array is undefined, assign empty array.
function updateArrays(){
arr0 = JSON.parse(window.localStorage.arr0 || '[]');
arr1 = JSON.parse(window.localStorage.arr1 || '[]');
}
// PRINT
// called every 5sec by setInterval
function print(){
// update arr0 and arr1 to match with contents of localStorage
updateArrays();
// arr0's turn to print
if(state === 0){
state = 1;
// if array is empty, return.
if(arr0.length < 1){ return; }
// if pointer is at the end (thus return false), reset to 0
if(!arr0[p0]){ p0 = 0 }
// finally print value and increment pointer
console.log(arr0[p0])
p0++;
return;
}
// arr1's turn to print
state = 0;
if(arr1.length < 1){ return; }
if(!arr1[p1]){ p1 = 0}
console.log(arr1[p1])
p1++;
return;
}
window.setInterval(function(){ print(); }, 5000);
/*
functions for UI event
every time user hit 'update arr0' or 'update arr1' button,
function smiler to following are called to update content of localStorage
value is always [array]
*/
function updateArr0(){
window.localStorage.arr0 = JSON.stringify(document.getElementById('arr0').value)
}
function updateArr1(){
window.localStorage.arr1 = JSON.stringify(document.getElementById('arr1').value)
}
@aredridel
Copy link

Ooh! I think you can do better with the modulo operator!

Basically, you need to turn an iteration number into a position within the two arrays. The modulo operator "wraps" a number around to zero at a specified length -- making a number line into a number circle.

var x = [
    [1, 2, 3, 4, 5],
    ['a', 'b', 'c']
];

for (var n = 0; n < 1000; n++) {
    console.log('n', n, 'set', whichSet(n), 'item', whichItem(n), '=', x[whichSet(n)][whichItem(n)]);
}

function whichSet(n) {
    return n % x.length;
}

function whichItem(n) {
    return (n / x.length | 0) % x[whichSet(n)].length;
}

Since you can do the mapping afresh for each iteration, without depending on the content of the arrays being stable for each pass, this means that updating from localStorage on each iteration is okay -- a fresh array will continue from the position you wanted, and the iteration number just keeps going up. (the iteration number "is monotonic"). That separates the "updating arrays" concern from the "iterating arrays" concern.

localStorage can be a bit slow (not in the big scale of things, but compared to simple numeric operations, it is), so if the thing modifying it can just tell you what the new arrays are, that's a nice optimization, but not actually relevant to the iterating -- just an interface cleanup so that your structure goes from being iterator <-- localStorage <-- editor to editor --> (iterator, localStorage) -- more directly connecting.

@aredridel
Copy link

Small note: | 0 is a javascript trick for making a decimal to an integer: 2.5 becomes 2.

@behcet
Copy link

behcet commented Nov 4, 2014

var array1 = ['0wow', '1many', '2array'];
var array2 = ['such', 'hacks'];

var queue = [];
queue.push(array1, array2)

setInterval(function () {
  var thisArray = queue.shift();
  // since you want this to loop forever, shove it back in
  queue.push(thisArray)
  var thisElem = thisArray.shift();
  thisArray.push(thisElem)
  console.log.call(console, thisElem);
}, 500);

@Fishrock123
Copy link

/off-topic/

Small note: | 0 is a javascript trick for making a decimal to an integer: 2.5 becomes 2.

ooh I hadn't thought of that one.

I wonder if there is any reasonable difference between ~~, >>0, and | 0 that would make one better than the other?

@kosamari
Copy link
Author

kosamari commented Nov 5, 2014

Thank you !

So I changed array update to editor --> (iterator, localStorage) per @aredridel's suggestion.

For iterator, I ended up using modulo operator to select between sets, then using array.shift() and array.push() to loop through each element (like @behcet's suggestion).
@aredridel's suggestion provided perfectly continuous iteration (and that's what I was aiming first), but realized when you update the set from UI, users think the old set is flashed out and expect the app to "start over from the 1st element of new set", so shift and push worked better for this case.

also I saw | 0 and ~~ and >>0 for the first time. awesome !

var arr = [
    [1, 2, 3, 4, 5],
    ['a', 'b', 'c']
];
var count = 0;

function whichSet(n) {
  return n % arr.length;
}

function print(){
  //select set 
  var thisArray = arr[whichSet(count)];

  //get 1st element and push to back of array
  var thisElem = thisArray.shift();
  thisArray.push(thisElem);

  //print & count up
  console.log(thisElem);
  count++;
}
window.setInterval(function(){ print(); }, 5000);

@aredridel
Copy link

Awesome! Nice to see it come together so tidy!

@aredridel
Copy link

@Fishrock123 ~~ is two operations; and | 0 is what asm.js adopted as a 'type hint' that something is a 32-bit int and not a double float.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment