Check if child object exists, if so, add to object [duplicate] - javascript

This question already has answers here:
How to determine equality for two JavaScript objects?
(82 answers)
Closed 7 years ago.
I'm trying to add one object to another object.
Let's say I have two objects. selectedItemObj and selectedItemQueue. I'd like to add the selectedItemObj to selecteditemQueue but ONLY if that selectedItemObject does not match any of the objects in selectedItemQueue
Let's say I have this object here:
var selecteditemObj = [
{
"market_hash_name":"Chroma 2 Case Key 1",
"assetid":"92700754417_143965972",
"amount":1,
"image":"https://steamcommunity-a.akamaihd.net/economy/image/-9a81dlWLwJ2UUGcVs_nsVtzdOEdtWwKGZZLQHTxDZ7I56KU0Zwwo4NUX4oFJZEHLbXX7gNTPcUxuxpJSXPbQv2S1MDeXkh6LBBOie3rKFRh16PKd2pDvozixtSOwaP2ar7SlzIA6sEo2rHCpdyhjAGxr0A6MHezetG0RZXdTA/"
}];
var selectedItemQueue = [
{
"market_hash_name":"Chroma 2 Case Key 2",
"assetid":"92700754667_143865972",
"amount":1,
"image":"https://steamcommunity-a.akamaihd.net/economy/image/-9a81dlWLwJ2UUGcVs_nsVtzdOEdtWwKGZZLQHTxDZ7I56KU0Zwwo4NUX4oFJZEHLbXX7gNTPcUxuxpJSXPbQv2S1MDeXkh6LBBOie3rKFRh16PKd2pDvozixtSOwaP2ar7SlzIA6sEo2rHCpdyhjAGxr0A6MHezetG0RZXdTA/"
},
{
"market_hash_name":"Shadow Case Key 3",
"assetid":"1293611210722_143865972",
"amount":1,
"image":"https://steamcommunity-a.akamaihd.net/economy/image/-9a81dlWLwJ2UUGcVs_nsVtzdOEdtWwKGZZLQHTxDZ7I56KU0Zwwo4NUX4oFJZEHLbXX7gNTPcUxuxpJSXPbQv2S1MDeXkh6LBBOiePrKF4wi6aaIGwStN_jl4bSzvXwMO6AwDlSvsYoiOiZ8dij3QbtqkU9ZnezetFWWxusZg/"
},
{
"market_hash_name":"Shadow Case Key 4",
"assetid":"123393510722_143861972",
"amount":1,
"image":"https://steamcommunity-a.akamaihd.net/economy/image/-9a81dlWLwJ2UUGcVs_nsVtzdOEdtWwKGZZLQHTxDZ7I56KU0Zwwo4NUX4oFJZEHLbXX7gNTPcUxuxpJSXPbQv2S1MDeXkh6LBBOiePrKF4wi6aaIGwStN_jl4bSzvXwMO6AwDlSvsYoiOiZ8dij3QbtqkU9ZnezetFWWxusZg/"
}
];
Here is my attempt of it, it adds to the queue but it doesn't check if the child object exists. How can I add that?
function addItemToSelectedQueue(assetId){
var itemObj = findItemById(assetId);
var queueHasItem = false;
for (var i = selectedItemQueue.length - 1; i >= 0; i--) {
if (selectedItemQueue[i] === itemObj) {
queueHasItem == true;
};
};
if (queueHasItem == false) {
selectedItemQueue.push(itemObj);
updateSelecteditems();
};
}

I would do it this way:
function addItemToSelectedQueue(fromobj, toobj){
var found = false;
for(var x=0; x<toobj.length; x++){
if(toobj[x].market_hash_name == fromobj[0].market_hash_name){
found = true;
}
}
if(found == false){
toobj.push(fromobj[0]);
}
}
Usage:
addItemToSelectedQueue(selecteditemObj, selectedItemQueue);
Works perfectly fine for me!

What about something like this #JsBIN? I assume market_hash_name is used to differential between each object.
var selecteditemObj = [
{
"market_hash_name":"Chroma 2 Case Key 1",
}
];
var selectedItemQueue = [
{
"market_hash_name":"Chroma 2 Case Key 2",
},
{
"market_hash_name":"Chroma 2 Case Key 3",
}
];
function addItemObjIfNotExist(obj1, obj2, id) {
for(var i = 0, len = obj2.length; i < len; i++) {
if(obj1[1][id] !== obj2[i][id]) {
obj2.push(obj1);
}
}
return obj2;
}
console.log(addItemObjIfNotExist(selectedItemQueue,selecteditemObj, 'market_hash_name'));
Output:
[[object Object] {
market_hash_name: "Chroma 2 Case Key 1"
}, [[object Object] {
market_hash_name: "Chroma 2 Case Key 2"
}, [object Object] {
market_hash_name: "Chroma 2 Case Key 3"
}]]

