Removing Duplicate object from array in jquery code not working - javascript

This is my array in jquery , which contains duplicate objects/elements :
[{
"name": "hello",
"label": "world"
}, {
"name": "abc",
"label": "xyz"
}, {
"name": "hello",
"label": "world"
}]
I am using the following piece of code to remove duplicate elements but it not working the duplicate elements are not removed.
var result = [];
$.each(subservices, function (i, e) {
if ($.inArray(e, result) == -1)
result.push(e);
});
alert(JSON.stringify(result));

Function $.inArray works fine for simple types (e.g. number or string), but for complex types it does not produce the correct result, because it tries to match by reference. Instead of using inArray in your loop you can search the array using function grep:
var subservices = [{
"name": "hello",
"label": "world"
}, {
"name": "abc",
"label": "xyz"
}, {
"name": "hello",
"label": "world"
}
];
var result = [];
$.each(subservices, function (i, e) {
var matchingItems = $.grep(result, function (item) {
return item.name === e.name && item.label === e.label;
});
if (matchingItems.length === 0){
result.push(e);
}
});
//displays result [{"name":"hello","label":"world"},{"name":"abc","label":"xyz"}]
alert(JSON.stringify(result));
Here is a working jsFiddle

You need to filter array by unique name/value. Here is some pure JS solution:
var data = [{
"name": "hello",
"label": "world"
}, {
"name": "abc",
"label": "xyz"
}, {
"name": "hello",
"label": "world"
}];
var result = data.filter(function(el, i, x) {
return x.some(function(obj, j) {
return obj.name === el.name && (x = j);
}) && i == x;
});
alert(JSON.stringify(result, null, 4));

This is because these two objects are distinct, even though all the attributes inside are the same. You can see this from:
console.log(result[0] === result[2]);
which results in false.
Instead, you need to iterate through your array based on a unique identifier, such as name & label as such:
for(var i = 0, i < results.length; i++) {
if (result[i].name === ... && result[i].label === ...) {
index = i;
break;
}
}
to check if your item is unique.

Related

How to update object except current index in Angular 8

this.StaticData = {
"values": [
{
"value": "test",
"label": "test"
},
{
"value": "aa",
"label": "bb"
},
{
"value": "cc",
"label": "dd"
}
]
};
I have above object of data. I wanted to return all object except currentIndex.
For example -
suppose in above objects, if I am going to edit 0th index values,
and I have updated "value": "rest", instead of "value": "test" and
"label": "test" need to keep as it is. So in that case,
it will allow to update the values.
{
"value": "rest",
"label": "test"
},
But if I tried to enter "label": "bb" and "label": "dd",
so it will return false, because these values are already available in above objects.
isLabelExist() {
const formData = this.editStaticParametersForm.value;
const currentIndex: number = this.StaticData.values.indexOf(this.selectedRowValue);
if (formData.label_value && this.StaticData) {
var isPresent = this.StaticData.values.some(function (el) {
return el.label === formData.label_value
});
if (isPresent) {
return false;
}
}
return true;
}
using find (or some) you can check the "index" (add a second argument to the function find), so,
var isPresent = this.StaticData.values.some(function (el,i) {
return el.label === formData.label_value && i!=currentIndex
});
Really in .ts we use arrow flat and use const or let, not var
const isPresent = this.StaticData.values.some((el,i)=> {
return el.label === formData.label_value && i!=currentIndex
});
Or
const isPresent = this.StaticData.values.some(
(el,i)=> el.label === formData.label_value && i!=currentIndex);

Javascript Push to Array if Condition is Met

