JS json array compare array and remove duplicates - javascript

I have below two arrays which are similar in structure except for additional key in the array 1 When I get array 2 I would like to remove duplicates from array 2 if they are already present in array 1.
For e.g. 2nd item is a duplicate.
Array 1:
[{
"from": "1",
"to": "2",
"text": "test",
"_goid": "1234"
}, {
"from": "3",
"to": "4",
"text": "test",
"_goid": "12345"
}, {
"from": "5",
"to": "6",
"text": "test",
"_goid": "123456"
}]
Array 2: (only difference is it does not contain key _goid)
[{
"from": "4",
"to": "8",
"text": "test"
},{
"from": "3",
"to": "4",
"text": "test"
},{
"from": "9",
"to": "10",
"text": "test"
}]
I have below code which removes duplicates if arrays are exactly same but not working for my case.
function removeDuplicatesJson(myArr) {
var props = Object.keys(myArr[0])
return myArr.filter((item, index, self) =>
index === self.findIndex((t) => (
props.every(prop => {
return t[prop] === item[prop]
})
))
)
}

The below code will do as you ask: remove any items from arr2 which already present in arr1:
var arr1 = [{
"from": "1",
"to": "2",
"text": "test",
"_goid": "1234"
}, {
"from": "3",
"to": "4",
"text": "test",
"_goid": "12345"
}, {
"from": "5",
"to": "6",
"text": "test",
"_goid": "123456"
}]
var arr2 = [{
"from": "4",
"to": "8",
"text": "test"
},{
"from": "3",
"to": "4",
"text": "test"
},{
"from": "9",
"to": "10",
"text": "test"
}]
// create a flat array of values to test against:
var arr1_keys = arr1.map(item => item.from + item.to);
// ["12", "34", "56"]
// filter out the dups and create a dup-free array
arr2 = arr2.filter(item => !arr1_keys.includes(item.from + item.to))
console.log(arr2)

