Remove duplicate nested objects in array using Lodash - javascript

I have an array which looks like below
var nestedArray = [
{ id: 1, filter: { type: "nestedArray", name: "5" } },
{ id: 2, filter: { type: "nestedArray1", name: "6" } },
{ id: 3, filter: { type: "nestedArray", name: "5" } }
];
Now here I have a duplicate object, I just want to identify the duplicates using a Lodash method. Any help is appreciated.
Have already tried map, filter options but need something in Lodash method.

You can use reject with a Property.
var myArray = [
{
"id": 1,
"filter": {
"type": "nestedArray",
"name": "5"
}
},
{
"id": 2,
"filter": {
"type": "nestedArray1",
"name": "6"
}
},
{
"id": 3,
"filter": {
"type": "nestedArray",
"name": "5"
}
}
];
var result = _.reject(myArray, ['filter.name', '5']);
console.log(result);
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.11/lodash.min.js"></script>

So u want to reject duplicate ones by value in filter key?
_.uniqWith(nestedArray, (x, y) => _.isEqual(x.filter, y.filter), myArray)
If you have the flexibility to use Ramda instead, it could be more concise like because of every functions are auto-curried
const rejectDuplicateFilter = R.uniqWith(R.eqProps('filter'));
rejectDuplicateFilter(myArray)

Related

Find Efficient way of Filtering of two arrays (ArrayA & ArrayB) to make a third ArrayC

Can anyone help me come up with a faster way of filtering the following ArrayC (see below what it should be equal to. ArrayA is self explanatory. ArrayB has inside of each element an object 'data' that has a property "target" as a string "\_teacher" that I can filter out based on a global variable "userType" to distinguish students vs teachers. "filter_klas_1371" ==> filter_{GroepType }_{GroepID} from Array A. This property changes. breaking the string and filtering has giving me a headache, so if there are faster more efficient ways to filter this please let me know.
let userType='teacher'
arrayA: [{
"ID": 1,
"GroepID": 1371,
"GroepType": "klas"
},
{
"ID": 2,
"GroepID": 1372,
"GroepType": "klas"
},
{
"ID": 3,
"GroepID": 1375,
"GroepType": "graad"
}
]
araayB: [{
"id": "bd5b12ba-b433-4610-801e-e0b78fa72ff8",
data: {
"target": "_teacher",
"filter_klas_1371": "true"
}
},
{
"id": "gggfdgdba-gfgg-fff-ggg-7657657676",
data:{
"target": "_teacher_student",
"filter_klas_1375": "true"
}
} {
"id": "uuuykllk-b433-4610-801e-8888888776",
data: {
"target": "_student",
"filter_klas_1372": "true"
}
} {
"id": "jkjkjkklk-jkhjk-66567-666-99977",
data: {
"target": "_teacher_student",
"filter_klas_1372": "true"
}
},
{
"id": "zzzzzzz-b433-4610-801e-8888888776",
data: {
"target": "_teacher",
"filter_klas_1372": "true"
}
},
]
//should get
arrayC:[{
"id": "bd5b12ba-b433-4610-801e-e0b78fa72ff8",
data: {
"target": "_teacher",
"filter_klas_1371": "true"
}
},
{
data: {
"id": "jkjkjkklk-jkhjk-66567-666-99977",
"target": "_teacher_student",
"filter_klas_1372": "true"
}
},
{
"id": "zzzzzzz-b433-4610-801e-8888888776",
data: {
"target": "_teacher",
"filter_klas_1372": "true"
}
}
]
If I understand correct you would like to filter arrayB based on the userType and the values in arrayA. I suggest making an array of all the possible filter_{groepType}_{groepId} with array map:
const filterKeys = arrayA.map(group => `filter_${group.GroepType}_${group.GroepID}`);
Then you can check if one of those values is set as a key in the keys of arrayB, using an intersection of array with a couple of filters. You can do this in more ways:
arrayC = arrayB.filter(item => {
const intersect = Object.keys(item.data).filter(key => filterKeys.includes(key));
return intersect.length > 0; // you can additionally add the filter for target here
})

how to make nested array objects in javascript in a key value pair format

array data=[
{
"id":1,
"name":"john",
"income":22000,
"expenses":15000
},
{
"id":2,
"name":"kiran",
"income":27000,
"expenses":13000
},
{
"id":1,
"name":"john",
"income":35000,
"expenses":24000
}
]
i want to make a new array set in following format which is in a key value pair. ie result set.
can you please explain the best method. ? how to achive using foreach.?
tried using foreach method by looping each element. but cant get the desired output format
var result= [ {
"name": "john",
"series": [
{
"name": "income",
"value": 22000
},
{
"name": "expenses",
"value": 15000
},
]
},
{
"name": "kiran",
"series": [
{
"name": "income",
"value": 27000
},
{
"name": "expenses",
"value": 13000
},
]
}]
// Your array
const result = [
{
name: "john",
series: [
{
name: "income",
value: 22000,
},
{
name: "expenses",
value: 15000,
},
],
},
{
name: "kiran",
series: [
{
name: "income",
value: 27000,
},
{
name: "expenses",
value: 13000,
},
],
},
];
// What is .map function?
// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/map
// Output
// map return a new function.
// it's a loop method but more equipped
result.map((item, index) => {
const seriesKeyValues = {};
// forEach is too, it's a loop method.
// but not have a return value,
// just loops and give you item on each loop
item.series.forEach(serie => {
//seriesKeyValues is a object.
// different between seriesKeyValues.serie.name
// it's a bracket notation
// look this documentation
// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Object_initializer#computed_property_names
seriesKeyValues[serie.name] = serie.value;
});
// return new Object
// ... is 'spread syntax' basically combine objects
// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Object_initializer#spread_properties
// spread syntax is a new way.
// old way is https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/assign
return {
id: index,
name: item.name,
...seriesKeyValues,
};
});
I hope it will help :). if you don't understand any lines of code, i can explain