I have the following Foods Object:
var Foods = {
"Fruits": [{
"id": "1",
"Name": "Granny Smith",
"Category": "1"
}, {
"id": "2",
"Name": "Raspberries",
"Category": "1"
}
],
"Potatoes": [{
"id": "3",
"Name": "Maris Piper",
"Category": "2"
}, {
"id": "4",
"Name": "Charlotte",
"Category": "2"
}]
}
What I would like to do is only push the produce that matches an id passed by a link.
Get Foods
This is what I have tried so far:
function getCat (id){
result = [];
for(let item in Foods) {
if(Foods[item].id == id) {
data[item].foreach(v=>result.push("<div class='box'><h2>" +
data[key].Name + "<br></div>"));
}
}
}
display();
function display() {
alert(result);
}
So if a user hits the link (which has an id of 2), the result array should contain "Charlotte" and "Maris Piper" but I am just drawing a blank.
Any help appreciated.
Cheers
Youre quite close, however theres a slight problem:
for(let item in Foods) {
console.log(Foods[item]);
/*
[{
"id": "1",
"Name": "Granny Smith",
"Category": "1"
}, {
"id": "2",
"Name": "Raspberries",
"Category": "1"
}
]
*/
So youre iterating over the categories, which are arrays.
Foods[item].id
is undefined as its an array and not a product. So we need to iterate the array to, e.g.
var result=[];
Object.values(Foods).forEach(function(category){
category.forEach(function(product){
if(product.id===id){
result.push(product);
}
});
});
Run
But if youre doing this quite often, it might be easier to create one product array once:
var products = Object.values(Foods).reduce((arr,cat)=>arr.concat(cat),[]);
So you can simply filter this whenever someone clicks a button:
var result = products.filter(product=>product.id === id);
Run
You're somewhat on the right track, but what's data? Why are you not doing anything with result? And you should be looking at the Category property rather than ID.
This'll work:
function getCat(id) {
let result = [];
for (let item in Foods) {
if (Foods.hasOwnProperty(item)) {
Foods[item].forEach((food) => {
if (food.Category == id) {
result.push(food);
}
});
}
}
console.log(result);
}
First of all result array should be at global scope so that you can access it in another function, And in object you are having categories then each category has some data in array so after iterating over object, you need to iterate the items from array as well to get the value. Check the below code.
var result = [];
function getCat(id){
for(let item in Foods) {
var foodItem = Foods[item];
for(let i=0; i<foodItem.length; i++){
if(foodItem[i].id == id) {
result.push("<div class='box'><h2>" + foodItem[i].Name + "<br></div>"));
}
}
}
}
function display() {
alert(result);
}
display();
Iterator is wrong. You should do it like this:
function getCat(id){
result = [];
for(let item in Foods) {
Foods[item].forEach(function(each){
if(each.id == id) { // you cmpare to the wrong target
// do something
}
});
}
}

Compare two arrays and update with the new values by keeping the existing objects using javascript

