cannot update an array of elements via a 2d iteration - javascript

I have two arrays of object, the first array (printerChart, around 80 elements) is made of the following type of objects:
[{
printerBrand: 'Mutoh',
printerModel: 'VJ 1204G',
headsBrand: 'Epson',
headType: '',
compatibilty: [
'EDX',
'DT8',
'DT8-Pro',
'ECH',
],
},
....
]
The second array (items, around 500 elements) is made of the following type of objects:
[
{
"customData": {
"brand": {
"value": {
"type": "string",
"content": "hp"
},
"key": "brand"
},
"printer": {
"value": {
"type": "string",
"content": "c4280"
},
"key": "printer"
}
},
"name": "DT8 XLXL",
"image": {
"id": "zLaDHrgbarhFSnXAK",
"url": "https://xxxxxxx.net/images/xxxxxx.jpg"
},
"brandId": "xxxxx",
"companyId": "xxxx",
"createdAt": "2018-03-26T14:39:47.326Z",
"updatedAt": "2018-04-09T14:31:38.169Z",
"points": 60,
"id": "dq2Zezwm4nHr8FhEN"
},
...
]
What I want to do is to iterate via the second array and, if the part of the name of an item (i.e. DT8) is included in an element of the array 'compatibility' of the first array, I would like to include a new properties to it from the element of the first array: printerBrand. I have tried but somehow the iteration doesn't take place correctly. This is what I tried:
items.forEach((item) => {
printerChart.forEach((printer) => {
if (printer.compatibilty.some(compatibleElem => (
item.name.includes(compatibleElem)))) {
item.printerBrand = printer.printerBrand;
} else {
item.printerBrand = '';
}
});
});
What am I doing wrong?

You do
items.items.forEach(...)
Shouldn't you be doing
items.forEach(...)
?

I suggest to initialize item.printerBrand with an empty string and use a nested approach of some for getting a brand and to exit the loops, if found.
This prevents to get an empty string even if there is a brand to assign.
items.forEach((item) => {
item.printerBrand = '';
printerChart.some(printer => {
if (printer.compatibilty.some(compatibleElem => item.name.includes(compatibleElem))) {
item.printerBrand = printer.printerBrand;
return true;
}
});
});

Related

How to filter an objects where is employeeId equals to some value

I'm using knockoutjs, but the question is really in Javascript domain.
I have variable vm.filteredSerivces() which contains all services by all employees.
Now, I want to just preserve those filteredSerivces where is vm.filteredSerivces()[0].GroupedServices[x].EmployeeId == 3684 (x is the number of index number of each object in GroupedServices object list)
I tried as follows:
var filteredSrvcs = vm.filteredSerivces()[0].GroupedServices.filter(x => x.EmployeeId != Id).remove();
vm.filteredSerivces(filteredSrvcs );
But I changed structure in that way, and my bindings in html is not corresponding.
Is there any other way to just remove this sub-sub object, and to preserve a structure as it is?
Here is the
Here's an example that maps a new array of new objects and the filter is set to only include the GroupedServices items where Id == 2000
let res = data.map(({ServiceTypeName, GroupedServices}) =>{
GroupedServices= GroupedServices.filter(({Id}) => Id == 2000);
return {ServiceTypeName,GroupedServices }
})
console.log(res)
<script>
let data =
[
{
"ServiceTypeName": "Type 1",
"GroupedServices": [{
"Id": 1,
"Name": "A"
}, {
"Id": 2,
"Name": "A"
},
{
"Id": 28456,
"Name": "AGSADGJS"
}]
},
{
"ServiceTypeName": "Type 2",
"GroupedServices": [{
"Id": 1203,
"Name": "AHASJ"
}, {
"Id": 2000,
"Name": "AHSJD"
},
{
"Id": 284536,
"Name": "UEHNCK"
}]
}];
</script>

Loop through JSON array of objects and get the properties based on the matching IDs from objects

