12

I have an array in JavaScript that have defined these values:

var myStringArray = ["1","2","3","4","5","6","7","8","9","10"];

And when I call a function the first time function, I need to get this:

1
2
3

Calling it again I need to get:

4
5
6

Calling it again:

7
8
9

Calling it again:

10
1
2

Calling again:

3
4
5

And so on. You got the point, showing 3 values from the array and if we are at the end of array, read from the beginning... I have an app that has remote control and has down and up keys. When the user presses the down button to get these values from an array as described in the above example, if the user presses the up button it needs to go back from an example...so reading the array in a loop (at end, the array is read from the beginning, but always shows three values).

I try using this:

var myStringArray = ["1","2","3","4","5","6","7","8","9","10"];
var arrayLength = myStringArray.length;
for (var i = 0; i < arrayLength; i++) {
    if (i<(6)) {
       console.log(myStringArray[i]);
    }
}

But the next time I call this code, it shows from the beginning values of the array, not continue to read others value...do I need a second counter?

3
  • Show what you have tried until now. StackOverflow is not the place where we give you direct and complete answers to your school projects. Hint: use a closure to save state inside your function. Commented May 22, 2018 at 13:40
  • Thanks i know this is not the place to write me code..but i really don't have idea how to archive reading in loop...so only can do it with lots if i<6 and second counter and that is not efficetly way...thanks for comenting out... Commented May 22, 2018 at 13:45
  • A closure is a function inside a function. It allows you to freeze the value of variables between calls. You can then freeze the value of your i and build the logic from here. It's just a matter of looping 3 times in a circular way. Commented May 22, 2018 at 13:47

8 Answers 8

9

If you are OK with manipulating your original array as you loop through it you could splice and concat similar to below (or you could use a clone of the array if you need to persist the original array):

var myStringArray = ["1","2","3","4","5","6","7","8","9","10"];

var loopByX = function(x){
  var y = myStringArray.splice(0,x);
  myStringArray = myStringArray.concat(y);
  
  return y;
}

console.log(loopByX(3));
console.log(loopByX(3));
console.log(loopByX(3));
console.log(loopByX(3));
console.log(loopByX(3));

If you want to go bi-directional (is that what you call it?), as mentioned in the comments, you could do it as below which then gives you the ability to go backwards or forward and the flexibility to do so in an arbitrary number:

var myStringArray = ["1", "2", "3", "4", "5", "6", "7", "8", "9", "10"];

var loopByX = function(x) {
  var len = myStringArray.length;

  // Ensure x is always valid but you can add any behaviour here in that case yourself. As an example I return an empty array.
  if (Math.abs(x) > len) {
    return [];
  }

  var y = x > 0 ? myStringArray.splice(0, x) : myStringArray.splice(len + x, len);

  myStringArray = x > 0 ? myStringArray.concat(y) : y.concat(myStringArray);

  return y;
}

console.log(loopByX(20)); // invalid number
console.log(loopByX(-20)); // invalid number
console.log(loopByX(-3));
console.log(loopByX(-6));
console.log(loopByX(3));
console.log(loopByX(4));

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

6 Comments

If you do myStringArray = x > 0 ? myStringArray.concat(y) : y.concat(myStringArray) it will also work backwards
That's an interesting solution.
Very interesting code...could you please give example #2 using x > 0 ? as you posted comment? I try in jsfiddle but i got always error Uncaught ReferenceError: x is not defined
I added the reversal example and some basic validation using Math.abs(x) but you can tweak that to your needs.
I like this function very much...it is working as expected...and very efficient way...now i im trying to return for each number <div></div> because my app using jQuery inserts it i try using this code: $(".mm_vert_container").append("<div>"+(temp.concat(temp.length < 6 ? tv.slice(0, ch) : []).join(' '))+"</div>"); but i need to play it a little
|
4

You could take a function which slices three elements and if not possible, it takes the needed first values of the array as well.

function take3() {
    var temp = array.slice(index, index += 3)
    index %= array.length;
    console.log(temp.concat(temp.length < 3 ? array.slice(0, index) : []).join(' '));
}

var array = ["1", "2", "3", "4", "5", "6", "7", "8", "9", "10"],
    index = 0;
<button onclick="take3()">take 3</button>

With a mapping of a dynamic count.

