Stack Overflow is a community of 4.7 million programmers, just like you, helping each other.

Join them; it only takes a minute:

Sign up
Join the Stack Overflow community to:
  1. Ask programming questions
  2. Answer and help your peers
  3. Get recognized for your expertise

I have a JavaScript array like:

var myArray = ['a', 'x', 'b', 'x', 'x', 'p', 'y', 'x', 'x', 'b', 'x', 'x'];

I want to fetch only those elements of the array that come after 2 consequent occurrences of a particular element.

i.e. in the above array, I want to fetch all the elements that come after consequent 'x', 'x'

So my output should be:

'p'
'b'

I have a solution like :

var arrLength = myArray.length;
for (var i = 0; i < arrLength; i++) {
    if(i+2 < arrLength && myArray[i] == 'x' && myArray[i+1] == 'x') {
        console.log(myArray[i+2]);
    }
};

This satisfies my needs, but it is not so generic.

For eg. if I have to check for 3 consequent occurrences, then again I have to add a condition inside if for myArray[i+2] == 'x' and so on.

Could anyone provide a better way to fetch the elements?

share|improve this question
2  
What if you have 4 'x'? If the 3rd fetched? Do the 3rd and the 4rt fetch the following item? – Oriol 5 hours ago
    
Are the array elements always single letters? This is essentially a string problem (with many good and efficient solutions), though none of them is natively implemented on Array – Bergi 1 hour ago

The functional way would be to use recursion. With an ES6 spread, you can pretty much emulate the terseness of a truly 'functional' language :-)

var myArray = ['a', 'x', 'b', 'x', 'x', 'p', 'y', 'x', 'x', 'b', 'x', 'x'];

function reducer(acc, xs) {
    if (xs.length > 2) {
        if (xs[0] === xs[1]) {
            // add the third element to accumulator
            // remove first three elements from xs
            return reducer([xs[2], ...acc], xs.slice(3));
        } else {
            // remove first element from xs and recurse
            return reducer(acc, xs.slice(1))
        }
    } else {
        return acc;
    }
}

console.log(reducer([], myArray));
share|improve this answer
    
for a linear problem, there is no need for a recursion, and it uses splice and it is to complicated for a simple counting task. – Nina Scholz 4 hours ago
    
ok, I prefer functional over imperative – Simon H 4 hours ago
    
that was not the question and recursion is not necessary functional. – Nina Scholz 4 hours ago
    
Recursion is a heavily recurrent mechanism in functional languages. And this code really does emulate functional programming very well -- no procedural/imperative code except for slice(), which can be reproduced in functional languages anyway. – Purag 57 mins ago

A generic straight forward approach for any comparable content. (No push, splice, recursion, double iteration, substring.)

It uses Array.prototype.filter() and a single variable for the index of the pattern array.

array                    i
-----------------------  -
a x b x x p y x x b x x
  x   x x     x x
-                        0
  ^                      1 first element found
    -                    0
      ^                  1 first element found
        ^                2 second element found
          !              0 take p
            -            0
              ^          1 first element found
                ^        2
                  !      0 take b
                    ^    1 first element found
                      ^  2 second element found

function getParts(array, pattern) {
    var i = 0;
    return array.filter(function (a) {
        if (i === pattern.length) {
            i = 0;
            return true;
        }
        if (a === pattern[i]) {
            i++;
        } else {
            i = 0;
        }
    });
}

function p(o) {
    document.write('<pre>' + JSON.stringify(o, 0, 4) + '</pre>');
}

p(getParts(['a', 'x', 'b', 'x', 'x', 'p', 'y', 'x', 'x', 'b', 'x', 'x'], ['x', 'x']));
p(getParts(['a', 'x', 'b', 'x', 'x', 'p', 'y', 'x', 'x', 'b', 'x', 'x'], ['a', 'x', 'b']));
p(getParts(['a', 'b', 'c', 'd', 'z', 'y', 'a', 'b', 'c', 'd', 'x', 'x'], ['a', 'b', 'c', 'd']));
p(getParts([41, 23, 3, 7, 8, 11, 56, 33, 7, 8, 11, 2, 5], [7, 8, 11]));

share|improve this answer

Here is a straightforward iterative solution. We maintain an array consecutive of consecutive elements. If that array gets to length 2, then the next element is printed and consecutive is reset.

var arr = ['a', 'x', 'b', 'x', 'x', 'p', 'y', 'x', 'x', 'b', 'x', 'x'];

var REPEATS_NEEDED = 2;

var consecutive = [arr[0]];
for (var i = 1; i < arr.length; i++) {
    if (consecutive.length === REPEATS_NEEDED) {
        console.log(arr[i]);
        consecutive = [arr[i]];
        continue;
    }

    // either add to or reset 'consecutive'
    if (arr[i] === consecutive[0]) {
        consecutive.push(arr[i]);
    } else {
        consecutive = [arr[i]];
    }
};
share|improve this answer

Try using for loop using variables referencing previous index, current index, next index of array

var myArray = ["a", "x", "b", "x", "x", "p", "y", "x", "x", "b", "x", "x"];

for (var res = [], curr = 0, prev = curr - 1, match = curr + 1
    ; curr < myArray.length - 1; curr++, prev++, match++) {
  if (myArray[curr] === myArray[prev]) res.push(myArray[match]);
};

console.log(res);
document.body.textContent = res;

share|improve this answer

You can try following logic

var myArray = ['a', 'x', 'b', 'x', 'x', 'p', 'y', 'x', 'x', 'b', 'x', 'x'];

function search(ch, times) {
  var splitStr = "";  
  for(var i = 0; i < times; i++) {
   splitStr += ch;
  } // Generate the split string xx in the above case.
  var str = myArray.join(''); // Join array items into a string
  var array = str.split(splitStr); // Split the string based on split string
  var result = {};
  // iterate on the array starting from index 1 as at index 0 will be string before split str
  for (var i = 1 ; i < array.length; i++) { 
     if(array[i] !== "") {
        result[array[i].substring(0,1)] = ''; // A map in order to avoid duplicate values
     }
  }
  
  return Object.keys(result); // return the keys
}

console.dir(search('x',2));

share|improve this answer

You can create an additional function isItGood like this:

var myArray = ['a', 'x', 'b', 'x', 'x', 'p', 'y', 'x', 'x', 'b', 'x', 'x'];
var arrLength = myArray.length;
for (var i = 0; i < arrLength; i++) {
    isItGood(myArray, i, 'x', 2);
};

function isItGood(arr, i, elem, total) {
    for ( var j = 0 ; j < total ; j++ ) {
        if ( i + total >= arr.length || arr[i+j] != elem ) {
            return;
        }
    }
    console.log(arr[i+total]);
    // just to see the result (no need to open a console)
    document.getElementById('p').innerHTML+=("<br/>"+arr[i+total]);
}
<p id="p">Result: </p>

share|improve this answer

If I had to write this in Scala instead of JavaScript I could just do it in one line. myArray.sliding(3).filter(l => l(0) == 'x' && l(1) == 'x').map(l => l(2))

So I guess I could do it the same way in JS if I implement the sliding function myself. e.g.

function sliding(array, n, step) {
  if(!step) step = 1;
  var r = [];
  for(var i = 0; i < array.length - n + 1; i += step) {
    r.push(array.slice(i, i + n));
  }
  return r;
}
var result = sliding(myArray, 3).filter(l => l[0] === "x" && l[1] === "x").map(l => l[2]);

The only downside here is that this runs slower than a more iterative approach. But that only matters for very big arrays.

share|improve this answer

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.