My target is if the id from digital_assets and products matches then get the value of URL fro digital_assets and ProductName from products object. I'm able to traverse through the object and get the values of digital_assets and products but need some help to compare these two objects based on IDs to get the value of URL and ProductName. Below is what I've done so far.
var data = [{
"digital_assets": [{
"id": "AA001",
"url": "https://via.placeholder.com/150"
},{
"id": "AA002",
"url": "https://via.placeholder.com/150"
}]
}, {
"products": [{
"id": ["BB001", "AA001"],
"ProductName": "PROD 485"
},{
"id": ["BB002", "AA002"],
"ProductName": "PROD 555"
}]
}
];
$.each(data, function () {
var data = this;
//console.log(data);
$.each(data.digital_assets, function () {
var dAssets = this,
id = dAssets['id'];
// console.log(id);
});
$.each(data.products, function () {
var proData = this,
prod_id = proData['id'];
// console.log(prod_id);
$.each(prod_id, function () {
var arr_id = this;
console.log(arr_id);
});
});
});
Do I need to create new arrays and push the values into the new arrays? Then concat() these array to one. ? Bit lost any help will be appreciated.
Here is one way you can do this via Array.reduce, Array.includes, Object.entries and Array.forEach:
var data = [{ "digital_assets": [{ "id": "AA001", "url": "https://via.placeholder.com/150" }, { "id": "AA002", "url": "https://via.placeholder.com/150" } ] }, { "products": [{ "id": ["BB001", "AA001"], "ProductName": "PROD 485" }, { "id": ["BB002", "AA002"], "ProductName": "PROD 555" } ] } ]
const result = data.reduce((r,c) => {
Object.entries(c).forEach(([k,v]) =>
k == 'digital_assets'
? v.forEach(({id, url}) => r[id] = ({ id, url }))
: v.forEach(x => Object.keys(r).forEach(k => x.id.includes(k)
? r[k].ProductName = x.ProductName
: null))
)
return r
}, {})
console.log(Object.values(result))
You can use Array.prototype.find, Array.prototype.includes and Array.prototype.map to achieve this very gracefully.
let data = [
{
"digital_assets": [
{
"id": "AA001",
"url": "https://via.placeholder.com/150"
},
{
"id": "AA002",
"url": "https://via.placeholder.com/150"
}
]
},
{
"products": [
{
"id": ["BB001", "AA001"],
"ProductName": "PROD 485"
},
{
"id": ["BB002","AA002"],
"ProductName": "PROD 555"
}
]
}
];
// Find the 'digital_assets' array
let assets = data.find(d => d['digital_assets'])['digital_assets'];
// Find the 'products' array
let products = data.find(d => d['products'])['products'];
// Return an array of composed asset objects
let details = assets.map(a => {
return {
id : a.id,
url : a.url
name : products.find(p => p.id.includes(a.id)).ProductName
};
});
console.log(details);
changed answer to fit your needs:
var data = [
{
"digital_assets": [
{
"id": "AA001",
"url": "https://via.placeholder.com/150"
},
{
"id": "AA002",
"url": "https://via.placeholder.com/150"
}
]
},
{
"products": [
{
"id": ["BB001", "AA001"],
"ProductName": "PROD 485"
},
{
"id": ["BB002","AA002"],
"ProductName": "PROD 555"
}
]
}
]
let matchingIds = [];
let data_assetsObject = data.find(element => {
return Object.keys(element).includes("digital_assets")
})
let productsObject = data.find(element => {
return Object.keys(element).includes("products")
})
data_assetsObject["digital_assets"].forEach(da => {
productsObject["products"].forEach(product => {
if (product.id.includes(da.id)){
matchingIds.push({
url: da.url,
productName: product.ProductName
})
}
})
})
console.log(matchingIds);
working fiddle: https://jsfiddle.net/z2ak1fvs/3/
Hope that helped. If you dont want to use a new array, you could also store the respective data within the element you are looping through.
Edit:
I think i know why i got downvoted. My example works by making data an object, not an array. changed the snippet to show this more clearly.
Why is data an array anyway? Is there any reason for this or can you just transform it to an object?
Edit nr2:
changed the code to meet the expectations, as i understood them according to your comments. it now uses your data structure and no matter whats in data, you can now search for the objects containing the digital_assets / products property.
cheers
https://jsfiddle.net/2b1zutvx/
using map.
var myobj = data[0].digital_assets.map(function(x) {
return {
id: x.id,
url: x.url,
ProductName: data[1].products.filter(f => f.id.indexOf(x.id) > -1).map(m => m.ProductName)
};
});

How to delete object from an array of objects having relations with each arrays?