Related

Ignore TypeError during For Loop

I'm trying to figure out how to "ignore" TypeErrors during a For Loop, but I would like to pass an empty string value to my variable when I do come across a TypeError or a property that does not exist. I have tried some try/catch with TypeError, but I'm not quite sure what to do with the catch. Any help is appreciated...
My obj
theObj = [
{
name:"Billy",
age:"30",
level:"10"
},
{
name:"Jimbo",
age:"25",
level:"8"
},
{
name:"Ralph",
age:"37"
},
{
name:"Rita",
age:"23",
level:"3"
}
]
Loop
for (var i = 0; i < theObj.length; i++) {
const levels = theObj[i]['level']
console.log(levels)
}
console
10
8
undefined
3
What I would like to see
10
8
3
OR
10
8
Null or some other value like DNE, N/A
3
No problem
for (var i = 0; i < theObj.length; i++) {
const levels = theObj[i]['level']
console.log(levels ? levels : "")
}
Try theObj[i]?.level, like:
const theObj = [
{
name:"Billy",
age:"30",
level:"10"
},
{
name:"Jimbo",
age:"25",
level:"8"
},
{
name:"Ralph",
age:"37"
},
{
name:"Rita",
age:"23",
level:"3"
}
];
for (let i = 0; i < theObj.length; i++) {
const levels = theObj[i]?.level;
console.log(levels)
}
you should try this
const levels = theObj?.[i]?.['level'] || ""
?. make sure that the parent is defined and if not it will return undefined

Javascript to validate json message

