Remove similar duplicates from 2D array in JavaScript - javascript

I need to remove similar duplicates as well as real duplicates from 2D array in JavaScript.
let a = [
[5, 6],
[1,1],
[6,5],
[1,1],
[3,2],
[2,3]
]
function makeUnique(arr) {
var uniques = [];
var itemsFound = {};
for(var i = 0, l = arr.length; i < l; i++) {
var stringified = JSON.stringify(arr[i]);
if(itemsFound[stringified]) continue;
uniques.push(arr[i]);
itemsFound[stringified] = true;
}
return uniques;
}
a=makeUnique(a)
console.log(a);
I have got this output:
[ [ 5, 6 ], [ 1, 1 ], [ 6, 5 ], [ 3, 2 ], [ 2, 3 ] ]
Correct should be:
[ [ 5, 6 ], [ 1, 1 ], [ 2, 3 ] ]
My code removes correctly duplicates, but I need to remove similar duplicates also.
For example if I have [3,2] and [2,3] I should remove [3,2] (the one which has bigger starting index value.)
Could you help me to fix this?

Here is an example of how you can do it:
function makeUnique(arr) {
var uniques = [];
var itemsFound = {};
arr.sort((a, b) => a[0] + a[1] - (b[0] + b[1]))
for (var i = 0, l = arr.length; i < l; i++) {
if (!itemsFound[arr[i]] && !itemsFound[[arr[i][1], arr[i][1]]]) {
uniques.push(arr[i]);
itemsFound[arr[i]] = true;
itemsFound[[arr[i][1], arr[i][0]]] = true;
}
}
return uniques;
}
I hope it helps.

There are two parts
similar should be considered
among similar, one with smaller first key should stay
1. Similar should be considered
Here you can just make the key for hashmap in such a way that similar items produce same key.
One way to do that is sort the items in the tuple and then form the key, as there are two items only, first one will be min and second one will be max
let a = [
[5, 6],
[1,1],
[6,5],
[1,1],
[3,2],
[2,3]
]
function makeUnique(arr) {
var uniques = [];
var itemsFound = {};
for(var i = 0, l = arr.length; i < l; i++) {
let [a,b] = arr[i];
const hashKey = [ Math.min(a,b), Math.max(a,b)];
var stringified = JSON.stringify(hashKey);
if(itemsFound[stringified]) continue;
uniques.push(arr[i]);
itemsFound[stringified] = true;
}
return uniques;
}
let ans1=makeUnique(a)
console.log(ans1);
2. Among similar, the one with smaller first key should stay
Now you can remember in the hashmap what the value for a key was and keep updating it based on the correct candidate
let a = [
[5, 6],
[1,1],
[6,5],
[1,1],
[3,2],
[2,3]
]
function makeUniqueSmallerFirst(arr) {
var items = {};
for(var i = 0, l = arr.length; i < l; i++) {
let [a,b] = arr[i];
const hashKey = [ Math.min(a,b), Math.max(a,b)];
var stringified = JSON.stringify(hashKey);
if (stringified in items) {
let previous = items[stringified];
if (previous[0] > arr[i][0]) {
items[stringified] = arr[i];
}
} else {
items[stringified] = arr[i] // I am just storing the array because if I see a similar item next time, I can compare if that has first item smaller or not
}
}
return Object.values(items); // this doesn't guarantee output order though
// if you want order as well . you can iterate over input array once more and arrange the items in the preferred order.
}
let ans2=makeUniqueSmallerFirst(a)
console.log(ans2);

UPDATED (More simple and faster example for ES5+):
function makeUnique(arr) {
return new Set(a.map(
arr => JSON.stringify(arr.sort((a, b) => a - b)))
)
}
const m = makeUnique(a)
console.log(m) //
OLD:
This is an example of code that makes a two-dimensional array with arrays of any length unique.
let a = [
[5, 6],
[1, 1],
[6, 5],
[1, 5],
[3, 2],
[2, 3],
[6, 5, 3],
[3, 5, 6]
]
function isUnique(uniqueArray, checkedArray) {
let checked = [...checkedArray];
let unique = [...uniqueArray];
let uniqueValue = 0;
unique.forEach(value => {
if (checked.includes(value)) {
checked.splice(checked.indexOf(value), 1)
} else uniqueValue++;
})
return uniqueValue > 0;
}
function makeUnique(array2d) {
let unique = [array2d[0]]
array2d.forEach(checkedArray => {
if (unique.some(uniqueArray => {
if (checkedArray.length !== uniqueArray.length) return false;
return !isUnique(uniqueArray, checkedArray)
}
)) return 0;
else unique.push(checkedArray)
})
return unique
}
console.log(makeUnique(a)) // [ [ 5, 6 ], [ 1, 1 ], [ 1, 5 ], [ 3, 2 ], [ 6, 5, 3 ] ]
isUnique() this function checks if the numbers in both arrays are unique, and if they are, it outputs true. We use the copy through spread operator, so that when you delete a number from an array, the array from outside is not affected.
makeUnique() function makes the array unique, in the following way:
It checks if our unique two-dimensional array has at least one array that is identical to checkedArray
The first check if the arrays are of different lengths - they are unique, skip and check for uniqueness, if !isUnique gives out true, then the array is skipped by return 0