Below are my two arrays .I want to compare them and the resultant array should contain the updated values.Id's are common..
The arrays spans to n levels ie., there is no fixed levels..
The first array ie., the array before updation..
var parentArray1=[
{
"id": 1,
"name": "test",
"context": [
{
"id": 1.1,
"name": "test 1.1"
}
]
},
{
"id": 2,
"name": "test"
},
{
"id": 3,
"name": "test",
"context": [
{
"id": 3.1,
"name": "test 3.1"
}
]
},
{
"id": 4,
"name": "test"
}
]
The operations that i performed are
1.Adding a new Item
2.Updating an existing item
As a result of these two operations the changed values I will be getting in a different array..
ie.,
var changedArray=
[
{
"id": 1,
"name": "test1",
"context": [
{
"id": 1.1,
"name": "Changed test 1.1"
}
]
},
{
"id": 5,
"name": "test5"
}
]
Now I have written a generic function that loops through the parentArray1 and using the unique propertiesI need to either add a new item,if the item is there in the changedArray or update an existing item at any level
The resultant array should be ..
[
{
"id": 1,
"name": "test",
"context": [
{
"id": 1.1,
"name": "Changed test 1.1"
}
]
},
{
"id": 2,
"name": "test"
},
{
"id": 3,
"name": "test",
"context": [
{
"id": 3.1,
"name": "test 3.1"
}
]
},
{
"id": 4,
"name": "test"
},
{
"id": 5,
"name": "test5"
}
]
Generic function:
compareArray(parentArray1, changedArray, ["id"]);
function compareArray(array1, array2, propertyArray) {
var newItem = new Array();
array2.map(function(a1Item) {
array1.map(function(a2Item) {
/ If array loop again /
if (a2Item.constructor === Array) {
compareArray(a2Item, a1Item)
} else {
/ loop the property name to validate /
propertyArray.map(function(property) {
if (a2Item[property]) {
if (a2Item[property] === a1Item[property]) {
a2Item = a1Item
} else {
var isAvailable = _.find(newItem, function(item) {
return item[property] === a1Item[property]
})
if (!isAvailable) {
newItem.push(a1Item);
}
}
}
})
}
});
});
/ Insert the new item into the source array /
newItem.map(function(item) {
array1.push(item);
});
console.log("After Compare : " + array1);
}
I suggest to use a temporary object for the reference to the id and update if exist or push if not exist.
var parentArray1 = [{ "id": 1, "name": "test", "context": [{ "id": 1.1, "name": "test 1.1" }] }, { "id": 2, "name": "test" }, { "id": 3, "name": "test", "context": [{ "id": 3.1, "name": "test 3.1" }] }, { "id": 4, "name": "test" }],
changedArray = [{ "id": 1, "name": "test1", "context": [{ "id": 1.1, "name": "Changed test 1.1" }] }, { "id": 5, "name": "test5" }];
function insert(array, data) {
function iter(array) {
array.forEach(function (a) {
if (!('id' in a)) {
return;
}
if (o[a.id] !== a) {
o[a.id] = a;
}
Object.keys(a).forEach(function (k) {
Array.isArray(a[k]) && iter(a[k]);
});
});
}
var o = {};
iter(array);
data.forEach(function (a) {
if (o[a.id]) {
Object.keys(a).forEach(function (k) {
o[a.id][k] = a[k];
});
return;
}
array.push(a);
});
}
insert(parentArray1, changedArray);
document.write('<pre>' + JSON.stringify(parentArray1, 0, 4) + '</pre>');
This is what I came up with:
function sameKeys(o1, o2, keys) {
for (var i = 0; i < keys.length; i++) {
var key = keys[i];
if (!o1.hasOwnProperty(key) || !o2.hasOwnProperty(key))
throw 'compared objects do not have the key ' + key;
if (o1[key] !== o2[key])
return false;
}
return true;
}
function isNothing(o) {
return typeof(o) === 'undefined' || o === null;
}
// this does not work if objects have functions as properties
function clone(o) {
if (isNothing(o))
return o;
return JSON.parse(JSON.stringify(o));
}
function extend(o1, o2, keys) {
if (isNothing(o2))
return;
if (isNothing(o1))
throw ('first parameter cannot be empty');
if (typeof(o1) != 'object' || typeof(o2) != 'object')
throw ('extend only works on objects');
Object.keys(o2).forEach(function (key) {
var newVal = o2[key];
if (o1.hasOwnProperty(key)) {
if (isNothing(newVal)) {
delete o1[key];
} else
if (Array.isArray(newVal)) {
compareArray(o1[key], newVal, keys);
} else {
switch (typeof(newVal)) {
case 'object':
extend(o1[key], newVal, keys);
break;
case 'boolean':
case 'number':
case 'string':
o1[key] = newVal;
break;
default:
throw 'not supported property type: ' + typeof(newVal);
}
}
} else {
o1[key] = clone(newVal);
}
});
}
function removeFromArray(arr, ids, keyArray) {
var indexes = [];
var it1s = arr.forEach(function (it, idx) {
if (sameKeys(ids, it, keyArray)) {
indexes.push(idx);
} else {
Object.keys(it).forEach(function (key) {
var newVal = it[key];
if (Array.isArray(newVal)) {
removeFromArray(it[key], ids, keyArray);
}
});
}
});
if (indexes.length) {
if (indexes.length > 1)
throw 'found multiple possible objects for the same key combination'
arr.splice(indexes[0], 1);
}
}
function compareArray(a1, a2, keyArray) {
a2.forEach(function (it2) {
var it1s = a1.filter(function (it) {
return sameKeys(it2, it, keyArray);
});
var it1;
if (!it1s.length) {
it1 = clone(it2);
a1.push(it1);
} else {
if (it1s.length > 1)
throw 'found multiple possible objects for the same key combination'
it1 = it1s[0];
extend(it1, it2, keyArray);
}
if (it2.removedIds) {
it2.removedIds.forEach(function (ids) {
removeFromArray(a1, ids, keyArray);
});
}
});
}
Use it with compareArray(parentArray1,changedArray,['id']);
Note that it would not work with objects that contain functions. Also, if the arrays would be large, perhaps a better solution is to sort both arrays by key, then always look from the last found object up. That's all I got for now.
Updated it with some concepts from Nina and some clearing of the code.
As I understood it, you only want to add properties. So extend({a: {b: 2}},{a:{c:3}}) will result in {a: {b:2,c:3}}. If this is not what you wanted, let me know.
I also added functionality for removing ids. If any of the objects in the array contains a removedIds array of the form [{id: 4},{id: 5}] then the items with those ids will be removed from the original array.
Slight modification on code, to satisfy your conditions. Try it!
function compareArray(originalArray, destinationArray, propertyArray) {
var newItem = new Array(), processedItem = new Array();
for (var i = 0; i < originalArray.length; i++) {
var sourceElement = originalArray[i];
for (var j = 0; j < destinationArray.length; j++) {
var destinationElement = destinationArray[j];
var isUpdated = false;
if (sourceElement.constructor === Array) {
compareArray(sourceElement, destinationElement, propertyArray);
} else {
/* loop the property name to validate */
propertyArray.map(function(property) {
if (sourceElement[property]) {
if (sourceElement[property] === destinationElement[property]) {
originalArray[i] = _.clone(destinationElement);
isUpdated = true;
return;
} else {
var isAvailable = _.find(newItem, function(item) {
return item[property] === destinationElement[property];
});
if (!isAvailable) {
var isAlreadyProcessed = _.find(processedItem, function(item) {
return item[property] === destinationElement[property];
});
if(!isAlreadyProcessed){
newItem.push(destinationElement);
}
}
}
}
});
}
if (isUpdated === true) {
break;
}
}
processedItem.push(sourceElement);
}
newItem.map(function(item) {
originalArray.push(item);
});
return originalArray;
}