This Object have relationship as: childOne > childTwo > childThree > childFour > childFive > childSix.
{
"parentObj": {
"childOne": [
{
"name": "A",
"id": "1"
},
{
"name": "B",
"id": "2"
}
],
"childTwo": [
{
"name": "AB",
"parent_id": "1",
"id": "11"
},
{
"name": "DE",
"parent_id": "2",
"id": "22"
}
],
"childThree": [
{
"name": "ABC",
"parent_id": "22",
"id": "111"
},
{
"name": "DEF",
"parent_id": "11",
"id": "222"
}
],
"childFour": [
{
"name": "ABCD",
"parent_id": "111",
"id": "1111"
},
{
"name": "PQRS",
"parent_id": "111",
"id": "2222"
}
],
"childFive": [
{
"name": "FGRGF",
"parent_id": "1111",
"id": "11111"
},
{
"name": "ASLNJ",
"parent_id": "1111",
"id": "22222"
},
{
"name": "ASKJA",
"parent_id": "1111",
"id": "33333"
}
],
"childSix": [
{
"name": "SDKJBS",
"parent_id": "11111",
"id": "111111"
},
{
"name": "ASKLJB",
"parent_id": "11111",
"id": "222222"
}
]
}
}
Is there any way to delete an item by ID and the objects which are associated with that particular ID should get deleted(i.e., If I do delete parentObj.childTwo[1], then all the related object beneath it should also gets deleted).
Looping manually is too bad code, and generate bugs. There must be better ways of dealing with this kind of problems like recursion, or other.
The data structure does not allow for efficient manipulation:
By nature objects have an non-ordered set of properties, so there is no guarantee that iterating the properties of parentObj will give you the order childOne, childTwo, childThree, ... In practice this order is determined by the order in which these properties were created, but there is no documented guarantee for that. So one might find children before parents and vice versa.
Although the id values within one such child array are supposed to be unique, this object structure does not guarantee that. Moreover, given a certain id value, it is not possible to find the corresponding object in constant time.
Given this structure, it seems best to first add a hash to solve the above mentioned disadvantages. An object for knowing a node's group (by id) and an object to know which is the next level's group name, can help out for that.
The above two tasks can be executed in O(n) time, where n is the number of nodes.
Here is the ES5-compatible code (since you mentioned in comments not to have ES6 support). It provides one example call where node with id "1111" is removed from your example data, and prints the resulting object.
function removeSubTree(data, id) {
var groupOf = {}, groupAfter = {}, group, parents, keep = { false: [], true: [] };
// Provide link to group per node ID
for (group in data) {
data[group].forEach(function (node) {
groupOf[node.id] = group;
});
}
// Create ordered sequence of groups, since object properties are not ordered
for (group in data) {
if (!data[group].length || !data[group][0].parent_id) continue;
groupAfter[groupOf[data[group][0].parent_id]] = group;
}
// Check if given id exists:
group = groupOf[id];
if (!group) return; // Nothing to do
// Maintain list of nodes to keep and not to keep within the group
data[group].forEach(function (node) {
keep[node.id !== id].push(node);
});
while (keep.false.length) { // While there is something to delete
data[group] = keep.true; // Delete the nodes from the group
if (!keep.true.length) delete data[group]; // Delete the group if empty
// Collect the ids of the removed nodes
parents = {};
keep.false.forEach(function (node) {
parents[node.id] = true;
});
group = groupAfter[group]; // Go to next group
if (!group) break; // No more groups
// Determine what to keep/remove in that group
keep = { false: [], true: [] };
data[group].forEach(function (node) {
keep[!parents[node.parent_id]].push(node);
});
}
}
var tree = {"parentObj": {"childOne": [{"name": "A","id": "1"},{"name": "B","id": "2"}],"childTwo": [{"name": "AB","parent_id": "1","id": "11"},{"name": "DE","parent_id": "2","id": "22"}],"childThree": [{"name": "ABC","parent_id": "22","id": "111"},{"name": "DEF","parent_id": "11","id": "222"}],"childFour": [{"name": "ABCD","parent_id": "111","id": "1111"},{"name": "PQRS","parent_id": "111","id": "2222"}],"childFive": [{"name": "FGRGF","parent_id": "1111","id": "11111"},{"name": "ASLNJ","parent_id": "1111","id": "22222"},{"name": "ASKJA","parent_id": "1111","id": "33333"}],"childSix": [{"name": "SDKJBS","parent_id": "11111","id": "111111"},{"name": "ASKLJB","parent_id": "11111","id": "222222"}]}}
removeSubTree(tree.parentObj, "1111");
console.log(tree.parentObj);
.as-console-wrapper { max-height: 100% !important; top: 0; }
Sure, the function you use to delete an entry should FIRST recurse, which means run itself on the linked entry, unless there is none. So, in psuedocode
function del(name, index)
{
if parent[name][index] has reference
Then del(reference name, reference ID)
Now del parent[name][index]
}
No loop needed.
And since we stop if there is no reference, we do not recurse forever.
Not sure what it is you want but maybe this will work:
const someObject = {
"parentObj": {
"childOne": [
{
"name": "A",
"id": "1"
},
{
"name": "B",
"id": "2"
}
],
"childTwo": [
{
"name": "AB",
"childOne": "1",
"id": "11"
},
{
"name": "DE",
"childOne": "2",
"id": "22"
}
]
}
};
const removeByID = (key,id,parent) =>
Object.keys(parent).reduce(
(o,k)=>{
o[k]=parent[k].filter(
item=>
!(Object.keys(item).includes(key)&&item[key]===id)
);
return o;
},
{}
);
const withoutID = Object.assign(
{},
someObject,
{ parentObj : removeByID("childOne","1",someObject.parentObj) }
);
console.log(`notice that childTwo item with childOne:"1" is gone`);
console.log("without key:",JSON.stringify(withoutID,undefined,2));
const otherExample = Object.assign(
{},
someObject,
{ parentObj : removeByID("childOne","2",someObject.parentObj) }
);
console.log(`notice that childTwo item with childOne:"2" is gone`);
console.log("without key:",JSON.stringify(otherExample,undefined,2));
const both = Object.assign(
{},
someObject,
{ parentObj : removeByID("childOne","1",otherExample.parentObj) }
);
console.log(`notice that childTwo items with childOne are both gone`);
console.log("without key:",JSON.stringify(both,undefined,2));

