views:

57

answers:

2

First, apologies,this should be simple but I've had too much coffee and cannot wrap my tired brain around this (at least not without making it way more complicated than I know it should be).

Lets say I have a simple Javascript array with a number of items in it:

var items = ["Hello", "This", "is", "an", "array", "with", 
             "a", "number", "of", "items", "in", "it"];

For whatever reason I'm suddenly interested in the 2nd value:

items[1]
//-> "This"

But I also want to get the previous value, and the next two values…

//-> "Hello", "This", "is", "an"

To put it this way:

function getBatch(items, start) {
  // What goes here so it would return the results below?
}

getBatch(items, 0);
//-> ["it", "Hello", "This", "is"]

getBatch(items, 4);
//-> ["an", "array", "with", "a"]

getBatch(items, (items.length-1));
//-> ["in" "it", "Hello", "This"]

What is the code for the function getBatch (above) in order to return those result-sets?

Please, no answers dependent on JQuery :)

+3  A: 

Well, obviously the naive first step would be to simply write

return items.slice(start - 1, start + 2)

However this isn't going to work with the wrapping that you require. One approach that should work is a helper function that effectively makes the array circular on both edges:

function getElementAtIndex(items, idx) {
    // Normalise the index to an element in the actual range
    while (idx > items.length - 1)
    {
        idx -= items.length;
    }
    while (idx < 0)
    {
        idx += items.length;
    }

    return items[idx];
}

Then you can simply manually return the four elements surrounding your index like so:

function getBatch(items, start) {
   return [ getElementAtIndex(items, start - 1),
            getElementAtIndex(items, start),
            getElementAtIndex(items, start + 1),
            getElementAtIndex(items, start + 2)];
}

This approach is shown working here.

This probably isn't the most efficient or elegant approach, but it's fairly straightforward to understand and implement, so it might end up being the most practical if this code isn't in a performance hotspot.

Andrzej Doyle
+1  A: 

Edited: (removed original version, as it was more crap than this)

function getBatch(items, start) {
  var tmpArr = items;
  tmpArr.splice(0,0,items);

  var offset = (start > items.length-3) ? 0 : items.length;

  return tmpArr.slice(start+offset-1,start+offset+3);
}

Edit 2.1 (bugfixed)

Edit 2.2 (move start to actual start and eliminate one wrap case (final)

Ok, crying boy cared for by his mother. Now, let's do this correct.

function getBatch(items, start) {
  // Behaviour not defined by example
  if(items.length < 4)
    return items;

  // Set start to actual start (start-1), and
  // ensure that start is always within 0 - items.length
  start = ((start-1)+items.length) % items.length;

  // First take care of the easy case.
  if(start < items.length-3) return items.slice(start,start+4);

  // Last x elements + (4-x) elements from beginning of array
  return items.slice(start).concat(items.slice(0,4-(items.length-start)));
}
Ivar Bonsaksen
Good try but this doesn't satisfy all cases. Providing a start value of 0 returns an empty array. A start value of (items.length-1) returns ["in", "it"]
michael
Should be better now...
Ivar Bonsaksen
Using your 2nd edit as a breakthrough, I can up with this working version (badly formatted): function getBatch(items, start) { var tmpArr = items; if(start == 0) { // Add last element to beginning of array (as defined by first example) tmpArr.splice(0,0,tmpArr.slice(-1).toString()); start = 1; } else if (start > items.length-3) { tmpArr = tmpArr.concat(tmpArr,tmpArr.slice(0,2)); } return tmpArr.slice(start-1,start+3);}
michael
Actually, your 3rd edit doesn't work (also missing closing bracket on Line 8)... will retest
michael
Ok, bugfixed and TESTED this time. Added paranthesis to start == 0 case, and changed start position in last case from start to start-1.
Ivar Bonsaksen
Reduced the number of wrap checks to one. I think this is my final answer :)
Ivar Bonsaksen