I'm working to keep validation to the incoming json message mentioned below.
"fields_group": [{
"index": 1,
"value": "test"
}, {
"index": 2,
"value": "test"
}, {
"index": 3,
"value": "test"
}, {
"index": 4,
"value": "test"
}, {
"index": 5,
"value": "test"
}]
Validations:
1) Index value should not be duplicate
2) Should allow indexes 1 to 5 only.
3) Make sure index exist for each value.
Can someone help me with Javascript that does the above in an optimal way? I tried with 2 for loops which is O(n2), but I need a faster solution.
You can use every() and add object as optional parameter to check for duplicate index values.
var obj = {"fields_group":[{"index":1,"value":"test"},{"index":2,"value":"test"},{"index":3,"value":"test"},{"index":4,"value":"test"},{"index":5,"value":"test"}]}
var result = obj.fields_group.every(function(e) {
if(!this[e.index] && e.index <= 5 && e.index > 0 && e.index) {
this[e.index] = true;
return true;
}
}, {});
console.log(result)
You can also use regular expression /^[1-5]$/ to check index values.
var obj = {"fields_group":[{"index":1,"value":"test"},{"index":2,"value":"test"},{"index":3,"value":"test"},{"index":4,"value":"test"},{"index":5,"value":"test"}]}
var result = obj.fields_group.every(function(e) {
if(!this[e.index] && /^[1-5]$/.exec(e.index)) {
this[e.index] = true;
return true;
}
}, {});
console.log(result)
Use the following approach with Array.map, Array.some and RegExp.test functions :
var obj = {"fields_group":[{"index":1,"value":"test"},{"index":2,"value":"test"},{"index":3,"value":"test"},{"index":4,"value":"test"},{"index":5,"value":"test"}]}
var isValid = function(obj){
var indexes = obj.map(function(v){ return v.index; });
return !indexes.some(function(v, k, a){ return a.lastIndexOf(v) !== k; })
&& indexes.length === indexes.map(Boolean).length
&& /^[1-5]+$/.test(indexes.join(""));
}
console.log(isValid(obj.fields_group)); // true
!indexes.some(function(v, k, a){ return a.lastIndexOf(v) !== k; }) - ensures that all indexes are unique
indexes.length === indexes.map(Boolean).length - ensures that each index value exists(not empty)
/^[1-5]+$/.test(indexes.join("") - ensures that there's should be indexes in range from 1 to 5 only
Another method:
function validate(fields_group) {
if (fields_group.length > 5) {
console.log("The array has more than 5 elements. The max is 5.");
return false;
}
var idxs = {};
for (var i = 0; i < fields_group.length; i++) {
var obj = fields_group[i];
if (obj.index == null || idxs[obj.index] || obj.index < 1 || obj.index > 5) {
console.log("An object does not have a valid index.");
return false;
} else {
idxs[obj.index] = true;
}
}
console.log("The feilds group is valid.");
return true;
}
I have measured the execution time (using performace.now() on Chrome) for the answers listed, and found this to be the fastest.

JavaScript - find unique values in array of objects, with count and create a new array of objects

I have an array of objects as below:
var arr =[
{
price:20,
rule:a
},
{
price:10,
rule:b
},
{
price:5,
rule:a
},
{
price:50,
rule:b
},
{
price:70,
rule:b
}
]
I want to extract an array of objects out of this as below:
var filteredArr = [
{
rule:a,
countOfRule:2,
minPriceForThisRule:5
},
{
rule:b,
countOfRule:3,
minPriceForThisRule:10
}
]
This means:
1) I want to create new array with no. of objects as unique no. of rules in first array "arr"
2) Need to count the unique rule repetition and add as property in new array objects - given as "countOfRule"
3) Find the minimum price for in a category of unique rule - given as "minPriceForThisRule"
I have read similar answers on SO and was able to get first 2 conditions only, and that too were not in the format as i need.
What I tried, referring to links on SO:
var ff = {},e;
for (var i = 0,l=arr.length; i < l; i++) {
e = arr[i];
ff[e.rule] = (ff[e.rule] || 0) + 1;
}
But this gives only a single object as
{
a : 2,
b: 3
}
You can do this with forEach and thisArg optional parameter.
var arr = [{"price":20,"rule":"a"},{"price":10,"rule":"b"},{"price":5,"rule":"a"},{"price":50,"rule":"b"},{"price":70,"rule":"b"}],
r = [];
arr.forEach(function(e) {
if(!this[e.rule]) {
this[e.rule] = {rule: e.rule, countOfRule: 0, minPriceForThisRule: e.price}
r.push(this[e.rule]);
}
this[e.rule].countOfRule++;
if(this[e.rule].minPriceForThisRule > e.price) this[e.rule].minPriceForThisRule = e.price;
}, {});
console.log(r)
I would use reduce. Something like:
var reduced = arr.reduce(function(memo, obj){
var rule = memo[obj.rule];
rule.countOfRule++;
if(!rule.minPriceForThisRule){
rule.minPriceForThisRule = obj.price;
} else{
if(obj.price < rule.minPriceForThisRule){
rule.minPriceForThisRule = obj.price;
}
}
return memo;
}, map);
where the initial map looks like:
var map = {
1: {
rule: 1,
countOfRule: 0,
minPriceForThisRule: null
},
2: {
rule: 2,
countOfRule: 0,
minPriceForThisRule: null
}
}
Of course you could dynamically create the map if needed.
https://plnkr.co/edit/wLw3tEx2SMXmYE7yOEHg?p=preview
This is how i would do this job,
var arr =[
{
price:20,
rule:"a"
},
{
price:10,
rule:"b"
},
{
price:5,
rule:"a"
},
{
price:50,
rule:"b"
},
{
price:70,
rule:"b"
}
],
reduced = arr.reduce((p,c) => { var fo = p.find(f => f.rule == c.rule);
fo ? (fo.countOfRule++,
fo.minPriceForThisRule > c.price && (fo.minPriceForThisRule = c.price))
: p.push({rule:c.rule, countOfRule:1, minPriceForThisRule: c.price});
return p;
},[]);
console.log(reduced);
Arrows might not work at IE or Safari. If that would be a problem please replace them with their conventional counterparts.

How to Re-format this JSON using Lodash / JavaScript?