How to append object-key value form one array to other array?

I have an existing array with multiple object. With an interval I would like to update the existing array with values from another array. See the (simplified) example below.
I've serverall gools:
Copy the value of fan_count form the new array, to the current array with the key "fan_count_new"
If a object is removed or added in the New array, it have to do the same to the Current array.
As far I can see now, I can use some es6 functions :) like:
object-assign, but how to set the new key "fan_count_new"?
How to loop through the array to compare and add or remove + copy the fan_count?
Current array:
[{
"fan_count": 1234,
"id": "1234567890",
"picture": {
"data": {
"url": "https://scontent.xx.fbcdn.net/v/photo.png"
}
}
},
{
"fan_count": 4321,
"id": "09876543210",
"picture": {
"data": {
"url": "https://scontent.xx.fbcdn.net/v/photo.png"
}
}
}, ...
]
New array:
[{
"fan_count": 1239,
"picture": {
"data": {
"url": "https://scontent.xx.fbcdn.net/v/photo.png"
}
"id": "1234567890"
},
{
"fan_count": 4329,
"picture": {
"data": {
"url": "https://scontent.xx.fbcdn.net/v/photo.png"
}
},
"id": "09876543210"
}, ...
]]
You can remove elements which doesn't exists in new array by using array.filter and you can loop through the new array to update the same object in the current array:
var currArr = [
{
"fan_count": 1234,
"id": "1234567890",
},
{
"fan_count": 4321,
"id": "09876543210",
},
{
"fan_count": 4321,
"id": "09876543215",
}
];
var newArr = [
{
"fan_count": 1234,
"id": "1234567890"
},
{
"fan_count": 5555,
"id": "09876543210"
}
];
currArr = currArr.filter(obj => newArr.some(el => el.id === obj.id));
newArr.forEach(obj => {
var found = currArr.find(o => o.id === obj.id);
if (found) {
found.fan_count_new = obj.fan_count;
}
});
console.log(currArr);
Later on I realised that is was better to turn it around, add the fan_count form the currArr to the new one. This because it is easier to handle new objects, and you dont't have to deal with deleted objects. So, anybody how is looking for something like this:
newArr.forEach(obj => {
var found = currArr.find(o => o.id === obj.id);
if (found) {
console.log('found: ', found.fan_count, obj.fan_count)
obj.fan_count_prev = found.fan_count;
obj.fan_count_diff = Math.round(obj.fan_count - found.fan_count);
}
if (typeof obj.fan_count_prev === "undefined") {
obj.fan_count_prev = obj.fan_count;
obj.fan_count_diff = 0
}
});

