Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Find if two arrays are repeated in array and then select them

I have multiple arrays in a main/parent array like this:

var array = [[1, 17], [1, 17], [1, 17], [2, 12], [5, 9], [2, 12], [6, 2], [2, 12]];

here are the array's for simpler reading:

[1, 17]
[1, 17]
[1, 17]
[2, 12]
[5, 9]
[2, 12]
[6, 2]
[2, 12]
[2, 12]

I want to select the arrays that are repeated 3 or more times (> 3) and assign it to a variable. So in this example, var repeatedArrays would be [1, 17] and [2, 12].

So this should be the final result:

console.log(repeatedArrays);
>>> [[1, 17], [2, 12]]

I found something similar here but it uses underscore.js and lodash.

How could I it with javascript or even jquery (if need be)?

like image 626
Timmy Balk Avatar asked Nov 23 '18 20:11

Timmy Balk


People also ask

How do you check if two arrays are the same value?

The Arrays. equals() method checks the equality of the two arrays in terms of size, data, and order of elements. This method will accept the two arrays which need to be compared, and it returns the boolean result true if both the arrays are equal and false if the arrays are not equal.

How do I check if an array contains duplicates?

To check if an array contains duplicates:Use the Array. some() method to iterate over the array. Check if the index of the first occurrence of the current value is NOT equal to the index of its last occurrence. If the condition is met, then the array contains duplicates.


4 Answers

Try this

array.filter(( r={}, a=>!(2-(r[a]=++r[a]|0)) ))

var array = [[1, 17], [1, 17], [1, 17], [2, 12], [5, 9], [2, 12], [6, 2], [2, 12]];

var r= array.filter(( r={}, a=>!(2-(r[a]=++r[a]|0)) ))

console.log(JSON.stringify(r));

Time complexity O(n) (one array pass by filter function). Inspired by Nitish answer.

Explanation

The (r={}, a=>...) will return last expression after comma (which is a=>...) (e.g. (5,6)==6). In r={} we set once temporary object where we will store unique keys. In filter function a=>... in a we have current array element . In r[a] JS implicity cast a to string (e.g 1,17). Then in !(2-(r[a]=++r[a]|0)) we increase counter of occurrence element a and return true (as filter function value) if element a occurred 3 times. If r[a] is undefined the ++r[a] returns NaN, and further NaN|0=0 (also number|0=number). The r[a]= initialise first counter value, if we omit it the ++ will only set NaN to r[a] which is non-incrementable (so we need to put zero at init). If we remove 2- as result we get input array without duplicates - or alternatively we can also get this by a=>!(r[a]=a in r). If we change 2- to 1- we get array with duplicates only.

UPDATE

Even shorter version based on @ken comment can be written (it should always work with arrays of numbers). The original longer version of @ken code is in snippet and shows how @ken uses in clever way second argument of .filter to avoid usage global variable r.

array.filter(a=>!(2-(this[a]=++this[a]|0)))

var array = [[1, 17], [1, 17], [1, 17], [2, 12], [5, 9], [2, 12], [6, 2], [2, 12]];

var r= array.filter(a=>!(2-(this[a]=++this[a]|0)), {})

console.log(JSON.stringify(r));
like image 169
Kamil Kiełczewski Avatar answered Sep 29 '22 18:09

Kamil Kiełczewski


You could take a Map with stringified arrays and count, then filter by count and restore the arrays.

var array = [[1, 17], [1, 17], [1, 17], [2, 12], [5, 9], [2, 12], [6, 2], [2, 12]],
    result = Array
        .from(array.reduce(
            (map, array) =>
                (json => map.set(json, (map.get(json) || 0) + 1))
                (JSON.stringify(array)),
            new Map
         ))
        .filter(([, count]) => count > 2)
        .map(([json]) => JSON.parse(json));
        
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }

Filter with a map at wanted count.

var array = [[1, 17], [1, 17], [1, 17], [2, 12], [5, 9], [2, 12], [6, 2], [2, 12]],
    result = array.filter(
        (map => a => 
            (json =>
                (count => map.set(json, count) && !(2 - count))
                (1 + map.get(json) || 1)
            )
            (JSON.stringify(a))
        )
        (new Map)
    );
        
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }

Unique!

var array = [[1, 17], [1, 17], [1, 17], [2, 12], [5, 9], [2, 12], [6, 2], [2, 12]],
    result = array.filter(
        (s => a => (j => !s.has(j) && s.add(j))(JSON.stringify(a)))
        (new Set)
    );
        
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }
like image 24
Nina Scholz Avatar answered Sep 29 '22 17:09

Nina Scholz


You can use Object.reduce, Object.entries for this like below

var array = [[1, 17], [1, 17], [1, 17], [2, 12], [5, 9], [2, 12], [6, 2], [2, 12]];


let res = Object.entries(
            array.reduce((o, d) => {
              let key = d.join('-')
              o[key] = (o[key] || 0) + 1

              return o
          }, {}))
          .flatMap(([k, v]) => v > 2 ? [k.split('-').map(Number)] : [])
  
  
console.log(res)

OR may be just with Array.filters

var array = [[1, 17], [1, 17], [1, 17], [1, 17], [2, 12], [5, 9], [2, 12], [6, 2], [2, 12]];

let temp = {}
let res = array.filter(d => {
  let key = d.join('-')
  temp[key] = (temp[key] || 0) + 1
  
  return temp[key] == 3
})

console.log(res)
like image 45
Nitish Narang Avatar answered Sep 29 '22 19:09

Nitish Narang


For a different take, you can first sort your list, then loop through once and pull out the elements that meet your requirement. This will probably be faster than stringifying keys from the array even with the sort:

var arr = [[1, 17], [1, 17], [1, 17], [2, 12], [5, 9], [2, 12], [6, 2], [2, 12]]
arr.sort((a, b) => a[0] - b[0] || a[1] - b[1])

// define equal for array
const equal = (arr1, arr2) => arr1.every((n, j) => n === arr2[j])

let GROUP_SIZE = 3
first = 0, last = 1, res = []

while(last < arr.length){
    if (equal(arr[first], arr[last])) last++
    else {
        if (last - first >= GROUP_SIZE)  res.push(arr[first])
        first = last
    }
}
if (last - first >= GROUP_SIZE)  res.push(arr[first])
console.log(res)
like image 34
Mark Avatar answered Sep 29 '22 19:09

Mark