I need to reformat the following JSON data
[
{
"name": "Hello",
"value": 1
},
{
"name": "Hello",
"value": 11
},
{
"name": "Bye",
"value": 2
},
{
"name": "Bye",
"value": 22
}
]
to this:
[
{
"Hello": 1,
"Bye": 2
},
{
"Hello": 11,
"Bye": 22
},
]
There will always be an object with the same "name" field (but a different value in the "value" field) right after. I am stuck and not sure how to solve this. Is it possible to do using Lodash or pure JavaScript?
I have never before heard of Lodash, but in pure JS this can be solved with two nested loops:
function myConvert(long)
{
var short = [];
for(var i = 0; i < long.length; i++)
{
var key = long[i].name;
var value = long[i].value;
var object = null;
for(var j = 0; j < short.length; j++)
{
if(short[j][key] === undefined)
{
object = short[j];
break;
}
}
if(object === null)
{
object = {};
short.push(object);
}
object[key] = value;
}
return short;
}
This is basically:
Iterate over all elements of long.
For each of those, iterate over all elements of short to find the first element where the current name as key is not defined.
Create a new object, if not found.
Add the current value to object with name as key.

remove array element using javascript

I am new to javascript & jquery, Need to remove an element from the below array structure
[{
"tag": "tag1",
"description": "description1"
}, {
"tag": "tag2",
"description": "description2"
}, {
"tag": "tag3",
"description": "description3"
}]
The element to be removed is known {"tag":"tag2", "description":"description2"}.
How can i find this element and remove from the array.
Please find the code which i am using to remove an element
var actionDic = [];
actionDic.push({
description: desc,
tag: tag
});
The actionDic array is populated as user enter text in textinput and selects 'add' option.
var deleterow = {
tag: "tag2",
description: "description2"
};
var index = $.inArray(deleterow, actionDic);
if (index != -1) {
actionDic.splice(index, 1);
}
The correct index is not obtained. Kindly let me know what wrong is in the code.
Thanks.
Since the comparison between the item to remove and each element in actionDic isn't trivial, you could use jQuery.grep():
actionDic = jQuery.grep(actionDic, function(elem) {
return elem.tag == deleterow.tag && elem.description == deleterow.description;
}, true);
Demo
It performs a search using a custom search function and returns the array elements that didn't match. The result replaces the previous value of actionDic and effectively removed that one item.
Update
Unfortunately, this method could be considered heavy because a new array gets created at each invocation; both in terms of what jQuery can do and standard JavaScript functionality, this particular feature is lacking. ECMAScript 6 will have the Array.prototype.find() method that will do the job of finding the index in an array (with which you can perform the splice).
You can of course write one yourself too:
(function($) {
$.find = function(arr, fn) {
for (var i = 0, len = arr.length; i < len; ++i) {
if (fn(arr[i], i, arr)) {
return i;
}
}
return -1;
};
}(jQuery));
var index = $.find(actionDic, function(elem) {
return elem.tag == deleterow.tag && elem.description == deleterow.description;
});
if (index != -1) {
actionDic.splice(index, 1);
}
Demo
I've implemented an indexOfObject method of Array prototype in one of my projects. It searches for an index of object by the given property name and value. Here it is:
Array.prototype.indexOfObject = function(searchTerm, property) {
for (var i = 0, l = this.length; i < l; i++) {
if (this[i][property] === searchTerm) {
return i;
}
}
return -1;
};
You can use this method to find the index of your object using a unique property. In your case you can use it like this:
var arr = [{
"tag": "tag1",
"description": "description1"
}, {
"tag": "tag2",
"description": "description2"
}, {
"tag": "tag3",
"description": "description3"
}], deleteObject = {
tag: "tag2",
description: "description2"
};
var index = arr.indexOfObject(deleteObject.tag, 'tag');
Then you can use that index to remove the object from the array:
if (index > -1) {
arr.splice(index, 1);
}
Here is the working example in JSFiddle.
var actionDic = [{
"tag": "tag1",
"description": "description1"
}, {
"tag": "tag2",
"description": "description2"
}, {
"tag": "tag3",
"description": "description3"
}]
var element = {"tag":"tag2", "description":"description2"}
for(var i=0;i<actionDic.length;i++) {
var found = false;
for(each in actionDic[i]) {
if(actionDic[i][each] == element[each]) {
found = true
} else {
found = false;
break;
}
}
if(found) {
actionDic.splice(i,1);
found=false;
}
}
This gets your inner array objects:
for (var x = 0; x < actionDic.length; x++){
var arrayItem = actionDic[x];
if (arrayItem["tag"] == "tag2"){
alert(arrayItem["description"]);
}
}
Working fiddle: http://jsfiddle.net/4khjp/
You can use underscore.js which contains many useful helpers for Objects, Arrays etc.
Removing array element:
array = _.reject(array, function(item) {
return item.tag == 'tag2'; // <- if tag is unique to whole array
});

Categories

Resources