I'm not sure if it's what you want but it might help you.
1.
Faster but limited option (depends on the amount of data), only if you're sure about objects signature, the order of properties is important:
const removeDuplicates = (baseArray, toDedupe) => {
const baseArrayFormatted = baseArray.map(({ _goid, ...restProps }) => JSON.stringify(restProps));
return toDedupe
.map(item => JSON.stringify(item))
.filter((item) => !baseArrayFormatted.some(baseItem => baseItem === item))
.map(item => JSON.parse(item));
}
2.
Slower but more accurate:
const removeDuplicates = (baseArray, toDedupe) => {
const props = Object.keys(toDedupe[0]);
return toDedupe
.filter((item) => !baseArray.some(baseItem => props.every(prop => baseItem[prop] === item[prop])))
}
Keep in mind that there is no checking of objects signature, also there is a lof of validation missing (if it's really an objects, if it's a function etc, but I believe it's not the question here).

Related

How can i filter result if i have array in body

i have a payload
{
"category": "Mobile",
"price": {
"from": "10",
"to": "50"
},
"location": [
"Jakrta",
"Bandung",
"Surabaya"
],
"rating": [
"1",
"2",
"3"
]
}
i want to find all object which have rating 1 or 2 or 3 and also have any location
Basically i am creating a filter for an ecommerce store i which we will get multiple location and multiple ratings as well so we will return only those object which have matched property. i am attaching a screenshot of UI for better understanding.
i want to run this filter with multiple location and multiple checked checkbox
You can do create a filter dynamically:
const { category, price, location, rating } = req.body;
const filter = {};
if (category) filter.category = category;
if (price) filter.price = { $gte: parseInt(price.from, 10), $lte: parseInt(price.to, 10) };
if (location?.length) filter.location = { $in: location };
if (rating?.length) filter.rating = { $in: rating };
const data = await Collection.find(filter);
If you want to filter your objects, you should use filter() from your array :
const arr = [{
"category": "Mobile1",
"price": {
"from": "10",
"to": "50"
},
"location": [
"Jakrta",
"Bandung",
"Surabaya"
],
"rating": [
"1",
"2",
"3"
]
},
{
"category": "Mobile2",
"price": {
"from": "10",
"to": "50"
},
"location": [
"Jakrta",
"Bandung",
"Surabaya"
],
"rating": [
"2",
"3"
]
}];
const result = arr.filter(el => el.rating.includes("1") || el.rating.includes("2") || el.rating.includes("3"));
console.log(result);

Using JavaScript, how can I filter an array of objects using multiple criteria in a child object

I want to get all the customers who have returned product "2":
// Note that in production this array is much longer
const customers = [
{
"customerId": "1",
"products": [
{
"productId": "1",
"status": "purchased"
},
{
"productId": "2",
"status": "purchased"
}
]
},
{
"customerId": "2",
"products": [
{
"productId": "1",
"status": "purchased"
},
{
"productId": "2",
"status": "returned"
}
],
}
]
const returns = customers.filter((customer) =>
customer.products.some((product) => product.productId === "2" && product.status === "returned")
);
console.log(returns);
I thought my use of filter would work - but I am guessing some() doesn't work with multiple criteria? Or am I doing something else wrong? Or is there a better way?
Your condition product.productId === "2" && product.status === "returned" does match only one object
if the productId is '2' AND the status is 'returned' matches the last object which is returned.
if you only want the products that have the Id of '2' then it should be product.productId === "2"
Hope this makes sense
Try using some function for the products.
const customers = [{
"customerId": "1",
"products": [{
"productId": "1",
"status": "purchased"
},
{
"productId": "2",
"status": "purchased"
}
]
},
{
"customerId": "2",
"products": [{
"productId": "1",
"status": "purchased"
},
{
"productId": "2",
"status": "returned"
}
],
}
]
const returns = customers.filter((customer) =>
customer.products.some((product) => product.productId === "2" && product.status === "returned"))
console.log(returns);

How to filter from an array of objects one value and reduce it to one result per value without duplicates [duplicate]

This question already has answers here:
Get all unique values in a JavaScript array (remove duplicates)
(91 answers)
Remove duplicates form an array
(17 answers)
Closed 1 year ago.
I'm trying to build a method in javascript which can filter from an array of object one only value and have a result that value only once without having duplicates
sharing a snippet and more details what I want to achieve
const arr = [{
"id": "1",
"value": "something"
}, {
"id": "1",
"value": "something"
}, {
"id": "2",
"value": "something"
}, {
"id": "2",
"value": "something"
},
{
"id": "3",
"value": "something"
},
{
"id": "3",
"value": "something"
},
{
"id": "3",
"value": "something"
}];
const result = arr.filter(res => res.id).map(ele => ele.id);
console.log(result);
As you see result is an array like this
["1", "1", "2", "2", "3", "3", "3"]
What I would like to get is as follow
["1", "2", "3"]
The idea is to extract only one ID per result.
You can use a Set as follows:
const arr = [
{ "id": "1", "value": "something" },
{ "id": "1", "value": "something" },
{ "id": "2", "value": "something" },
{ "id": "2", "value": "something" },
{ "id": "3", "value": "something" },
{ "id": "3", "value": "something" },
{ "id": "3", "value": "something" }
];
const result = [...arr.reduce((set,{id}) => {
set.add(id);
return set;
}, new Set)];
console.log(result);

Most performant way to sort a deeply nested array of objects by another deeply nested array of objects

As an example - I've included a one element array that contains an object that has a Children key, which is an array of objects and each object also has its' own Children key that contains another array.
[
{
"Id": "1",
"Children": [
{
"Id": "2",
"Children": [
{
"Id": "10",
"DisplayName": "3-4",
},
{
"Id": "1000",
"DisplayName": "5-6",
},
{
"Id": "100",
"DisplayName": "1-2",
},
]
}
]
}
]
There is a second array of objects that I would like to compare the first array of objects to, with the intention of making sure that the first array is in the same order as the second array of objects, and if it is not - then sort until it is.
Here is the second array:
[
{
"Id": "1",
"Children": [
{
"Id": "2",
"Children": [
{
"Id": "100",
"DisplayName": "1-2",
},
{
"Id": "10",
"DisplayName": "3-4",
},
{
"Id": "1000",
"DisplayName": "5-6",
},
]
}
]
}
]
The data that this will run on can be up in the tens of thousands - so performance is paramount.
What I'm currently attempting is using a utility method to convert each element of the second array into a keyed object of objects e.g.
{
1: {
"Id": "1",
"Children": [
{
"Id": "2",
"Children": [
{
"Id": "4",
"DisplayName": "3-4",
},
{
"Id": "3",
"DisplayName": "1-2",
},
]
}
]
}
}
This allows fast look up from the top level. I'm wondering if I should continue doing this all the way down or if there is an idiomatic way to accomplish this. I considered recursion as well.
The order of the already sorted array is not based on Id - it is arbitrary. So the order needs to be preserved regardless.
Assuming same depth and all Id's exist in each level of each object use a recursive function that matches using Array#findIndex() in sort callback
function sortChildren(main, other) {
other.forEach((o, i) => {
if (o.children) {
const mChilds = main[i].children, oChilds = o.children;
oChilds.sort((a, b) => {
return mChilds.findIndex(main => main.Id === a.Id) - mChilds.findIndex(main => main.Id === b.Id)
});
// call function again on this level passing appropriate children arrays in
sortChildren(mChilds, oChilds)
}
})
}
sortChildren(data, newData);
console.log(JSON.stringify(newData, null, ' '))
<script>
var data = [{
"Id": "1",
"Children": [{
"Id": "2",
"Children": [{
"Id": "3",
"DisplayName": "1-2",
},
{
"Id": "4",
"DisplayName": "3-4",
},
]
}]
}]
var newData = [{
"Id": "1",
"Children": [{
"Id": "2",
"Children": [{
"Id": "4",
"DisplayName": "3-4",
},
{
"Id": "3",
"DisplayName": "1-2",
},
]
}]
}]
</script>

Remove duplicate objects, but push property to array on remaining object

I have an array of objects like so:
[
{
"id": "1",
"location": "US"
},
{
"id": "7",
"location": "US"
},
{
"id": "1",
"location": "France"
},
{
"id": "1",
"location": "China"
}
]
I would like to end up with a resulting array that looks like this:
[
{
"id": "1",
"locations": ["US", "France", "China"]
},
{
"id": "7",
"locations": ["US"]
}
]
Is there a solid way to accomplish this using underscore?
I'm contemplating looping through the array and for each id looping through the rest of the array and pushing location values to a locations array on that first object (by id), then at the end removing all duplicate objects (by id) which do not contain a locations property.
This is different from existing questions on SO that simply ask about removing duplicates. I am aiming to remove duplicates while also holding on to certain property values from these duplicates in an array on the 'surviving' object.
Solution in plain Javascript
var data = [{ "id": "9" }, { "id": "1", "location": "US" }, { "id": "7", "location": "US" }, { "id": "1", "location": "France" }, { "id": "1", "location": "China" }],
result = [];
data.forEach(function (a) {
a.location && !result.some(function (b) {
if (a.id === b.id) {
b.locations.push(a.location);
return true;
}
}) && result.push({ id: a.id, locations: [a.location] });
});
document.write('<pre>' + JSON.stringify(result, 0, 4) + '</pre>');
You can use reduce function to transform your array.
var data = [
{ "id": "1", "location": "US" },
{ "id": "7", "location": "US" },
{ "id": "1", "location": "France" },
{ "id": "1", "location": "China" }
];
var result = data.reduce(function (prev, item) {
var newItem = prev.find(function(i) {
return i.id === item.id;
});
if (!newItem) {
prev.push({id: item.id, locations: [item.location]});
} else {
newItem.locations.push(item.location);
}
return prev;
}, []);
And a version using underscore:
var result = _.chain(data)
.groupBy('id')
.map(function(group, id){
return {
id: id,
locations: _.pluck(group, 'location')
}
})
.value();

Categories

Resources