I have an array object call listOfObjects.
[{"name":"A", "data":"[{"value1":"1","value2":"2"}]"},
{"name":"B", "data":"[{"value1":"1","value2":"2"}]"}]
What I want to do is insert an object into the array where the array is empty.If the array is not empty then do a check on the item inside. If item already exist, do update on the item, else add it to the array. Below is my code
var searchName= "A";
if (listOfObjects.length > 0) {
for (var i = 0; i < listOfObjects.length; i++) {
if (listOfObjects[i].name == searchName) {
listOfObjects[i].data = data;
break;
} else {
insert = {
'name': searchName,
'data': data
};
listOfObjects.push(insert);
}
}
} else {
insert = {
'name': searchName,
'data': data
};
listOfObjects.push(insert);
}
When I run it, even though A already exist, it update the existing item but also add one more time to the listOfObjects. Is there anyway that can achieve what I want? Thanks..
The problem is you're inserting into the array inside your for loop looking for a match. Instead, remember whether you've seen a match and insert after the loop if you haven't. There's also no reason for the length check and no reason to repeat your logic for inserting:
var searchName= "A";
var found = false;
for (var i = 0; !found && i < listOfObjects.length; i++) {
if (listOfObjects[i].name == searchName) {
listOfObjects[i].data = data;
found = true;
}
}
if (!found) {
listOfObjects.push({
'name': searchName,
'data': data
});
}
Note that you can use Array#find (which can be polyfilled for old browsers) to find the entry rather than a for loop if you like:
var searchName= "A";
var entry = listOfObjects.find(function(entry) {
return entry.name == searchName;
});
if (entry) {
entry.data = data;
} else {
listOfObjects.push({
'name': searchName,
'data': data
});
}
First of all change this
[{"name":"A", "data":"[{"value1":"1","value2":"2"}]"},
{"name":"B", "data":"[{"value1":"1","value2":"2"}]"}]
by
[{"name":"A", "data":[{"value1":1,"value2":2}]},
{"name":"B", "data":[{"value1":"1","value2":"2"}]}];
because your list will throw Uncaught SyntaxError: Unexpected identifier
Write another simple function to get the item listOfObjects[i] with selected searchName. Here 'getSearchObject()' function checks the existance of searchName and then add or updates array.
addOrRemoveItem() {
let listOfObjects = [
{ "name": "A", "data": "[{'value1':'1','value2':'2'}]" },
{ "name": "B", "data": "[{'value1':'1','value2':'2'}]" }
],
data = '[{"value1":"1","value2":"2"}]';
var searchName = "C";
if (listOfObjects.length > 0) {
let searchObj = this.getSearchObject(listOfObjects, searchName);
if (searchObj) {
searchObj.data = data;
} else {
let insert = {
"name": searchName,
"data": data
}
listOfObjects.push(insert);
}
} else {
let insert = {
"name": searchName,
"data": data
}
listOfObjects.push(insert);
}
}
getSearchObject(objArr, searchKey) {
var obj = null;
for (let i = 0; i < objArr.length; i++) {
if (objArr[i].name === searchKey) {
obj = objArr[i];
}
}
return obj;
}
A generic solution that recognizes older JS engines (filter instead of find) but does always assume getting passed a list of unique items could be implemented like this ...
function updateList(itemList, item) { // - always assume a list of unique items.
var
itemName = item.name,
listItem = itemList.filter(function (elm) { // - assume `filter`, not find`.
return (elm.name === itemName); // - find/get existing list item by name.
})[0];
if (listItem) {
listItem.data = item.data;
} else {
itemList.push(item)
}
}
var list = [
{ "name": "A", "data": [ { "value1": "A1", "value2": "A2" }] },
{ "name": "B", "data": [ { "value1": "B1", "value2": "B2" }] },
{ "name": "C", "data": [ { "value1": "C1", "value2": "C2" }] }
];
console.log('list : ', list);
updateList(list, { "name": "D", "data": [ { "value1": "D1", "value2": "D2" }] });
updateList(list, { "name": "B", "data": [ { "value1": "b_1", "value2": "b_2", "value3": "b_3" }] });
updateList(list, { "name": "C", "data": [ { "value3": "C3" }] });
console.log('list : ', list);
.as-console-wrapper { max-height: 100%!important; top: 0; }
Related
Get the corresponding type in the object, and then traverse the array of push objects, but I can't think of a better way to solve the desired result below.
I want a good return as follows:
[{
"id": 1,
"type": "one",
"name": ["apple","apricot"]
},
{
"id": 3,
"type": "two",
"name": ["avocado"]
}]
var result = [{
"id": 1,
"type": "one",
"name": "apple"
}, {
"id": 2,
"type": "one",
"name": "apricot"
},
{
"id": 3,
"type": "two",
"name": "avocado"
}
]
Array.prototype.unique = function() {
var hash = {},
len = this.length,
result = [];
for (var i = 0; i < len; i++) {
if (!hash[this[i].type]) {
result.push(this[i].type);
hash[this[i].type] = true;
}
}
return result;
}
console.log(result)
console.log(result.unique())
var cArr = result.unique()
var arr = []
cArr.forEach(function(prop) {
result.map(function(item) {
if (prop == item.type) {
console.log(item)
arr.push({
...item,
[`user_${item.id}`]: item.user,
})
}
})
})
console.log(arr)
You can do this with reduce quite easily:
var input = [
{ id: 1, type: "one", name: "apple"},
{ id: 2, type: "one", name: "apricot" },
{ id: 3, type: "two", name: "avocado" }
];
// Make sure `unique` doesn't already exist on the Array prototype
if (!('unique' in Array.prototype)) {
Array.prototype.unique = function () {
// iterate over the array
const temp = this.reduce((acc, current) => {
// Desstructure the id, type, and name from the current object
const { id, type, name } = current;
// If an key with the value of `type` doesn't exist
// on the accumulator, add a new object with name set
// to an empty array
acc[type] = acc[type] || { id, type, name: [] };
// Push the name in the current object to the name array
acc[type].name.push(name);
// Return the accumulator for the next iteration
return acc;
// Note: the initial accumulator value is an object
}, {});
// Then simply return the values from the accumulated object
return Object.values(temp);
}
}
console.log(input.unique())
I am using an array with nested object of array. Assigning the values in array's values according to input line index, values are passed into the array's indexed value. I have checked the condition that if in array object is there, it converts it into array and call the recursive function and it calls recursion until the object's array's value is full but don't know why it is not working properly. Please help me in this bug
(function($) {
var xmlOutput = document.querySelector(".xmlOutput");
let templateStore = [];
let preservedEntriesValue = [];
let selectedTemplate = [];
function generateDOMDropdown(selectedID) {
let optionTemplate = templateStore.map(function(entry) {
return `<option value="${
entry.id
}" ${entry.id === selectedID ? "selected" : ""}>${entry.name}</option>`;
});
$("#select").html(optionTemplate);
}
function processEntries(entries) {
let output = "";
for (const entry of entries) {
output += entry;
}
return output;
}
function parseJSONToXML(input) {
const domStructure = input.entriesValue.map(function(tagObj) {
if (typeof tagObj === "string") {
return `<${tagObj}></${tagObj}>`;
} else if (Array.isArray(tagObj)) {
if (tagObj.length > 1) {
return `<${tagObj[0]}>${tagObj[1]}</${tagObj[0]}>`;
} else if (tagObj.length == 1) {
return `<${tagObj[0]}></${tagObj[0]}>`;
}
} else {
const outerTag = Object.keys(tagObj).pop();
const innerDOM = parseJSONToXML({ entriesValue: tagObj[outerTag] });
return `<${outerTag}>${processEntries(innerDOM)}</${outerTag}>`;
}
});
return domStructure;
}
function preFillSelected() {
const root = selectedTemplate.root;
const domStructure = parseJSONToXML(selectedTemplate);
xmlOutput.innerText = vkbeautify.xml(
`<?xml version="1.0" encoding="UTF-8"?><${root}>${processEntries(
domStructure
)}</${root}>`,
5
);
}
$.ajax({
type: "get",
url: window.location.origin + "/templates.json",
success: function(data) {
templateStore = data;
if (data.length > 0) {
selectedTemplate = data[0];
generateDOMDropdown(selectedTemplate.id);
preservedEntriesValue = selectedTemplate.entriesValue;
preFillSelected();
$("#select")
.off("change")
.on("change", function() {
selectedTemplate = templateStore[$("#select").val()];
preservedEntriesValue = selectedTemplate.entriesValue;
preFillSelected();
window.template = selectedTemplate;
});
}
}
});
function generateValueJSON(
template,
lines,
inputLen,
templateLen,
flatLen,
cidx
) {
cidx = cidx || 0;
// console.log('Entry', lines, template, cidx);
return Array.from(template.entriesValue.entries()).map(([idx, entry]) => {
console.log("Lines", lines);
if (idx < lines.length) {
if (Array.isArray(entry)) {
return [entry[0], lines[idx]];
} else if (typeof entry === "object") {
// debugger;
const outerTag = Object.keys(entry).pop();
const innerLength = entry[outerTag].length;
if (cidx === 0) cidx = idx;
const outerIdx = cidx + innerLength;
// console.log((flatLen - templateLen - inputLen));
// console.log({ flatLen, templateLen, inputLen, outerIdx, cidx, idx });
const innerObj = generateValueJSON(
{ entriesValue: entry[outerTag] },
lines.slice(idx, outerIdx),
inputLen,
templateLen,
flatLen,
idx
);
// cidx = 0;
entry[outerTag] = innerObj;
return entry;
}
return [entry, lines[idx]];
}
return entry;
});
}
function mapLength(template) {
return template.entriesValue
.map((entry) => {
return typeof entry === "object"
? [Object.keys(entry), Object.values(entry)]
: entry;
})
.flat(3).length;
}
$("#txtInput").on("keyup", function() {
const lines = $(this)
.val()
.split("\n\n")
.map((v) => v.trim().replace(/\n/g, "<br/>"));
// console.log(preservedEntriesValue);
selectedTemplate.entriesValue = preservedEntriesValue;
templateLength = mapLength(selectedTemplate);
const newEntriesValue = generateValueJSON(
selectedTemplate,
lines,
lines.length,
selectedTemplate.entriesValue.length,
templateLength
);
// console.log(newEntriesValue);
selectedTemplate.entriesValue = newEntriesValue;
preFillSelected();
});
})(window.jQuery, Node);
//here is the data array
[{
"id": "1",
"name": "Template Name 2",
"root": "media",
"entriesValue": [
"mediaid",
"category",
"provider",
"date",
"caption_photo_1",
{
"image": [
"imageid",
"type",
"width",
"hfive"
]
},
{
"video": [
"name",
"type",
"bitrate",
"size",
"width",
"hfive",
"headline",
"summary"
]
}
]
},
{
"id": "0",
"name": "Template Name 1",
"root": "article",
"entriesValue": [
"author",
"headline",
"cats",
"subcats",
"image",
"video",
"tags",
"summary",
"content"
]
},
{
"id": "2",
"name": "Template Name 3",
"root": "article",
"entriesValue": [
"author",
"headline",
"cats",
"subcats",
"image",
"video",
"summary",
"content",
"keyword"
]
},
{
"id": "3",
"name": "Template Name 4",
"root": "root",
"entriesValue": [
"description",
"title",
"languageId",
"categoryIds"
]
}
]
At first input it work properly but in second input it passes the value in in both object
<image>
<imageid>Correct</imageid>
<type>bug</type>
<width>bug</width>
<hfive></hfive>``
</image>
<video>
<name>bug</name>
<type>bug</type>
<bitrate></bitrate>
<size></size>
<width></width>
<hfive></hfive>
<headline></headline>
<summary></summary>
</video>
I have an array of objects:-
var arr1 = [{
"name": "A"
}, {
"name": "B"
}, {
"name": "C"
}, {
"name": "D"
}];
I want to add a new property to each element which are not present in the second array.
var arr2 = [C,D]
The resulted array should be:-
arr1 = [{
"name": "A",
"country":"USA"
}, {
"name": "B",
"country":"USA"
}, {
"name": "C"
}, {
"name": "D"
}];
Can any one tell me how to achieve that?
I want to add a new property to each element which are not present in the second array.
That completely changes the question you originally asked.
If the items are mutable, you'd just loop through the array adding the property to selected items. There are many ways to do that, such as forEach:
arr1.forEach(function(item) {
if (arr2.indexOf(item.name) === -1) {
item.country = "USA";
}
});
Live Example:
var arr1 = [{
"name": "A"
}, {
"name": "B"
}, {
"name": "C"
}, {
"name": "D"
}];
var arr2 = ["C", "D"];
arr1.forEach(function(item) {
if (arr2.indexOf(item.name) === -1) {
item.country = "USA";
}
});
console.log(arr1);
If they're immutable, you'd use map instead:
arr1 = arr1.map(function(item) {
if (arr2.indexOf(item.name) === -1) {
return /*...create item with `country = "USA"` here...*/;
} else {
return item;
}
});
Live Example:
var arr1 = [{
"name": "A"
}, {
"name": "B"
}, {
"name": "C"
}, {
"name": "D"
}];
var arr2 = ["C", "D"];
arr1 = arr1.map(function(item) {
if (arr2.indexOf(item.name) === -1) {
return {name: item.name, country: "USA"};
} else {
return item;
}
});
console.log(arr1);
Original answer: (to your original question)
You would loop over the resulting array adding the property. There are many ways to do that, such as forEach:
arr1.forEach(function(item) {
item.country = "USA";
});
Technically, you could make it a side-effect of your filter, like this:
var arr1 = arr1.filter(function(item){
if (arr2.indexOf(item.name) === -1) {
item.country = "USA";
return true;
};
return false;
});
BUT, side-effects in filter callbacks (and similar) are generally not a great idea. Unless you know that the resulting array (arr1) is hundreds of thousands of entries, the second pass keeps things simple by filtering and then modifying.
Use Array.forEach and add the property if the element is not present - by using the same comparison you were already using.
I would like to know what is the faster way to retrieve an object by its id, keeping in consideration that the structure where it is stored could be different.
Does any native function in JS for this operation?
Example 1
var source = {
"page": [{
"id": "1",
"site": "",
"items": [{
"id": "2"
}, {
"id": "3",
"anotherItem": [{
"id": "4"
}, {
"id": "5"
}]
}]
}, {
"id": "6"
}]
};
Example 2
Structure could be completely different, the script should be always able to get the object containing id.
{
"smtElse": {
"id": "1"
}
}
No, there is no native function.
The fastest way is the same as the only way which is to iterate over the object, probably recursively, looking for IDs and returning what you want.
I solved using the following script, as it seems no native functionality is available.
var data = {
item: [
{
itemNested: [
{
itemNested2: [{
id: "2"
}
]
}
]
}
]
};
function findById(obj, id) {
var result;
for (var p in obj) {
if (obj.id == id) {
return obj;
} else {
if (typeof obj[p] === 'object') {
result = findById(obj[p], id);
if (result) {
return result;
}
}
}
}
return result;
}
var result = findById(data, "2");
console.log(result);
you can try this
<script type="text/javascript">
var re = /"id":\s+"(.*?)"/;
var sourcestring = "source string to match with pattern";
var results = [];
var i = 0;
for (var matches = re.exec(sourcestring); matches != null; matches = re.exec(sourcestring)) {
results[i] = matches;
for (var j=0; j<matches.length; j++) {
alert("results["+i+"]["+j+"] = " + results[i][j]);
}
i++;
}
Here is what I want to do:
I have a tree (javascript object-literal structure) with multiple levels.
I have a value of a particular key of this object.
I want to search for this exact key-value pair in the structure and return the value of another key as an output.
For clarity following is my object literal:
{
"nodeId": 1081,
"appId": 150,
"displayText": "Welcome here",
"Nodes": [
{
"nodeId": 2000,
"appId": 150,
"displayText": "Buy",
"parentNodeId": 1081,
"Nodes": [
{
"nodeId": 2003,
"appId": 150,
"displayText": "tCars",
"parentNodeId": 2000,
"Nodes": [
{
"nodeId": 2006,
"appId": 150,
"displayText": "Diesel",
"parentNodeId": 2003,
"Nodes": [
{
"nodeId": 2008,
"appId": 150,
"displayText": "Price", //This is what I want as return value.
"parentNodeId": 2006,
"Nodes": [],
"nodeCode": "RN_1_1_2_1_3_2_4_1",
"parentCode": "RN_1_1_2_1_3_2",
"jumpToNode": "RN_1_1" //here is the value that I have with me.
}
],
"nodeCode": "RN_1_1_2_1_3_2",
"parentCode": "RN_1_1_2_1"
}
],
"concatWithHeader": false,
"nodeCode": "RN_1_1_2_1",
"parentCode": "RN_1_1"
}
],
"nodeCode": "RN_1_1",
"parentCode": "RN"
}
],
"nodeCode": "RN",
"parentCode": "ROOT_NODE"
}
2. Value that I have with me is "RN_1_1" against jumpToNode
3. I want to search in this object literal and get the value of the key displayText
I searched and tried few things for this but couldnt get the logic to iterate over the inner Nodes objects.
Method I wrote so far:
function getObjects(tree){
var searchkey="RN_1_1";
var displayText = "displayText";
var nodeCode = "nodeCode";
var returnText;
if (tree.hasOwnProperty(nodeCode)) {
var obj = tree[nodeCode];
if(obj == searchkey){
returnText = tree[displayText]; //gives me the return text
break;
}
else{
//here I should iterate over the inner `Nodes` and get the required value.
}
}
}
Please help.
Thanks.
I think you can do something like this which works recursively:
function findProperty(obj, prop, val, propToFetch) {
var answer;
if (obj.hasOwnProperty(prop) && obj[prop] === val) {
return obj[propToFetch];
}
for (var i = 0, len = obj.Nodes.length; i < len; i++) {
answer = findProperty(obj.Nodes[i], prop, val, propToFetch);
if (answer !== null) {return answer;}
}
return null;
}
var result = findProperty(data, "jumpToNode", "RN_1_1", "displayText");
Working demo here: http://jsfiddle.net/jfriend00/EjC5V/
Accordingly to your JSON object you can use this way:
var searchKey="RN_1_1",
displayText = "displayText",
nodeCode = "nodeCode",
returnText,
treeSearch = function (obj, searchKey) {
if (obj[nodeCode] === searchKey) {
returnText = obj[displayText];
} else {
if (obj['Nodes'][0]) {
treeSearch(obj['Nodes'][0], searchKey);
} else {
returnText = null
}
}
};
treeSearch(JSONdata, 'RN_1_1_2_1_3_2');
I have flattened the array using the nodeId to be easier to search through it.
After you flatten the array you can filter it as you wish(i suggest using underscorejs.org)
Here is the live example. The result is displayed in the console.
function flattenNodes (obj, newArr) {
if (obj && obj.Nodes) {
var nodes = obj.Nodes;
delete(obj.Nodes);
newArr[obj.nodeId] = obj;
return flattenNodes(nodes.pop(), newArr);
} else {
return newArr;
}
};
var flattenArr = flattenNodes(arr, new Array());
function findInJumpToNode(find) {
for(key in flattenArr) {
if (flattenArr[key] && flattenArr[key]['jumpToNode']) {
if (flattenArr[key]['jumpToNode'] == find) {
return flattenArr[key];
}
}
}
}
var found = findInJumpToNode('RN_1_1');
console.log(found);
You can use recursion to handle your case.
Check out this sample on jsFiddle.
var nodes= [getNodes()];
alert(getObjects(nodes));
function getObjects(tree){
var searchkey="RN_1_1_2_1_3_2_4_1";
var displayText = "displayText";
var nodeCode = "nodeCode";
var returnText;
if(tree.length > 0)
{
if(tree[0]["nodeCode"] === searchkey)
{
return tree[0][displayText];
}
if(typeof tree[0]["Nodes"] === "undefined")
{
return;
}
return getObjects(tree[0]["Nodes"]);
}
}