How to delete duplicate elements between two javascript arrays? - javascript

a = [
{ id: 1, books: [1, 2, 3, 4] },
{ id: 2, books: [1, 2, 3] },
{ id: 3, books: [1, 2, 3, 4, 5] },
{ id: 9, books: [1, 2] }
];
b = [{ id: 2, books: [1, 2, 3] }, { id: 3, books: [1, 2, 3, 4, 5] }];
I want to delete array b the same id elements from a.
How to do that? Thanks.
It means:
I want to get the a = [{id: 1, books: [1,2,3,4]}], get rid the same element within array b;
my code is:
const delDuplicate = (a, b) => {
const bLen = b.length;
if (!bLen) return a;
for (let i = 0; i < a.length; i++) {
for (let j = 0; j < bLen; j++) {
if (a[i].id === b[j].id) {
const delItem = a.splice(i, 1)[0];
console.log(delItem);
}
}
}
return a;
};
a = delDuplicate(a, b);
It works, is there a better way? I think reduce and map maybe work too.
These two arrays are not simple array. So can not use a.indexOf(b[i]) !== -1.

You can use .map(), .reduce(), .filter(), .indexOf()
var ids = b.map(o => o.id);
a = a.reduce((res, o) =>
[...res] = [...res.filter(Boolean), ids.indexOf(o.id) < 0 && o], []);
var a = [{id: 1, books: [1,2,3,4]}, {id: 2, books: [1,2,3]}, {id: 3, books: [1,2,3,4,5]}, {id: 9, books: [1,2]}];
var b = [{id: 2, books: [1,2,3]}, {id: 3, books: [1,2,3,4,5]}];
var ids = b.map(o => o.id);
a = a.reduce((res, o) =>
[...res] = [...res.filter(Boolean), ids.indexOf(o.id) < 0 && o], []);
console.log(a);

I found another way to do this. By looping through both arrays and if a match/duplicate is NOT found add this element to a third array. The third array can over write the A array at the end if required. Have tested and works.
var a = [{id: 1, books: [1,2,3,4]}, {id: 2, books: [1,2,3]}, {id: 3, books: [1,2,3,4,5]}, {id: 9, books: [1,2]}];
var b = [{id: 2, books: [1,2,3]}, {id: 3, books: [1,2,3,4,5]}];
var c = []; // New array to sort parsed A array
var boolMatch; // Boolean if duplicate is found
for(i = 0; i < a.length; i++){
boolMatch = false; // Required to reset the Boolean at the start of each loop
for(j = 0; j < b.length; j++){
if(a[i].id == b[j].id){
boolMatch = true;
break;
}
}
if(!boolMatch) c.push(a[i]); // Add to C array if element from A is NOT found in B array
}