How to iterate through deeply nested objects inside of a JSON?

I know there are plenty of questions about iterating through JSON objects but I haven't found one that quite relates to my exact problem. This is the JSON that I'm trying to iterate through:
psinsights = {
"kind": "pagespeedonline#result",
"id": "/speed/pagespeed",
"responseCode": 200,
"title": "PageSpeed Home",
"score": 90,
"pageStats": {
"numberResources": 22,
"numberHosts": 7,
"totalRequestBytes": "2761",
"numberStaticResources": 16,
"htmlResponseBytes": "91981",
"cssResponseBytes": "37728",
"imageResponseBytes": "13909",
"javascriptResponseBytes": "247214",
"otherResponseBytes": "8804",
"numberJsResources": 6,
"numberCssResources": 2
},
"formattedResults": {
"locale": "en_US",
"ruleResults": {
"AvoidBadRequests": {
"localizedRuleName": "Avoid bad requests",
"ruleImpact": 0.0
},
"MinifyJavaScript": {
"localizedRuleName": "Minify JavaScript",
"ruleImpact": 0.1417,
"urlBlocks": [
{
"header": {
"format": "Minifying the following JavaScript resources could reduce their size by $1 ($2% reduction).",
"args": [
{
"type": "BYTES",
"value": "1.3KiB"
},
{
"type": "INT_LITERAL",
"value": "0"
}
]
},
"urls": [
{
"result": {
"format": "Minifying $1 could save $2 ($3% reduction).",
"args": [
{
"type": "URL",
"value": "http://code.google.com/js/codesite_tail.pack.04102009.js"
},
{
"type": "BYTES",
"value": "717B"
},
{
"type": "INT_LITERAL",
"value": "1"
}
]
}
},
{
"result": {
"format": "Minifying $1 could save $2 ($3% reduction).",
"args": [
{
"type": "URL",
"value": "http://www.gmodules.com/ig/proxy?url\u003dhttp%3A%2F%2Fjqueryjs.googlecode.com%2Ffiles%2Fjquery-1.2.6.min.js"
},
{
"type": "BYTES",
"value": "258B"
},
{
"type": "INT_LITERAL",
"value": "0"
}
]
}
}
]
}
]
},
"SpriteImages": {
"localizedRuleName": "Combine images into CSS sprites",
"ruleImpact": 0.0
}
}
},
"version": {
"major": 1,
"minor": 11
}
};
Now, I'm trying to write a function that iterates through all of the ruleResults objects and returns an array of the localizedRuleName properties. According to the JSON, ruleResults has three member objects (AvoidBadRequests, MinifyJavaScript, and SpriteImages). Each of these has a localizedRuleName property I'm trying to access, but when I print out my array, it's blank. Here's how I've written my function:
function ruleList(results) {
var ruleArray = [];
for(var ruleName in results.formattedResults.ruleResults){
ruleArray[counter] = results.formattedResults.ruleResults[ruleName].localizedRuleName;
}
return ruleArray;
}
console.log(ruleList(psinsights));
Can you guys help me get on the right track? I used basically this same method to iterate through the pageStats of the JSON and it worked perfectly. I'm not sure why I can't get it to work with these deeper nested objects and properties.
your problem is not your iteration, but your undefined variable "counter".
Instead of using a counter can use the "push" function:
function ruleList(results) {
var ruleArray = [];
for(var ruleName in results.formattedResults.ruleResults){
ruleArray.push(results.formattedResults.ruleResults[ruleName].localizedRuleName);
}
return ruleArray;
}
fiddle: https://jsfiddle.net/fo9h56gh/
Hope this helps.
you're probably getting a javascript error since counter is not defined. you can try this:
function ruleList(results) {
var ruleArray = [];
var counter = 0;
for(var ruleName in results.formattedResults.ruleResults){
ruleArray[counter] = results.formattedResults.ruleResults[ruleName].localizedRuleName;
counter++;
}
return ruleArray;
}

Categories

Resources