Related

Find all duplicates in array of objects [duplicate]

I need to check a JavaScript array to see if there are any duplicate values. What's the easiest way to do this? I just need to find what the duplicated values are - I don't actually need their indexes or how many times they are duplicated.
I know I can loop through the array and check all the other values for a match, but it seems like there should be an easier way.
Similar question:
Get all unique values in a JavaScript array (remove duplicates)
You could sort the array and then run through it and then see if the next (or previous) index is the same as the current. Assuming your sort algorithm is good, this should be less than O(n2):
const findDuplicates = (arr) => {
let sorted_arr = arr.slice().sort(); // You can define the comparing function here.
// JS by default uses a crappy string compare.
// (we use slice to clone the array so the
// original array won't be modified)
let results = [];
for (let i = 0; i < sorted_arr.length - 1; i++) {
if (sorted_arr[i + 1] == sorted_arr[i]) {
results.push(sorted_arr[i]);
}
}
return results;
}
let duplicatedArray = [9, 9, 111, 2, 3, 4, 4, 5, 7];
console.log(`The duplicates in ${duplicatedArray} are ${findDuplicates(duplicatedArray)}`);
In case, if you are to return as a function for duplicates. This is for similar type of case.
Reference: https://stackoverflow.com/a/57532964/8119511
If you want to elimate the duplicates, try this great solution:
function eliminateDuplicates(arr) {
var i,
len = arr.length,
out = [],
obj = {};
for (i = 0; i < len; i++) {
obj[arr[i]] = 0;
}
for (i in obj) {
out.push(i);
}
return out;
}
console.log(eliminateDuplicates([1,6,7,3,6,8,1,3,4,5,1,7,2,6]))
Source:
http://dreaminginjavascript.wordpress.com/2008/08/22/eliminating-duplicates/
This is my answer from the duplicate thread (!):
When writing this entry 2014 - all examples were for-loops or jQuery. JavaScript has the perfect tools for this: sort, map and reduce.
Find duplicate items
var names = ['Mike', 'Matt', 'Nancy', 'Adam', 'Jenny', 'Nancy', 'Carl']
const uniq = names
.map((name) => {
return {
count: 1,
name: name
};
})
.reduce((result, b) => {
result[b.name] = (result[b.name] || 0) + b.count;
return result;
}, {});
const duplicates = Object.keys(uniq).filter((a) => uniq[a] > 1);
console.log(duplicates); // [ 'Nancy' ]
More functional syntax:
#Dmytro-Laptin pointed out some code that can be removed. This is a more compact version of the same code. Using some ES6 tricks and higher-order functions:
const names = ['Mike', 'Matt', 'Nancy', 'Adam', 'Jenny', 'Nancy', 'Carl'];
const count = names =>
names.reduce((result, value) => ({ ...result,
[value]: (result[value] || 0) + 1
}), {}); // don't forget to initialize the accumulator
const duplicates = dict =>
Object.keys(dict).filter((a) => dict[a] > 1);
console.log(count(names)); // { Mike: 1, Matt: 1, Nancy: 2, Adam: 1, Jenny: 1, Carl: 1 }
console.log(duplicates(count(names))); // [ 'Nancy' ]
UPDATED: Short one-liner to get the duplicates:
[1, 2, 2, 4, 3, 4].filter((e, i, a) => a.indexOf(e) !== i) // [2, 4]
To get the array without duplicates simply invert the condition:
[1, 2, 2, 4, 3, 4].filter((e, i, a) => a.indexOf(e) === i) // [1, 2, 3, 4]
Note that this answer’s main goal is to be short. If you need something performant for a big array, one possible solution is to sort your array first (if it is sortable) then do the following to get the same kind of results as above:
myHugeSortedArray.filter((e, i, a) => a[i-1] === e)
Here is an example for a 1 000 000 integers array:
const myHugeIntArrayWithDuplicates =
[...Array(1_000_000).keys()]
// adding two 0 and four 9 duplicates
.fill(0, 2, 4).fill(9, 10, 14)
console.time("time")
console.log(
myHugeIntArrayWithDuplicates
// a possible sorting method for integers
.sort((a, b) => a > b ? 1 : -1)
.filter((e, i, a) => a[i-1] === e)
)
console.timeEnd("time")
On my AMD Ryzen 7 5700G dev machine it outputs:
[ 0, 0, 9, 9, 9, 9 ]
time: 22.738ms
As pointed out in the comments both the short solution and the performant solution will return an array with several time the same duplicate if it occurs more than once in the original array:
[1, 1, 1, 2, 2, 2, 2].filter((e, i, a) => a.indexOf(e) !== i) // [1, 1, 2, 2, 2]
If unique duplicates are wanted then a function like
function duplicates(arr) {
return [...new Set(arr.filter((e, i, a) => a.indexOf(e) !== i))]
}
can be used so that duplicates([1, 1, 1, 2, 2, 2, 2]) returns [1, 2].
When all you need is to check that there are no duplicates as asked in this question you can use the every() method:
[1, 2, 3].every((e, i, a) => a.indexOf(e) === i) // true
[1, 2, 1].every((e, i, a) => a.indexOf(e) === i) // false
Note that every() doesn't work for IE 8 and below.
Find duplicate values in an array
This should be one of the shortest ways to actually find duplicate values in an array. As specifically asked for by the OP, this does not remove duplicates but finds them.
var input = [1, 2, 3, 1, 3, 1];
var duplicates = input.reduce(function(acc, el, i, arr) {
if (arr.indexOf(el) !== i && acc.indexOf(el) < 0) acc.push(el); return acc;
}, []);
document.write(duplicates); // = 1,3 (actual array == [1, 3])
This doesn't need sorting or any third party framework. It also doesn't need manual loops. It works with every value indexOf() (or to be clearer: the strict comparision operator) supports.
Because of reduce() and indexOf() it needs at least IE 9.
You can add this function, or tweak it and add it to Javascript's Array prototype:
Array.prototype.unique = function () {
var r = new Array();
o:for(var i = 0, n = this.length; i < n; i++)
{
for(var x = 0, y = r.length; x < y; x++)
{
if(r[x]==this[i])
{
alert('this is a DUPE!');
continue o;
}
}
r[r.length] = this[i];
}
return r;
}
var arr = [1,2,2,3,3,4,5,6,2,3,7,8,5,9];
var unique = arr.unique();
alert(unique);
UPDATED: The following uses an optimized combined strategy. It optimizes primitive lookups to benefit from hash O(1) lookup time (running unique on an array of primitives is O(n)). Object lookups are optimized by tagging objects with a unique id while iterating through so so identifying duplicate objects is also O(1) per item and O(n) for the whole list. The only exception is items that are frozen, but those are rare and a fallback is provided using an array and indexOf.
var unique = function(){
var hasOwn = {}.hasOwnProperty,
toString = {}.toString,
uids = {};
function uid(){
var key = Math.random().toString(36).slice(2);
return key in uids ? uid() : uids[key] = key;
}
function unique(array){
var strings = {}, numbers = {}, others = {},
tagged = [], failed = [],
count = 0, i = array.length,
item, type;
var id = uid();
while (i--) {
item = array[i];
type = typeof item;
if (item == null || type !== 'object' && type !== 'function') {
// primitive
switch (type) {
case 'string': strings[item] = true; break;
case 'number': numbers[item] = true; break;
default: others[item] = item; break;
}
} else {
// object
if (!hasOwn.call(item, id)) {
try {
item[id] = true;
tagged[count++] = item;
} catch (e){
if (failed.indexOf(item) === -1)
failed[failed.length] = item;
}
}
}
}
// remove the tags
while (count--)
delete tagged[count][id];
tagged = tagged.concat(failed);
count = tagged.length;
// append primitives to results
for (i in strings)
if (hasOwn.call(strings, i))
tagged[count++] = i;
for (i in numbers)
if (hasOwn.call(numbers, i))
tagged[count++] = +i;
for (i in others)
if (hasOwn.call(others, i))
tagged[count++] = others[i];
return tagged;
}
return unique;
}();
If you have ES6 Collections available, then there is a much simpler and significantly faster version. (shim for IE9+ and other browsers here: https://github.com/Benvie/ES6-Harmony-Collections-Shim)
function unique(array){
var seen = new Set;
return array.filter(function(item){
if (!seen.has(item)) {
seen.add(item);
return true;
}
});
}
var a = ["a","a","b","c","c"];
a.filter(function(value,index,self){ return (self.indexOf(value) !== index )})
This should get you what you want, Just the duplicates.
function find_duplicates(arr) {
var len=arr.length,
out=[],
counts={};
for (var i=0;i<len;i++) {
var item = arr[i];
counts[item] = counts[item] >= 1 ? counts[item] + 1 : 1;
if (counts[item] === 2) {
out.push(item);
}
}
return out;
}
find_duplicates(['one',2,3,4,4,4,5,6,7,7,7,'pig','one']); // -> ['one',4,7] in no particular order.
Find non-unique values from 3 arrays (or more):
ES2015
// 🚩🚩 🚩 🚩 🚩
var arr = [1,2,2,3,3,4,5,6,2,3,7,8,5,22],
arr2 = [1,2,511,12,50],
arr3 = [22,0],
merged,
nonUnique;
// Combine all the arrays to a single one
merged = arr.concat(arr2, arr3)
// create a new (dirty) Array with only the non-unique items
nonUnique = merged.filter((item,i) => merged.includes(item, i+1))
// Cleanup - remove duplicate & empty items items
nonUnique = [...new Set(nonUnique)]
console.log(nonUnique)
PRE-ES2015:
In the below example I chose to superimpose a unique method on top of the Array prototype, allowing access from everywhere and has more "declarative" syntax. I do not recommend this approach on large projects, since it might very well collide with another method with the same custom name.
Array.prototype.unique = function () {
var arr = this.sort(), i=arr.length; // input must be sorted for this to work
while(i--)
arr[i] === arr[i-1] && arr.splice(i,1) // remove duplicate item
return arr
}
Array.prototype.nonunique = function () {
var arr = this.sort(), i=arr.length, res = []; // input must be sorted for this to work
while(i--)
arr[i] === arr[i-1] && (res.indexOf(arr[i]) == -1) && res.push(arr[i])
return res
}
// 🚩🚩 🚩 🚩 🚩
var arr = [1,2,2,3,3,4,5,6,2,3,7,8,5,22],
arr2 = [1,2,511,12,50],
arr3 = [22,0],
// merge all arrays & call custom Array Prototype - "unique"
unique = arr.concat(arr2, arr3).unique(),
nonunique = arr.concat(arr2, arr3).nonunique()
console.log(unique) // [1,12,2,22,3,4,5,50,511,6,7,8]
console.log(nonunique) // [1,12,2,22,3,4,5,50,511,6,7,8]
using underscore.js
function hasDuplicate(arr){
return (arr.length != _.uniq(arr).length);
}
The simplest and quickest way is to use the Set object:
const numbers = [1, 2, 3, 2, 4, 5, 5, 6];
const set = new Set(numbers);
const duplicates = numbers.filter(item => {
if (set.has(item)) {
set.delete(item);
return false;
} else {
return true;
}
});
// OR more concisely
const duplicates = numbers.filter(item => !set.delete(item));
console.log(duplicates);
// [ 2, 5 ]
This is my proposal (ES6):
let a = [1, 2, 3, 4, 2, 2, 4, 1, 5, 6]
let b = [...new Set(a.sort().filter((o, i) => o !== undefined && a[i + 1] !== undefined && o === a[i + 1]))]
// b is now [1, 2, 4]
Here's the simplest solution I could think of:
const arr = [-1, 2, 2, 2, 0, 0, 0, 500, -1, 'a', 'a', 'a']
const filtered = arr.filter((el, index) => arr.indexOf(el) !== index)
// => filtered = [ 2, 2, 0, 0, -1, 'a', 'a' ]
const duplicates = [...new Set(filtered)]
console.log(duplicates)
// => [ 2, 0, -1, 'a' ]
That's it.
Note:
It works with any numbers including 0, strings and negative numbers e.g. -1 -
Related question: Get all unique values in a JavaScript array (remove duplicates)
The original array arr is preserved (filter returns the new array instead of modifying the original)
The filtered array contains all duplicates; it can also contain more than 1 same value (e.g. our filtered array here is [ 2, 2, 0, 0, -1, 'a', 'a' ])
If you want to get only values that are duplicated (you don't want to have multiple duplicates with the same value) you can use [...new Set(filtered)] (ES6 has an object Set which can store only unique values)
Hope this helps.
Here is mine simple and one line solution.
It searches not unique elements first, then makes found array unique with the use of Set.
So we have array of duplicates in the end.
var array = [1, 2, 2, 3, 3, 4, 5, 6, 2, 3, 7, 8, 5, 22, 1, 2, 511, 12, 50, 22];
console.log([...new Set(
array.filter((value, index, self) => self.indexOf(value) !== index))]
);
Shortest vanilla JS:
[1,1,2,2,2,3].filter((v,i,a) => a.indexOf(v) !== i) // [1, 2, 2]
one liner simple way
var arr = [9,1,2,4,3,4,9]
console.log(arr.filter((ele,indx)=>indx!==arr.indexOf(ele))) //get the duplicates
console.log(arr.filter((ele,indx)=>indx===arr.indexOf(ele))) //remove the duplicates
var a = [324,3,32,5,52,2100,1,20,2,3,3,2,2,2,1,1,1].sort();
a.filter(function(v,i,o){return i&&v!==o[i-1]?v:0;});
or when added to the prototyp.chain of Array
//copy and paste: without error handling
Array.prototype.unique =
function(){return this.sort().filter(function(v,i,o){return i&&v!==o[i-1]?v:0;});}
See here: https://gist.github.com/1305056
Fast and elegant way using es6 object destructuring and reduce
It runs in O(n) (1 iteration over the array) and doesn't repeat values that appear more than 2 times
const arr = ['hi', 'hi', 'hi', 'bye', 'bye', 'asd']
const {
dup
} = arr.reduce(
(acc, curr) => {
acc.items[curr] = acc.items[curr] ? acc.items[curr] += 1 : 1
if (acc.items[curr] === 2) acc.dup.push(curr)
return acc
}, {
items: {},
dup: []
},
)
console.log(dup)
// ['hi', 'bye']
You can use filter method and indexOf() to get all the duplicate values
function duplicate(arr) {
return duplicateArray = arr.filter((item, index) => arr.indexOf(item) !== index)
}
arr.indexOf(item) will always return the first index at which a given element can be
found
ES5 only (i.e., it needs a filter() polyfill for IE8 and below):
var arrayToFilter = [ 4, 5, 5, 5, 2, 1, 3, 1, 1, 2, 1, 3 ];
arrayToFilter.
sort().
filter( function(me,i,arr){
return (i===0) || ( me !== arr[i-1] );
});
Here is a very light and easy way:
var codes = dc_1.split(',');
var i = codes.length;
while (i--) {
if (codes.indexOf(codes[i]) != i) {
codes.splice(i,1);
}
}
ES6 offers the Set data structure which is basically an array that doesn't accept duplicates.
With the Set data structure, there's a very easy way to find duplicates in an array (using only one loop).
Here's my code
function findDuplicate(arr) {
var set = new Set();
var duplicates = new Set();
for (let i = 0; i< arr.length; i++) {
var size = set.size;
set.add(arr[i]);
if (set.size === size) {
duplicates.add(arr[i]);
}
}
return duplicates;
}
With ES6 (or using Babel or Typescipt) you can simply do:
var duplicates = myArray.filter(i => myArray.filter(ii => ii === i).length > 1);
https://es6console.com/j58euhbt/
Simple code with ES6 syntax (return sorted array of duplicates):
let duplicates = a => {d=[]; a.sort((a,b) => a-b).reduce((a,b)=>{a==b&&!d.includes(a)&&d.push(a); return b}); return d};
How to use:
duplicates([1,2,3,10,10,2,3,3,10]);
I have just figured out a simple way to achieve this using an Array filter
var list = [9, 9, 111, 2, 3, 4, 4, 5, 7];
// Filter 1: to find all duplicates elements
var duplicates = list.filter(function(value,index,self) {
return self.indexOf(value) !== self.lastIndexOf(value) && self.indexOf(value) === index;
});
console.log(duplicates);
This answer might also be helpful, it leverages js reduce operator/method to remove duplicates from array.
const result = [1, 2, 2, 3, 3, 3, 3].reduce((x, y) => x.includes(y) ? x : [...x, y], []);
console.log(result);
Higher ranked answers have a few inherent issues including the use of legacy javascript, incorrect ordering or with only support for 2 duplicated items.
Here's a modern solution which fixes those problems:
const arrayNonUniq = array => {
if (!Array.isArray(array)) {
throw new TypeError("An array must be provided!")
}
return array.filter((value, index) => array.indexOf(value) === index && array.lastIndexOf(value) !== index)
}
arrayNonUniq([1, 1, 2, 3, 3])
//=> [1, 3]
arrayNonUniq(["foo", "foo", "bar", "foo"])
//=> ['foo']
You can also use the npm package array-non-uniq.
The following function (a variation of the eliminateDuplicates function already mentioned) seems to do the trick, returning test2,1,7,5 for the input ["test", "test2", "test2", 1, 1, 1, 2, 3, 4, 5, 6, 7, 7, 10, 22, 43, 1, 5, 8]
Note that the problem is stranger in JavaScript than in most other languages, because a JavaScript array can hold just about anything. Note that solutions that use sorting might need to provide an appropriate sorting function--I haven't tried that route yet.
This particular implementation works for (at least) strings and numbers.
function findDuplicates(arr) {
var i,
len=arr.length,
out=[],
obj={};
for (i=0;i<len;i++) {
if (obj[arr[i]] != null) {
if (!obj[arr[i]]) {
out.push(arr[i]);
obj[arr[i]] = 1;
}
} else {
obj[arr[i]] = 0;
}
}
return out;
}
var arr = [2, 1, 2, 2, 4, 4, 2, 5];
function returnDuplicates(arr) {
return arr.reduce(function(dupes, val, i) {
if (arr.indexOf(val) !== i && dupes.indexOf(val) === -1) {
dupes.push(val);
}
return dupes;
}, []);
}
alert(returnDuplicates(arr));
This function avoids the sorting step and uses the reduce() method to push duplicates to a new array if it doesn't already exist in it.

Function that returns all indexes that do not overlap - Javascript

I have an array like so:
[
{
indexes: [1, 3, 5, 8],
length: 2
},
{
indexes: [2, 4, 6, 7],
length: 1
}
]
I am using this to split a string (and many other similar ones):
matatatatt
I am trying to split it by the array ['at', 't'], which should return something like this in the future:
['m', 'at', 'at', 'at', 'at', 't']
This is the code I currently have:
function splitVars (eq, vars) {
let splitted = eq.split("");
let locs = [];
for (let i = 0; i < vars.length; i++) {
let variable = vars[i];
let found = locations(variable, eq)
locs.push({
indexes: found,
variable: variable,
varLength: variable.length
})
}
return locs;
}
function locations(substring, string){
var a=[],
i=-1;
while((i = string.indexOf(substring, i + 1)) >= 0) a.push(i);
return a;
}
console.log(splitVars('wmtmtmtt', ['mt', 't']));
However, back to my question.
As you can tell, because the length of the second string is one, it is picking up the one letter in the first indexes that is the same. Because the indexes [2, 4, 6] are overlapping with the first indexes, I would like to remove them.
How can I do such a thing?

Check array overlapping in JavaScript

I have some arrays like [1,5], [3,6], [2,8],[19,13], [12,15]. When i pass two arrays in the function output will be [1,6], [2,19],[12,15]
i want to remove overlapping numbers from 2 arrays . like on fist and second array 5 and 3 will be overlap between 1 to 6.
I believe this is what you want (you get the min of the first array and the max of the second array):
function removeOverlap(arr1, arr2) {
if (arr1 === undefined) {
return arr2;
}
if (arr2 === undefined) {
return arr1;
}
return [Math.min.apply(null, arr1), Math.max.apply(null, arr2)];
}
// Sample:
var myArrays = [[1,5], [3,6], [2,8], [19,13], [12,15]];
for (var i = 0; i < myArrays.length; i = i + 2) {
console.log(removeOverlap(myArrays[i], myArrays[i + 1]));
}
EDIT: answer with multiple parameters as you requested in your comment:
We could use rest parameters in the answer below, but I will use the arguments object for compatibility with Internet Explorer. If this is not a requirement you can adapt the solution to use the first.
function removeOverlap(arr1, arr2) {
// Converting the arguments object to array:
var argsArray = Array.prototype.slice.call(arguments);
// Removing undefined:
argsArray = argsArray.filter(function(el) {
return el != undefined;
});
// Alternative (not compatible with Internet Explorer):
//argsArray = argsArray.filter(el => el);
// We're looking for the min and max numbers, let's merge the arrays
// e.g. transform [[1, 5], [3, 6], [2, 8]] into [1, 5, 3, 6, 2, 8]
var merged = [].concat.apply([], argsArray);
// Alternative, but it is not compatible with Internet Explorer:
//var merged = Array.flat(argsArray);
return [Math.min.apply(null, merged), Math.max.apply(null, merged)];
}
// Sample:
var myArrays = [[1,5], [3,6], [2,8], [19,13], [12,15]];
for (var i = 0; i < myArrays.length; i = i + 2) {
console.log(removeOverlap(myArrays[i], myArrays[i + 1]));
}
console.log(removeOverlap(myArrays[0], myArrays[1], myArrays[2]));
This can easily be accomplished my finding the min of the current and max of the next item.
let initial = [ [1, 5], [3, 6], [2, 8], [19, 13], [12, 15] ]
let expected = [ [1, 6], [2, 19], [12, 15] ]
let actual = calculateOverlaps(initial);
console.log(JSON.stringify(actual) === JSON.stringify(expected)); // true
function calculateOverlaps(arr) {
let result = [];
for (let i = 0; i < arr.length; i+=2) {
if (i >= arr.length - 1) {
result.push(arr[i]); // If the array has an odd size, get last item
} else {
let curr = arr[i];
let next = arr[i + 1];
result.push([ Math.min(...curr), Math.max(...next) ]);
}
}
return result;
}
Here is a more code-golf oriented function:
const calculateOverlaps1 = (arr) => arr.reduce((r, e, i, a) =>
(i % 2 === 0)
? r.concat([
(i < a.length - 1)
? [ Math.min(...e), Math.max(...a[i+1]) ]
: e
])
: r, []);
And even smaller, at just 101 bytes.
f=a=>a.reduce((r,e,i)=>i%2===0?r.concat([i<a.length-1?[Math.min(...e),Math.max(...a[i+1])]:e]):r,[]);

Find consecutive numbers in multiples arrays JavaScript

I have array structured like this:
[
[8,[1]],
[15,[2]],
[20,[3]],
[23,[4,41]],
[497,[18]],
[1335,[38]],
[2092,[39,55,61]],
[3615,[5]],
[4121,[14]],
[5706,[39,55,61]],
[5711,[62]],
[5714,[63]],
[5719,[64]],
[6364,[38]]
]
I use the modified code from this answer to find consecutive numbers but I can't adapt it to also find consecutive numbers from arrays with multiple values
This is my code :
const a = [
[8,[1]],
[15,[2]],
[20,[3]],
[23,[4,41]],
[497,[18]],
[1335,[38]],
[2092,[39,55,61]],
[3615,[5]],
[4121,[14]],
[5706,[39,55,61]],
[5711,[62]],
[5714,[63]],
[5719,[64]],
[6364,[38]]
];
// this variable will contain arrays
let finalArray = [];
// Create a recursive function
function checkPrevNextNumRec(array) {
let tempArr = [];
// if the array contaon only 1 element then push it in finalArray and
// return it
if (array.length === 1) {
finalArray.push(array);
return
}
// otherside check the difference between current & previous number
for (let i = 1; i < array.length; i++) {
if (array[i][1][0] - array[i - 1][1][0] === 1) {
// if current & previous number is 1,0 respectively
// then 0 will be pushed
tempArr.push(array[i - 1]);
} else {
// if current & previous number is 5,2 respectively
// then 2 will be pushed
tempArr.push(array[i - 1])
// create a an array and recall the same function
// example from [0, 1, 2, 5, 6, 9] after removing 0,1,2 it
// will create a new array [5,6,9]
let newArr = array.splice(i);
finalArray.push(tempArr);
checkPrevNextNumRec(newArr)
}
// for last element if it is not consecutive of
// previous number
if (i === array.length - 1) {
tempArr.push(array[i]);
finalArray.push(tempArr)
}
}
}
checkPrevNextNumRec(a)
And here the result, as you can see, all the tables containing consecutive figures in [i][1][0] have been grouped
[
[
[8,[1]],
[15,[2]],
[20,[3]],
[23,[4,41]]
],
[
[497,[18]]
],
[
[1335,[38]],
[2092, [39,55,61]]
],
[
[3615,[5]]
],
[
[4121,[14]]
],
[
[5706,[39,55,61]]
],
[
[5711,[62]],
[5714,[63]],
[5719,[64]]
],
[
[6364,[38]]
]
]
But I need that field 5706 is also included with 5711, 5714, and 5719, but obviously it is not included because is not in [i][1][0]
I thought of being inspired by this post but I cannot integrate it correctly
Can you help me?
Thanks!
The following code enumerates each of the items in the array.
For each item, its sub-array is enumerated to see if the following item fits in a sequence.
If it fits in sequence, the next item is appended to a temporary variable, and we continue to the next item.
If the last entry in the subarray is reached without detecting a continuation of the sequence, we end the current sequence, start a new sequence and continue to the next item.
const data = [ [8,[1]], [15,[2]], [20,[3]], [23,[4,41]], [497,[18]], [1335,[38]], [2092,[39,55,61]], [3615,[5]], [4121,[14]], [5706,[39,55,61]], [5711,[62]], [5714,[63]], [5719,[64]], [6364,[38]] ]
function sequences(data) {
const result = []
let sequence = [data[0]]
for(let x=0; x<data.length-1; x++) {
const [,sub] = data[x]
for(let y=0; y<sub.length; y++) {
const currSubV = sub[y]
const [,nextSub] = data[x+1]
if(nextSub.some((nextSubV) => currSubV+1 === nextSubV)) {
sequence.push(data[x+1])
break
}
if(y === sub.length-1) {
result.push(sequence)
sequence = [data[x+1]]
}
}
}
return result
}
for(let s of sequences(data)) console.log(JSON.stringify(s).replace(/\s/g))
Basically the logic here is to iterate over the input and at each iteration, compare it with the data values from the previous iteration i.e.:prevData.
On each iteration, I used Array.prototype.map to create a new array that contains the what-would-be consecutive values (relative to the data in the previous iteration) by simply adding 1 to each item in prevData.
Next step is to loop that array to see if we encounter a consecutive value - as soon as we do we can break as there's no need to keep checking.
Finally is we apply the grouping logic with a single if/else.
const a = [
[8, [1]],
[15, [2]],
[20, [3]],
[23, [4, 41]],
[497, [18]],
[1335, [38]],
[2092, [39, 55, 61]],
[3615, [5]],
[4121, [14]],
[5706, [39, 55, 61]],
[5711, [62]],
[5714, [63]],
[5719, [64]],
[6364, [38]]
];
function group(input) {
let prev;
return input.reduce((accum, el) => {
let hasConsecutive = false;
const [key, current] = el;
if (prev == null) {
prev = current;
}
const consecutives = prev.map(n => n + 1);
for (let i = 0; i < consecutives.length; i += 1) {
if (current.includes(consecutives[i])) {
hasConsecutive = true;
break;
}
}
if (prev && hasConsecutive) {
accum[accum.length - 1].push(el);
} else {
accum.push([el]);
}
prev = current;
return accum;
}, []);
}
console.log(group(a));
Here's the result run through a beautifier:
[
[
[8, [1]],
[15, [2]],
[20, [3]],
[23, [4, 41]]
],
[
[497, [18]]
],
[
[1335, [38]],
[2092, [39, 55, 61]]
],
[
[3615, [5]]
],
[
[4121, [14]]
],
[
[5706, [39, 55, 61]],
[5711, [62]],
[5714, [63]],
[5719, [64]]
],
[
[6364, [38]]
]
]
You need to check the last element of the grouped value.
const
array = [[8, [1]], [15, [2]], [20, [3]], [23, [4, 41]], [497, [18]], [1335, [38]], [2092, [39, 55, 61]], [3615, [5]], [4121, [14]], [5706, [39, 55, 61]], [5711, [62]], [5714, [63]], [5719, [64]], [6364, [38]]],
grouped = array.reduce((r, a) => {
var last = r[r.length - 1];
if (!last || last[last.length - 1][1][0] + 1 !== a[1][0]) r.push(last = []);
last.push(a);
return r;
}, []);
console.log(grouped);
.as-console-wrapper { max-height: 100% !important; top: 0; }

How to create an unique combination of array elements in Javascript?

I have an array of object where I want to create every unique combination of objects as its own array. The combinations also need to include a different number of elements and should work regardless of the elements provided. To simplify the problem let's say we have the following array.
let arr = [1, 2, 3];
The result in this situation would be the following:
[1]
[2]
[3]
[1, 2]
[1, 3]
[2, 3]
[1, 2, 3]
I have looked for a solution and have found an approach using cartesian products, but this doesn't really seem to apply for this case since i need unique combinations and no replicates. How can I a approach this problem with Javascript?
You could take a recursive approach and return an array of items.
function combinations(array) {
function iter(index, temp = []) {
if (!index--) return;
iter(index, temp);
result.push(temp = [array[index], ...temp]);
iter(index, temp);
}
var result = [];
iter(array.length);
return result;
}
combinations([1, 2, 3]).forEach(a => console.log(a.join(' ')));
.as-console-wrapper { max-height: 100% !important; top: 0; }
This can be defined recursively in pseudo-Javascript:
function combos(arr) {
if arr is empty
return arr;
else {
result = [];
// for every combination from the rest of the list
for x in combos( arr.slice(1) ) {
// get that combination w/o arr[0]
result.push( x );
x.push( arr[0] );
// … and the combination w/ arr[0]
result.push( x );
}
}
}
I managed to create a solution on my own. I created two helper functions for making the problem easier. The first one is just a function for switching array indexes and the second one is a recursive function that let's me remove an element at each recursive call and sums the result to its own array.
By iterating for every element i can get all the n-length combinations for the array. Then I remove the first element and repeat the procedure until i am out of elements. This will give me all the solutions, but they will have duplicates.
By sorting them ascending and converting them to a string i can create a Set out of them, which will create unique strings. The last step is to remove the duplicates and I end up with all the combinations.
let arr = [1, 2, 3];
let result = [];
while (arr.length !== 0) {
for (let i = 0; i < arr.length; i++) {
result = [...result, ...levelCombo(arr)];
arr = switchIndex(arr, 0, i);
}
arr = arr.slice(1);
}
result = result.map(el => JSON.stringify(el.sort()));
let uniqueResult = [...new Set(result)].map(el => JSON.parse(el));
console.log(uniqueResult);
function switchIndex(arr, a, b) {
let val1 = arr[a];
let val2 = arr[b];
arr[a] = val2;
arr[b] = val1;
return arr;
}
function levelCombo(arr) {
let result = [];
if (arr.length === 0) {
return [];
}
for (let i = 0; i < arr.length; i++) {
result.push(arr[i]);
}
result = [result, ...levelCombo(arr.slice(1))];
return result;
}
For the input [1, 2, 3] the printed result will be the following:
[
[ 1, 2, 3 ],
[ 2, 3 ],
[ 3 ],
[ 1, 3 ],
[ 1, 2 ],
[ 2 ],
[ 1 ]
]

Categories