How to display a specifc path from JSON tree depending on the leaves values?

I have a question regarding displaying a path from a tree depending on the value of the leaf, for example I have the following JSON :
{
"children":
[
{
"children":
[
{
"name": "Predict Conversion"
}
],
"name": "Browser ID in {1}"
},
{
"children":
[
{
"name": "Predict Click"
}
],
"name": "Browser ID not in {1}"
}
],
"name": "Device Type ID in {1,3,4}"
}
I want to display only the full path leading to the leaf with value = "Predict Conversion"
You can use recursion to loop over object. Use Array.isArray to test if value is of type Array and typeof(obj)==="object" for object.
Note: typeof(obj) will return object for both Array and for Object
function searchInObj(obj, value, result) {
// check for array and call for every item
if (Array.isArray(obj)) {
// primary flag for array.
var r = false;
obj.forEach(function(item, index) {
// temporary flag for every iteration.
var _r = searchInObj(item, value, result);
if (_r) result.push(index)
// if one of element returned true, array should return true.
r = _r || r;
});
return r;
}
// If Object, loop over properties
else if (typeof(obj) === "object") {
for (var k in obj) {
// If object, check if property is Object/Array and call self.
if (typeof(obj[k]) === "object") {
var r = searchInObj(obj[k], value, result);
if (r) result.push(k);
return r;
}
// If property is not Array/Object, match value
else if (obj[k] === value) {
result.push(k);
return true;
}
// If no match, return false
else {
return false;
}
}
}
}
var data = {
"children": [{
"children": [{
"name": "Predict Conversion"
}],
"name": "Browser ID in {1}"
}, {
"children": [{
"name": "Predict Click"
}],
"name": "Browser ID not in {1}"
}],
"name": "Device Type ID in {1,3,4}"
}
var result = []
searchInObj(data, "Predict Conversion", result);
document.write("<pre>" + JSON.stringify(result.reverse(), 0, 4) + "</pre>");
Note: For small JSON, this will work but if your JSON is very long, this can be very expensive operation.
You can use recursion for it.
Quick example
var tree = {
"children": [{
"children": [{
"name": "Predict Conversion"
}],
"name": "Browser ID in {1}"
}, {
"children": [{
"name": "Predict Click"
}],
"name": "Browser ID not in {1}"
}],
"name": "Device Type ID in {1,3,4}"
};
console.debug(tree);
function getPath(node, value){
if(typeof node.children !== "undefined" && node.children !== null){
for(var index in node.children){
var name = getPath(node.children[index], value);
if(name) {
return node.name+"."+name;
}
}
} else {
if(node.name === value){
return node.name;
}
return false;
}
}
console.log(getPath(tree, "Predict Conversion"))
Working example in this fiddle

How to iterate through nested objects in a generic way

I am trying to fetch the value of the nested objects without using it's key. Like for example if I have a object like
var a = {"key" : "100"}
I don't want to use a.key, to get the result, though i have nested objects, it is becoming difficult for me to fetch the value this is what I have tried:
var Obj = [{"ghi":{"content":"abc"}},{"def":{"imgURL":"test.png"}},{"abc":{"key":"001"}},{"ghi":{"content":"abc"}},{"def":{"imgURL":"test.png"}},{"abc":{"key":"001"}}]
for(var key in Obj){
abc = Obj[key]
for(var j in abc){
def = abc[key]
}
}
So i need the values of all the objects, without using the key directly.
Maybe this helps
function getValues(array, key) {
var result = [];
array.forEach(function (a) {
a[key] && result.push(a[key]);
});
return result;
}
var array = [{ "ghi": { "content": "abc" } }, { "def": { "imgURL": "test.png" } }, { "abc": { "key": "001" } }, { "ghi": { "content": "abc" } }, { "def": { "imgURL": "test.png" } }, { "abc": { "key": "001" } }];
document.write('<pre>' + JSON.stringify(getValues(array, 'ghi'), 0, 4) + '</pre>');

Categories

Resources