function take(length) {
    console.log(Array.from({ length }, _ => array[++index, index %= array.length]));
}

var array = ["1", "2", "3", "4", "5", "6", "7", "8", "9", "10"],
    index = -1;
<button onclick="take(3)">take 3</button>

1 Comment

I like this answer as well.
2

Your variable i is local to the for loop which means it basically resets every time the loop is started. So first make your variable i global.

var i=0;
function employeeNames(){
    var empList =  ["1","2","3","4","5","6","7","8","9","10"];
    var output = [];
    var j=0;
    while(j<3)
    {
        output.push(empList[i])
        i=(i+1)%empList.length;
        j++;
    }
    return output;
}

console.log(employeeNames());
console.log(employeeNames());
console.log(employeeNames());
console.log(employeeNames());
console.log(employeeNames());

Comments

1

If you want the immutable way to achieve your circular looping

function loopArray(arr, step=3) {
    let i = 0;
    return function inner() {
        for (let j = 0; j < step; j++) {
            console.log(arr[i]);
            i = (i + 1) % arr.length;
        }
    };
 }

const func = loopArray(["1","2","3","4","5","6","7","8","9","10"], 3);
func();
func();
func();
func();
func();

Comments

1

The fancy solution with generator functions:

function* cycle(arr) {
    let i=0;
    while (true) {
        yield arr[i++];
        i %= arr.length;
    }
}
function* chunksOf(n, iterable) {
    let chunk = [];
    for (const x of iterable) {
        chunk.push(x)
        if (chunk.length >= n) {
            yield chunk;
            chunk = [];
        }
    }
    if (chunk.length > 0)
        yield chunk;
}
function toFunction(iterator) {
    return () => iterator.next().value;
}
var myStringArray = ["1","2","3","4","5","6","7","8","9","10"];

const f = toFunction(chunksOf(3, cycle(myStringArray)));
console.log(f());
console.log(f());
console.log(f());
// …

Comments

1

@Igor Petev, JavaScript's closures are a nice concept that you can use to solve your problem.

Please read JavaScript's Closures - w3schools article. It's really nice and excellent.

I have used the concept of closures to solve this problem. Please leave a comment if you don't understand my code or anything else related to this problem.

Please have a look at the below code.

var get3items = (function () {

    var index = 0;
    var myStringArray = ["1", "2", "3", "4", "5", "6", "7", "8", "9", "10"];
    var len = myStringArray.length

    return function () {
       for(var count = 0; count < 3; count += 1)
       {
           console.log(myStringArray[index]);

           if(index == (len - 1))
           {
               index = 0;
           }
           else {
               index += 1;
           }
       }
    }
})();

get3items (); // First call

console.log()
get3items (); // Second call

console.log()
get3items (); // Third call

console.log()
get3items (); // Fourth call

console.log()
get3items (); // Fifth call

/*
 1
 2
 3

 4
 5
 6

 7
 8
 9

 10
 1
 2

 3
 4
 5
*/

2 Comments

thanks another very nice solution...thanks for posting i will study example and keep in mind when i need it in feauture project
No problem, enjoy JavaScript. Nice question, first time I used JavaScript's closure to answer any question on stackoverflow and it is accepted. Thanks.
0

How about using a generator:

function* get3() {
  var myStringArray = ["1","2","3","4","5","6","7","8","9","10"];
  var index = 0;
  while (true) {
    yield [0, 1, 2].map(i => myStringArray[(index + i) % myStringArray.length])
    index = (index + 3) % myStringArray.length;
  }
}

Calling this function returns an object which you can call .next() on, to get the next set of 3:

var getter = get3();
console.log(getter.next().value); // ["1","2","3"]
console.log(getter.next().value); // ["4","5","6"]
console.log(getter.next().value); // ["7","8","9"]
// etc.

Comments

-2
function* employeeNames(){
    var empList =  ["1","2","3","4","5","6","7","8","9","10"];

    for(var i =0; i<=empList.length; i++){
        yield empList[i];
    }
}

var emp;
emp = employeeNames();

It uses a generator function...

3 Comments

Using a generator function is a neat solution, but this code doesn't solve the question
This code does not give what i need in example posted above..but thanks for answering..
@Igor, you can use the JavaScript's closures (one of the excellent concept in JavaScript) to solve this problem. I have added its use in my answer below.

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.