Modify object while passing through react component

I am trying to pass through an object that looks like this
{
"nodes": [
{
"attributes": null
},
{
"attributes": {
"nodes": [
{
"attributeId": 1,
"name": "pa_color",
"options": [
"gray"
]
},
{
"attributeId": 2,
"name": "pa_size",
"options": [
"large"
]
}
]
}
},
{
"attributes": {
"nodes": [
{
"attributeId": 1,
"name": "pa_color",
"options": [
"blue"
]
}
]
}
}
]
}
into a react component that renders all the different options under all the unique names. However, the way the data is structured means that I receive duplicates of names and options.
I am trying to convert the object into this object
{
"node": {
"attributeId": 1,
"name": "pa_color",
"values": [
{
"name": "gray"
},
{
"name": "blue"
}
]
},
"node": {
"attributeId": 2,
"name": "pa_size",
"values": [
{
"name": "large"
}
]
},
}
Current code looks like this
export interface Category_products_edges_node_attributes_edges_node {
__typename: "ProductAttribute";
/**
* Attribute Global ID
*/
name: string;
/**
* Attribute options
*/
options: (string | null)[] | null;
/**
* Attribute ID
*/
attributeId: number;
}
export interface ProductFiltersProps {
attributes: Category_products_edges_node_attributes_edges_node[]
}
export const ProductFilters: React.FC<ProductFiltersProps> = ({
attributes,
}) => (
<div className="product-filters">
<div className="container">
<div className="product-filters__grid">
{attributes.map(attribute => (
I have tried to do
{groupBy(attributes, 'attributeId').map(attribute => (
With the Lodash library, but receive the error
This expression is not callable. Type
'Category_products_edges_node_attributes_edges_node[]' has no call
signatures.
What is the best way to do this?
Thank you
lodash groupBy returns an Object not an Array therefore the javascript .map call will not work on it. Also groupBy is used to group items with similar property under one key inside an object, it isn't used to remove duplicates.
To remove duplicates use the lodash uniqBy method. This method can be called on an array and returns an array without duplicates.
Update:
To view in more detail how you can remove duplicates based on more than one property of object please see great answer
Also the output object you are trying to achieve has similar keys, I think that is not what you want, a Javascript object should not have duplicate keys. So my output gives keys as node0, node1 instead of node
You can achieve this as follows:
const nodes = {
nodes: [
{ attributes: null },
{
attributes: {
nodes: [
{ attributeId: 1, name: "pa_color", options: ["gray"] },
{ attributeId: 2, name: "pa_size", options: ["large"] }
]
}
},
{
attributes: {
nodes: [{ attributeId: 1, name: "pa_color", options: ["blue"] }]
}
}
]
}
const attributes = []
nodes.nodes.forEach(e => {
if (e.attributes && Array.isArray(e.attributes.nodes)) {
attributes.push(...e.attributes.nodes)
}
})
const uniqueAttributes = _.uniqBy(attributes, (obj) => [obj.attributeId, obj.name, obj.options].join())
const uniqueNodes = uniqueAttributes.map((e, i) => ({ ["node" + i]: e }))
console.log("Unique Nodes: ", uniqueNodes)
<script src="https://cdn.jsdelivr.net/npm/lodash#4.17.10/lodash.min.js"></script>

Add json Elements and values to Multiple json objects

I want combine a JSON object to an ARRAY.
I would like retrieve data from keys finded on var product, and combine score finded to a new variable ( combined results )
combinedresults is what I need. I absolutely don't know how to do this
var product = {
"presentation": 3,
"imgmax": http://test.com/img.jpg,
"puissance": 5,
"efficacite": 4,
"description": "This product is awesome but i need to combine JSON results"
}
var array = [
{
"caracname": "presentation",
"name": "Présentation"
},
{
"caracname": "efficacite",
"name": "Efficacité"
},
{
"caracnam": "puissance",
"name": "Puissance"
}
]
var combinedresults = [
{
"caracname": "presentation",
"name": "Présentation",
"score": 3
},
{
"caracname": "efficacite",
"name": "Efficacité",
"score": 4
},
{
"caracnam": "puissance",
"name": "Puissance",
"score": 5
}
]
Iterate through each item of the array, if the product object contains a key that matches the current items caracname, add it's value as a score.
See below:
var product = {
"presentation": 3,
"imgmax": "http://test.com/img.jpg",
"puissance": 5,
"efficacite": 4,
"description": "This product is awesome but i need to combine JSON results"
}
var array = [
{
"caracname": "presentation",
"name": "Présentation"
},
{
"caracname": "efficacite",
"name": "Efficacité"
},
{
"caracname": "puissance",
"name": "Puissance"
}
]
array.forEach(function(item) {
if (product[item.caracname]) {
item.score = product[item.caracname];
}
});
console.log(array);
Simply map over your current array, extending every object with the score attribute.
array.map(obj => ({...obj, score: product[obj.caracname]}));
If you are not familiar, consider having a look at the spread operator;

How can be optimized merging of two arrays of objects?

I would like to optimize my code for CPU and memory consumption. In my function I need to merge two arrays of object into one array. Like UNION, all the ids of the objects in the array have to be unique. I do not want to use third party libraries like Underscore.
This is my function:
var presentation_slides = [
{
"id": "2",
"type": "results"
},
{
"id": "1",
"type": "slide"
},
{
"id": "4",
"type": "questions"
}]
for(var i = 0; i < new_length; i++) {
var my_slide = presentation_slides.filter(function (obj) { return obj.id == i })[0]
if(!my_slide) {
presentation_slides.push({"id": i, "type": "slide"});
}
}
OUTPUT:
var presentation_slides = [
{
"id": "2",
"type": "results"
},
{
"id": "1",
"type": "slide"
},
{
"id": "4",
"type": "questions"
},
{
"id": 0,
"type": "slide"
},
{
"id": 3,
"type": "slide"
}]
Thank you!
EDIT:
Some tests for comparison: http://jsperf.com/how-can-be-optimized-merging-of-two-arrays-of-objects
you can use some instead of filter, i have added a code snipet to your jsperf, which is faster...
check this: .....jsperf.....
for (var i = 0; i < new_length; i++) {
if (!presentation_slides.some(function(obj) { return obj.id == i}))
presentation_slides.push({ "id": i, "type": "slide" });
}
If you just want to merge two arrays, then you can use Array.concat():
var array1 = [
{ id: 1, type: "orange" },
{id: 3, type: "apple" },
{ id: 4, type: "banana" } ],
array2 = [
{ id: 8, type: "strawberry" },
{ id: 9, type: "raspberry" }
];
var array3 = array1.concat(array2);
array3 will contain all the elements from array1 and array2.
This will not check to see if the IDs are unique though.
also, reverse loops are a little faster:
var i = new_length;
while (i--) {
if (!presentation_slides.some(function(obj) { return obj.id == i })) {
presentation_slides.push({ "id": i, "type": "slide" });
}
}
check this ...jspref...

Categories

Resources