Firstly: your question is a bit unclear to me. If you clarify, I can make this answer better. I'm asuming that you are trying to remove elements from b that have same value as the corresponding element in array a. I'm also assuming that you want to update the incidences during the search.
Now IDK the exact syntax of Javascript, so this may be a bit off. However, it should give you a general idea of what to do. (I'll try and fix the code after I research a bit)
a = [{id: 1, books: [1,2,3,4]}, {id: 2, books: [1,2,3]}, {id: 3, books: [1,2,3,4,5]}, {id: 9, books: [1,2]}]
b = [{id: 2, books: [1,2,3]}, {id: 3, books: [1,2,3,4,5]}]
//set loop size to size of the smaller array
var lsize=b.length;
if(a.length<b.length) lsize = a.length;
//loop through length
for(var i = 0; i < lsize; i++) {
if(a[i] != b[i]) { //check if the values of the elements are the same
b.splice(i, 1); //remove the element from b
i=-1; //reset loop to check rest of elements
lsize-=1; //reduce size since there is one less
}
}

To make sure you compare all the elements correctly, you should sort them by the ids to make sure you're comparing the right array elements together. This solution assumes the objects only have one other property to compare, books, which is a sorted array.
// initialize arrays
var a = [{id: 1, books: [1,2,3,4]}, {id: 2, books: [1,2,3]}, {id: 3, books: [1,2,3,4,5]}, {id: 9, books: [1,2]}];
var b = [{id: 2, books: [1,2,3]}, {id: 3, books: [1,2,3,4,5]}];
// comparator
var comp = function(a,b) {
return a.id-b.id;
};
// index for array a
var j = 0;
// sort arrays
a.sort(comp);
b.sort(comp);
// check all elements in b against those with matching ids in a
for(var i=0; i<b.length; i++) {
// find next matching id in a
while(a[j].id<b[i]&&j<a.length) {
j++;
}
// break if no more elements to check against in a
if(j==a.length) {
break;
}
// compare elements with matching ids to see if the books array make the same string
// comparing array references won't work, so they're converted to strings instead
if(a[j].id==b[i].id&&a[j].books.join(",")==b[i].books.join(",")) {
// remove element from b and don't skip over next element
b.splice(i,1);
i--;
}
}
// b should share no elements with a

Related

for loop inside array filter method [duplicate]

This question already has an answer here:
trying to use a for loop with if else statement in objects
(1 answer)
Closed 1 year ago.
Let say I have two arrays
From here I want to filter arr1 with arr2 condition (assuming arr2 = arr1 id).
I have tried this code but only return first condition.
const arr1 = [{
id: 1,
name: "Jhon"
},
{
id: 2,
name: "Barbara"
},
{
id: 3,
name: "Rio"
}
];
const arr2 = [1, 2, 5];
const filter = (arr1, arr2) => {
const output = arr1.filter(value => {
for (let i = 0; i < arr2.length; i++) {
if (value.id !== arr2[i]) {
return false;
}
return true;
}
})
console.log(output);
};
filter(arr1, arr2);
// output = [{id: 1, name: "Jhon"}]
// intended output [{id: 1, name: "Jhon"}, {id: 2, name: "Barbara}]
Anyone can tell me what I'm missing? Thank you
See the dupe why it did not work and then vastly simplify this
const arr1 = [{ id: 1, name: "Jhon" }, { id: 2, name: "Barbara" }, { id: 3, name: "Rio" } ];
const arr2 = [1, 2, 5];
const filter = (arr1, arr2) => arr1.filter(({id}) => arr2.includes(id))
console.log(filter(arr1,arr2))

How to filter an Array with another Array

I have an Array of Objects:
const array = [{id: 1, bar: "test" }, {id: 2, bar: "test2" }, {id: 3, bar: "test3" }]
I have a second array containing the ID's that I want to filter out of the first Array:
const ids = [1, 2]
How do I create a new Array of Objects without the ID's found in ids.
This is a fairly simple filter operation
const array = [{id: 1, bar: "test" }, {id: 2, bar: "test2" }, {id: 3, bar: "test3" }];
const ids = [1, 2];
var result = array.filter( x => !ids.includes(x.id));
console.log(result);
If you need to mutate the original array you can do like this:
const array = [{id: 1, bar: "test" }, {id: 2, bar: "test2" }, {id: 3, bar: "test3" }];
const ids = [1, 2];
ids.forEach(idToDelete => {
const index = array.findIndex(({ id }) => id === idToDelete);
array.splice(index, 1);
});
console.log(array);
If you need a new array you can do like this:
const array = [{id: 1, bar: "test" }, {id: 2, bar: "test2" }, {id: 3, bar: "test3" }];
const ids = [1, 2];
const result = array.filter(({ id }) => !ids.includes(id));
console.log(result);
You could also reassign a new array to the array variable:
let array = [{id: 1, bar: "test" }, {id: 2, bar: "test2" }, {id: 3, bar: "test3" }];
const ids = [1, 2];
array = array.filter(({ id }) => !ids.includes(id));
console.log(array);
Use Array.filter :
let array = [
{id: 1, bar: "test" },
{id: 2, bar: "test2" },
{id: 3, bar: "test3" }
];
let ids = [1,2];
let filteredArray = array.filter(row=>!ids.includes(row.id));
console.log(filteredArray);
Use this oneliner from lodash.
const _ = require("lodash");
let filteredArray = _.remove(array, el=>[1,2].includes(el.id))
Use filter and indexOf.
const arr = [{ id: 1, bar: 'test' }, { id: 2, bar: 'test2' }, { id: 3, bar: 'test3' }];
const ids = [1, 2];
const result = arr.filter(element => ids.indexOf(element.id) === -1);
console.log(result);
We can filter an array in JavaScript using Array filter()
const myArray = [{id: 1, bar: "test" }, {id: 2, bar: "test2" }, {id: 3, bar: "test3" }]
const ids = [1,2]
const resultArray = myArray.filter(item => !ids.includes(item.id));
console.log(resultArray);
In term of performance the best solution will be the next one:
let array = [{id: 1, bar: "test" }, {id: 2, bar: "test2" }, {id: 3, bar: "test3" }];
const ids = [1,2];
const idSet = new Set();
for (const id of ids) {
idSet.add(id);
}
array = array.filter(x => !set.has(x.id));
//const newArray if you need the initial array unmodified
In this case we perform two consequencial iteration instead of a nested one, so the time complexity will be O(n) instead of O(n^2);
##Edit
If you instead need the initial array to be mutated and not overwritten you can use this approach:
const ids = [1,2];
const array = [{id: 1, bar: "test" }, {id: 2, bar: "test2" }, {id: 3, bar: "test3" }];
for (const id of ids) {
const index = array.findIndex(x => x.id == id);
array.splice(index, 1);
}
In the second case the time complexity will be O(n*m), where n is array length and m is ids length.
I want to propose something wildly different.
In my case, I wanted to filter one list of unique IDs against another.
I was curious if regex could do it faster.
Such a method really only works with one-dimensional arrays of simple objects.
It's probably best if items a single regex 'word' (string of 0-9a-z_).
A list of ids works perfect.
array.filter works best on small datasets (1,000), usually slightly faster
regex worked 66% faster on large datasets (10,000)
regex speed advantage widens. 90% faster on 100,000.
On comparing two arrays of 1m items, filter didn't do anything for me after more than 90 seconds. Regex returned a result in six seconds.
In this case, the input is number[], and the output is string[], which works for my purposes, but you can use map to convert back to numbers if you need, .
var listlength = 10000;
function createArray() {
let arr = new Set();
for (let i = 0; i < listlength; i++) {
arr.add(Math.floor(Math.random() * listlength));
}
return arr;
}
function filter() {
let arr1 = Array.from(createArray());
let arr2 = Array.from(createArray());
let start = +new Date();
let arr3 = arr1.filter((n) => !arr2.includes(n));
console.log('filter', (+new Date() - start) + 'ms', arr1.length, arr2.length, arr3.length);
}
function regex() {
let arr1 = Array.from(createArray());
let arr2 = Array.from(createArray());
let start = +new Date();
let str1 = arr1.join(',') + ',';
str1 = str1.replace(new RegExp('\\b(' + arr2.join('|') + '),', 'g'), '');
let result = str1.split(',') // .map(e=>Number(e)); (to convert back to number[])
result.pop();
console.log('regex', (+new Date() - start) + 'ms', arr1.length, arr2.length, result.length);
}
for (let x = 0; x < 10; x++) {
console.log(`try ${x}`);
filter();
regex();
}
On my NodeJS app, sets of 100,000, regex more than 90% faster.

Remove duplicate elements from an unsorted array without using any inbuilt function or without using any other array variable in node js?

Hi in my first nodejs interview interviewer ask me to remove all duplicate elements from an unsorted array without using any inbuilt function using java script in minimum TC and without using any other array.
This is my efforts.
var input = [1, 2, 3, 3, 4, 5,2, 6,3,6,1];
var current = input[0];
var found = false;
function removeDuplicate() {
for (var i = 0; i < input.length; i++) {
if (current == input[i]) {
//found = false;
} else if (current != input[i]) {
console.log(" " + current);
current = input[i];
found = false;
}
}
console.log(" " + current);
}
removeDuplicate();
I don't really understand precisely what inbuild functions are or to what extent is a function inbuilt, so I'm assuming I'm not allowed to use indexOf, hasOwnProperty, Array.prototype.push, ...
const input = [1, 2, 3, 3, 4, 5,2, 6,3,6,1];
function removeDuplicate(arr) {
const result = [];
let idx = 0;
const tmp = {};
for (let i = 0; i < arr.length; i++) {
if (!tmp[arr[i]]) {
tmp[arr[i]] = 1;
result[idx] = arr[i];
idx++;
}
}
return result;
}
console.log(removeDuplicate(input));
If you want to remove the elements in place, then the best I can do is save the elements in place, and give the length of the eventual array. But in JavaScript, it's actually valid since arrays in JavaScript are just objects that are enumberable with an extra property length.
const input1 = [1, 2, 3, 3, 4, 5,2, 6,3,6,1];
const input2 = [1, 2, 3, 3, 4, 5,2, 6,3,6,7];
function removeDuplicate(arr) {
let length = 0;
const tmp = {};
for (let i = 0; i < arr.length; i++) {
if (!tmp[arr[i]]) {
tmp[arr[i]] = 1;
arr[length] = arr[i];
length++;
}
}
// the last element is not a duplicate
if (!tmp[arr[arr.length-1]]) {
length--;
}
arr.length = length;
return arr;
}
console.log(removeDuplicate(input1));
console.log(removeDuplicate(input2));
One line of vanilla JavaScript with no loops
Since this seems like a homework then at least make some effort to make the solution interesting.
This is my first solution but it uses a built-in .filter() method:
const removeDuplicate = (c=>a=>a.filter(e=>!(c[e]||(c[e]=1)&&0)))({});
Here is another solution without using built-ins:
const f = (c=>(h,...r)=>h?(c[h]|=0)||c[h]++?f(...r):[h,...f(...r)]:[])({});
const removeDuplicate = a => f(...a);
Here you go. One line of vanilla JavaScript plus a convenience wrapper- the second line is so you can use:
console.log(removeDuplicate(input));
// or with literals:
console.log(removeDuplicate([1, 2, 3, 3, 4, 5, 2, 6, 3, 6, 1]));
but if you're fine with this:
console.log(f(...input));
// or with literals:
console.log(f(1, 2, 3, 3, 4, 5, 2, 6, 3, 6, 1));
then you can remove the second line (and of course rename f to something better).
let arrayB = [
{id: 1, name: "abc"},
{id:2, name: "abccc"},
{id: 2, name: "xyz"},
{id:3, name: "abccc"},
{id: 4, name : "asdada"}
];
function findRepeatedObject(arr){
var newObj={};
var newArr=[];
for(i=0;i<arr.length; i++){
if(newObj[arr[i].id]){
newObj[arr[i].id]+=1;
}else{
newObj[arr[i].id]=1;
newArr.push(arr[i])
}
}
return newArr;
}
console.log(findRepeatedObject(arrayB));
//output will be [{ id: 1, name: 'abc' },{ id: 2, name: 'abccc' },{ id: 3, name: 'abccc' },{ id: 4, name: 'asdada' }];
var arr=[
{id: 1, "name": "kumar"},
{id: 1, "name": "kumar"},
{id: 2, "name": "kumar1"},
{id: 2, "name": "kumar1"},
{id: 3, "name": "kumar2"}
];
var res=[];
var count={};
arr.forEach((el,ind)=>{
count[el.id]=(count[el.id] || 0)+1;
if(count[el.id]<2){
res.push(el);
}
})
console.log(res)//[{ id: 1, name: 'kumar' },{ id: 2, name: 'kumar1' },{ id: 3, name: 'kumar2' }]enter code here

Finding a key in an object by using values from an array

I have an array which is dynamically created by selecting items from a list:
[2, 4]
I also have an array of objects:
[{id: 1, name: "Param1"}, {id: 2, name: "Param2"}, {id: 3, name: "Param3"}, {id: 4, name: "Param4"}]
What I need to do is use the values in the first array to match against the ids in the objects in the second array and return those objects.
Help with this would be much appreciated
Thanks for your time
You can use this ES6 code, which turns the first array to a Set to allow fast lookup, and then applies the Array filter method, specifically intended for this purpose:
var select = [2, 4];
var data = [{id: 1, name: "Param1"}, {id: 2, name: "Param2"},
{id: 3, name: "Param3"}, {id: 4, name: "Param4"}]
var selectSet = new Set(select);
var result = data.filter( obj => selectSet.has(obj.id) );
console.log(result);
You can just use for loop as Liam's comment, or you can use the filter method of array like this:
var keys = [2, 4];
var objs = [{id: 1, name: "Param1"}, {id: 2, name: "Param2"}, {id: 3, name: "Param3"}, {id: 4, name: "Param4"}];
function filterById(obj) {
return keys.indexOf(obj.id) != -1;
}
var newArr = objs.filter(filterById);
The newArr is the result you want.

Merge duplicates in JavaScript Array

I have a stupid problem that at first seems to be simple to solve, but turns out to be tricky.
I have an array of objects, each with two properties: id and value:
[
{id: 2, value: 10},
{id: 4, value: 3},
{id: 2, value: 2},
{id: 1, value: 15}
]
I want to write an algorithm that sums up the values of ones with similar id.
My end result should be a new array with only the merged objects:
[
{id: 2, value: 12},
{id: 4, value: 3},
{id: 1, value: 15}
]
I've tried the following, but it doesn't work:
var arr = [];
arr.push({id: 2, visit:10});
arr.push({id: 4, visit:3});
arr.push({id: 2, visit:2});
arr.push({id: 1, visit:15});
// Deep copy
var copy = jQuery.extend(true, [], arr);
var masterArr = [];
for (var i = 0; i < arr.length; i++) {
var objArr = [];
objArr.push(arr[i]);
for (var j = copy.length-1; j > -1; j--) {
if (arr[i].id === copy[j].id) {
var q = copy.splice(j,1);
}
}
masterArr.push(objArr);
}
My plan was to first gather all similar objects in separate arrays (objArr), sum them up and put them in an end array (masterArr). I use jquerys extend to make a deep copy (not a reference) and reverse iteration and splice to remove objects thats already been found as "duplicates".
This doesn't work! And it doesn't seem to be a very efficient mehtod to solve my problem.
How could I do this? Performance isn't top priority but rather "nice to have"!
Thanks!
You can do it like this:
// Assuming:
a = [{id: 2, value: 10}, {id: 4, value: 3}, {id: 2, value: 2}, {id: 1, value: 15}]
var b = {}, // Temporary variable;
c = []; // This will contain the result;
// Build a id:value object ( {1: 15, 2: 12, 4: 3} )
a.map(function(current){b[current.id] = (b[current.id] || 0) + current.value});
for(var key in b){ // Form that into the desired output format.
c.push({id: parseInt(key, 10), value: b[key]});
}
console.log(c);
/* [{id: 1, value: 15},
{id: 2, value: 12},
{id: 4, value: 3}] */
I'm using parseInt(key, 10), since the keys are strings, you'll probably want them converted to integers again.
// First group the data based on id and sum the values
var temp = data.reduce(function(result, current) {
result[current.id] = (result[current.id] || 0) + current.value;
return result;
}, {});
// then recreate the objects with proper id and value properties
var result = [];
for (var key in temp) {
result.push({
id: parseInt(key, 10),
value: temp[key]
});
}
console.log(result);
Output
[ { id: 1, value: 15 },
{ id: 2, value: 12 },
{ id: 4, value: 3 } ]
The quickest approach loops over the array only once using Array.prototype.filter():
var tmp = {},
result = arr.filter(function (el) {
if (tmp.hasOwnProperty(el.id)) {
tmp[el.id].visit += el.visit;
return false;
}
else {
tmp[el.id] = el;
return true;
}
});
It also reuses the objects, though this renders the original array to contain inaccurate values. If this is a problem, you can modify the example to copy each object property to a new object.

Categories

Resources