Get value based on sub-array unique value - javascript

My JSON data looks like this:
{
"data": [{
"id": "1",
"blogTitle": "How to plant a tree?",
"categories": [{
"CategoryID": "10",
"CategoryTitle": "Apple Tree"
}, {
"CategoryID": "11",
"CategoryTitle": "Mango Tree"
}, {
"CategoryID": "42",
"CategoryTitle": "Banana Tree"
}]
},
{
"id": "2",
"blogTitle": "How to make Juice?",
"categories": [{
"CategoryID": "71",
"CategoryTitle": "Apple Juice"
}, {
"CategoryID": "72",
"CategoryTitle": "Mango Juice"
}, {
"CategoryID": "73",
"CategoryTitle": "Banana Juice"
}]
}
]
}
What I want is to get the value of id by passing the value of CategoryID
For example: if I send 10 then I should get 1 in return because "CategoryID": "10" is in the same block with "id": "1"
Each CategoryID is unique resulting in a unique value of id
What did I do?
Closest I came up with was using the array.filter() but I am able to filter id value give the value of id but how do I get the value of id, given CategoryID
Could someone please kindly help me?

You can integrate your data, then use Array#some like this.
const yourObject = {"data":[{"id":"1","blogTitle":"How to plant a tree?","categories":[{"CategoryID":"10","CategoryTitle":"Apple Tree"},{"CategoryID":"11","CategoryTitle":"Mango Tree"},{"CategoryID":"42","CategoryTitle":"Banana Tree"}]},{"id":"2","blogTitle":"How to make Juice?","categories":[{"CategoryID":"71","CategoryTitle":"Apple Juice"},{"CategoryID":"72","CategoryTitle":"Mango Juice"},{"CategoryID":"73","CategoryTitle":"Banana Juice"}]}]};
const find_ID_BasedOn_GivenCategoryId = (categoryId) => {
for(const item of yourObject.data){
if(item.categories && item.categories.some(r => r.CategoryID == categoryId))
return item.id;
}
return "Not found";
}
console.log(find_ID_BasedOn_GivenCategoryId(11));
console.log(find_ID_BasedOn_GivenCategoryId(71));
console.log(find_ID_BasedOn_GivenCategoryId(999));
Simpler approach: using Array#find
const yourObject = {"data":[{"id":"1","blogTitle":"How to plant a tree?","categories":[{"CategoryID":"10","CategoryTitle":"Apple Tree"},{"CategoryID":"11","CategoryTitle":"Mango Tree"},{"CategoryID":"42","CategoryTitle":"Banana Tree"}]},{"id":"2","blogTitle":"How to make Juice?","categories":[{"CategoryID":"71","CategoryTitle":"Apple Juice"},{"CategoryID":"72","CategoryTitle":"Mango Juice"},{"CategoryID":"73","CategoryTitle":"Banana Juice"}]}]};
const find_ID_BasedOn_GivenCategoryId = (categoryId) => {
const result = yourObject.data.find(item =>
item.categories && item.categories.some(r => r.CategoryID == categoryId));
return result ? result.id : "Not found";
}
console.log(find_ID_BasedOn_GivenCategoryId(11));
console.log(find_ID_BasedOn_GivenCategoryId(71));
console.log(find_ID_BasedOn_GivenCategoryId(999));

You can use find with a combination of some for checking the categoryID that you want, for example:
const data = {
"data": [{
"id": "1",
"blogTitle": "How to plant a tree?",
"categories": [{
"CategoryID": "10",
"CategoryTitle": "Apple Tree"
}, {
"CategoryID": "11",
"CategoryTitle": "Mango Tree"
}, {
"CategoryID": "42",
"CategoryTitle": "Banana Tree"
}]
},
{
"id": "2",
"blogTitle": "How to make Juice?",
"categories": [{
"CategoryID": "71",
"CategoryTitle": "Apple Juice"
}, {
"CategoryID": "72",
"CategoryTitle": "Mango Juice"
}, {
"CategoryID": "73",
"CategoryTitle": "Banana Juice"
}]
}
]
};
const findId = (categoryID, { data }) => {
const foundItem = data.find(({ categories }) =>
categories.some(({ CategoryID }) => CategoryID == categoryID)
);
return foundItem ? foundItem.id : null;
}
console.log(findId(71, data))

find + some
var data = [
{
id: "1",
blogTitle: "How to plant a tree?",
categories: [
{
CategoryID: "10",
CategoryTitle: "Apple Tree"
},
{
CategoryID: "11",
CategoryTitle: "Mango Tree"
},
{
CategoryID: "42",
CategoryTitle: "Banana Tree"
}
]
},
{
id: "2",
blogTitle: "How to make Juice?",
categories: [
{
CategoryID: "71",
CategoryTitle: "Apple Juice"
},
{
CategoryID: "72",
CategoryTitle: "Mango Juice"
},
{
CategoryID: "73",
CategoryTitle: "Banana Juice"
}
]
}
];
const findId = (id) => {
return data?.find((item) =>
item?.categories?.some((i) => i?.CategoryID === id)
)?.id;
};
console.log(findId("10")); //1

Related

How can I concatenate this type of JSON in javascript?

How can I concatenate this json to obtain it:
complements = ["XYZ 3, CDE TR, AAA 5", "", "NDP 3, DDD FR"] ?
Each address can contain a set of complements which must be concatenated and separated by a comma.
P.s: I'm using javascript.
P.s2: Complements can be null like in the second group in JSON.
[
{
"postalcode": "1234",
"street": "ABC",
"number": "1",
"complement": [
{
"type": "B",
"name": "XYZ",
"description": "3"
},
{
"type": "C",
"name": "CDE",
"description": "TR"
},
{
"type": "D",
"name": "AAA",
"description": "5"
}
]
},
{
"postalcode": "444",
"street": "No complements",
"number": "5"
},
{
"postalcode": "2222",
"street": "BBB",
"number": "2",
"complement": [
{
"type": "E",
"name": "NDP",
"description": "3"
},
{
"type": "F",
"name": "DDD",
"description": "FR"
}
]
}
];
My code I'm getting this.complementsList.forEach is not a function.
getComplement(addressesResponse){
this.complementsList = JSON.parse(addressesResponse);
this.complementsList.forEach((item) => {
Object.defineProperty(item, 'complements', {
get: function() {
return this.complement.map((c) => `${c.name} ${c.description}`).join(', '); }
})
});
Source: https://salesforce.stackexchange.com/questions/367713/how-to-render-a-json-in-the-same-line-lwc
how i solved it :
arr.map((x)=>x.complement != null? (x.complement.map((y)=>y.name+' '+y.description)+"") :'');
Having a javascript object, you can go through the keys of the object and combine some of them into strings
It will look something like this:
const jsonObject = [{...}, {...}, ...]
const complements = [];
jsonObject.forEach((item) => {
let complement = item['complement'].reduce((result, currObj)
=> result += (currObj.name+' '+currObj.description), "");
complements.push(complement);
});
This is just an example. There are many ways to do it.

How to parse a json using es6?

I have below json as input
result = [
{
"category": "Social Media",
"sub_category": "Facebook"
},
{
"category": "Social Media",
"sub_category": "Instagram"
},
{
"category": "Tech",
"sub_category": "Angular"
},
{
"category": "Tech",
"sub_category": "Javascript"
}
]
i am trying to acive below json
{
"Social Media": [
"Facebook",
"Instagram"
],
"Tech": [
"Angular",
"Javascript"
]
}
Below code i tried to active this. Could anyone please help where i am doing wrong
let result = [{
"category": "Social Media",
"sub_category": "Facebook"
},
{
"category": "Social Media",
"sub_category": "Instagram"
},
{
"category": "Tech",
"sub_category": "Angular"
},
{
"category": "Tech",
"sub_category": "Javascript"
}
]
let data = [];
let categorySet = new Set();
result.forEach((val, key) => {
categorySet.add(val.category);
});
result.forEach((val, key) => {
let subCat = new Set();
categorySet.forEach((v, k) => {
if (v == val.category) {
let d = {};
d[val] = subCat.add(val.sub_category);
data.push(d)
}
})
});
console.log(data)
Your question has actually nothing to do with es6, but here is the code that could help:
const data = {}
let result = [{
"category": "Social Media",
"sub_category": "Facebook"
},
{
"category": "Social Media",
"sub_category": "Instagram"
},
{
"category": "Tech",
"sub_category": "Angular"
},
{
"category": "Tech",
"sub_category": "Javascript"
}
];
result.forEach((value) => {
data[value.category] = data[value.category] || []
data[value.category].push(value.sub_category)
});
console.log(data);
Not sure, why you wanted to use a Set, because a Set more close to an array, but what you want to get as a final result is an object
you can use lodash, try this example
result = [
{
"category": "Social Media",
"sub_category": "Facebook"
},
{
"category": "Social Media",
"sub_category": "Instagram"
},
{
"category": "Tech",
"sub_category": "Angular"
},
{
"category": "Tech",
"sub_category": "Javascript"
}
]
var groupJson= _.groupBy(result, function(result) {
return result.category;
});
console.log(groupJson);
<script src='https://cdn.jsdelivr.net/lodash/4.17.2/lodash.min.js'></script>
This would give the expected output:
let result = [{
"category": "Social Media",
"sub_category": "Facebook"
},
{
"category": "Social Media",
"sub_category": "Instagram"
},
{
"category": "Tech",
"sub_category": "Angular"
},
{
"category": "Tech",
"sub_category": "Javascript"
}
];
let data = {};
result.forEach((row) => {
if (!data[row.category]) {
data[row.category] = [];
}
if (!data[row.category].includes(row.sub_category)) {
data[row.category].push(row.sub_category);
}
});
console.log(data);

Grouping array nested value while comparing 2 objects

I am working in small react project & I am facing issue in grouping the data. Requirement is to group the id & its feature into a single row if same id is there in before & after object.
Json Data:
{
"before":{
"device": [
{
id:"1234",
price:"10,
features:[
{name:"samsung",price:"10"},
{name:"Apple",price:"20"}
]
},
{id:"2154",
price:"20,
features:[
{name:"samsung",price:"30"},
{name:"Moto",price:"40"}
]
]
},
"after":{
"device": [
{
id:"1234",
price:"50,
features:[
{name:"samsung",price:"20"},
{name:"Lenovo",price:"30"}
]
},
{id:"2158",
price:"40,
features:[
{name:"samsung",price:"30"}
]
]
}
}
Expected grouping to be shown in UI is shared in image.
I tried to get unique ids in one array and lopping through after array and comparing unique array id I am getting unique id to show but issue i am facing while grouping their related feature.
Can anyone please help me to get a best approach to handle this requirement.
Thanks
There are 3 things i'd suggest you:
1.) Please verify the data your'e posting is correct and in proper format, people won't be able to help if the data is incorrect.
2.) The UI display requirement should be simple enough.
Now, if you still want to achieve this requirement i believe the correct JSON and the merged output json will look something like below:
//Correct input data that you have:
var input = {
"before": {
"device": [
{
"id": "1234",
"price": "10",
"features": [
{
"name": "samsung",
"price": "10"
},
{
"name": "Apple",
"price": "20"
}
]
},
{
"id": "2154",
"price": "20",
"features": [
{
"name": "samsung",
"price": "30"
},
{
"name": "Moto",
"price": "40"
}
]
}
]
},
"after": {
"device": [
{
"id": "1234",
"price": "50",
"features": [
{
"name": "samsung",
"price": "20"
},
{
"name": "Lenovo",
"price": "30"
}
]
},
{
"id": "2158",
"price": "40",
"features": [
{
"name": "samsung",
"price": "30"
}
]
}
]
}
};
// Output JSON which you should need to show the desired output.
var output = {
"devices": [
{
"id": 1234,
"feature": [
{
"name": "1234",
"price": {
"before": 10,
"after": 50
}
},
{
"name": "samsung",
"price": {
"before": 10,
"after": 20
}
},
{
"name": "apple",
"price": {
"before": 10,
"after": 0
}
},
{
"name": "lenovo",
"price": {
"before": 0,
"after": 30
}
}
]
}
]
};
3.) Please try to get the desired output from input yourself as this will help you learn a lot of things in between, as suggested by some please use map, filter, forEach for your requirement.
Hope this helps. Thanks!
You could take a nested approach for grouping.
var data = { before: { device: [{ id: "1234", price: "10", features: [{ name: "samsung", price: "10" }, { name: "Apple", price: "20" }] }, { id: "2154", price: "20", features: [{ name: "samsung", price: "30" }, { name: "Moto", price: "40" }] }] }, after: { device: [{ id: "1234", price: "50", features: [{ name: "samsung", price: "20" }, { name: "Lenovo", price: "30" }] }, { id: "2158", price: "40", features: [{ name: "samsung", price: "30" }] }] } },
cols = Object.fromEntries(Object.keys(data).map(k => [k, 0])),
result = Object.values(Object.entries(data).reduce((r, [col, { device }]) => {
device.forEach(({ id, price, features }) => {
r[id] = r[id] || [{ id, ...cols }];
r[id][0][col] = price;
features.forEach(({ name, price }) => {
let temp = r[id].find(q => q.name === name);
if (!temp) r[id].push(temp = { name, ...cols });
temp[col] = price;
});
});
return r;
}, {}));
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }
You can use lodash library for grouping
https://lodash.com/docs/3.10.1#groupBy
Comparing 2 objects, and output equivalent values
var has = {"before":[{
name: 'Nokia',
os: 'Andriod',
features: {
camera: "200 MPixel Camera",
battery: "24 hours battery backup",
}
}],
"after":[{
name: 'Samsung',
os: 'Andriod',
features: {
camera: "200 MPixel Camera",
battery: "30 hours battery backup",
}
}]
};
function compare(Pro1, Pro2) {
var Val1 = Object.values(Pro1);
var Val2 = Object.values(Pro2);
var equivalent = [];
var keys = Object.keys(Pro1);
keys.forEach(k => {
if (Pro1.hasOwnProperty(k) && Pro2.hasOwnProperty(k)) {
if (typeof Pro1[k] === 'object') {
let recursiveResult = compare(Pro1[k], Pro2[k]);
equivalent.push(...recursiveResult);
} else if (Pro1[k] === Pro2[k]) {
equivalent.push(Pro1[k]);
}
}
});
return equivalent;
}
let equiv = compare(has["before"], has["after"]);
console.log(equiv);

Object transformation using a functional approach

I am reading a simple data set from a data.txt file. I would like to take this data and transform it into a specific object as per my example below. I have managed to get it into a somewhat usable JSON object but this is not ideal. I have included an example of the desired object.
Here is my app.js file:
let output = fs.readFileSync('./data.txt', 'UTF8')
.trim()
.split('\r\n')
.map((line) => line.split(';'))
.reduce((customers, line) => {
customers.push({
name: line[0],
product: [{
item: line[1],
serial: line[2],
year: line[3]
}]
})
return customers
}, [])
console.log(JSON.stringify(output, null, 2))
This currently the above NodeJs code returns the following array object:
[
{
"name": "Nancy",
"product": [
{
"item": "Macbook Pro",
"serial": "A34D05980FCD4303",
"year": "2019"
}
]
},
{
"name": "Nancy",
"product": [
{
"item": "iPad",
"serial": "O0403X3028423C92",
"year": "2015"
}
]
},
{
"name": "Nancy",
"product": [
{
"item": "iPhone",
"serial": "X3830238S3309230",
"year": "2017"
}
]
},
{
"name": "John",
"product": [
{
"item": "Macbook Pro",
"serial": "X2020J393983H380",
"year": "2013"
}
]
},
{
"name": "John",
"product": [
{
"item": "iPhone",
"serial": "X38320093X032309",
"year": "2015"
}
]
},
{
"name": "fluffikins",
"product": [
{
"item": "iMac",
"serial": "F392D392033X3232",
"year": "2013"
}
]
},
{
"name": "fluffikins",
"product": [
{
"item": "iPad",
"serial": "FE322230D3223S21",
"year": "2011"
}
]
}
]
What I am trying to do is get the below object returned - ideally still following the same functional approach:
[
{
"name": "Nancy",
"product": [
{
"item": "Macbook Pro",
"serial": "A34D05980FCD4303",
"year": "2019"
},
{
"item": "iPad",
"serial": "O0403X3028423C92",
"year": "2015"
},
{
"item": "iPhone",
"serial": "X3830238S3309230",
"year": "2017"
}
]
},
{
"name": "John",
"product": [
{
"item": "Macbook Pro",
"serial": "X2020J393983H380",
"year": "2013"
},
{
"item": "iPhone",
"serial": "X38320093X032309",
"year": "2015"
}
]
},
{
"name": "fluffikins",
"product": [
{
"item": "iMac",
"serial": "F392D392033X3232",
"year": "2013"
},
{
"item": "iPad",
"serial": "FE322230D3223S21",
"year": "2011"
}
]
}
]
Here is my mock data set that lives in data.txt
Nancy;Macbook Pro;A34D05980FCD4303;2019
Nancy;iPad;O0403X3028423C92;2015
Nancy;iPhone;X3830238S3309230;2017
John;Macbook Pro;X2020J393983H380;2013
John;iPhone;X38320093X032309;2015
fluffikins;iMac;F392D392033X3232;2013
fluffikins;iPad;FE322230D3223S21;2011
Instead of an array you can use Map in reduce as accumulator, use name as key in Map and club value of all keys, finally just get the values Map to get desired output
const data = `Nancy;Macbook Pro;A34D05980FCD4303;2019
Nancy;iPad;O0403X3028423C92;2015
Nancy;iPhone;X3830238S3309230;2017
John;Macbook Pro;X2020J393983H380;2013
John;iPhone;X38320093X032309;2015
fluffikins;iMac;F392D392033X3232;2013
fluffikins;iPad;FE322230D3223S21;2011`
const final = data.split('\n')
.map(v => v.split(';'))
.reduce((op, [name, item, serial, year]) => {
let obj = { item, serial, year }
if (op.has(name)) {
op.get(name).products.push(obj)
} else{
op.set(name,{name, products:[obj]})
}
return op
}, new Map())
console.log([...final.values()])
Here is a "functional version" that utilizes a Map to find duplicates in O(1):
(map => (
fs.readFileSync('./data.txt', 'UTF8')
.trim()
.split('\r\n')
.map((line) => line.split(';'))
.forEach(([name, item, serial, year]) =>
map.has(name)
? map.get(name).product.push({ item, serial, year })
: map.set(name, { name, product: [{ item, serial, year }] })
),
[...map.values()]
)(new Map)
But seriously, whats so bad about imperative style?:
const customers = new Map;
const entries = fs.readFileSync('./data.txt', 'UTF8')
.trim()
.split('\r\n');
for(const entry of entries) {
const [name, item, serial, year] = entry.split(";");
const product = { item, serial, year };
if(customers.has(name)) {
customers.get(name).product.push(product);
} else customers.set(name, { name, product: [product] });
}
const result = [...customers.values()];
You can modify the .reduce function to only add a new item to the array if there isn't one with that name. If there is, just add the product to that item's product array.
const data = `Nancy;Macbook Pro;A34D05980FCD4303;2019
Nancy;iPad;O0403X3028423C92;2015
Nancy;iPhone;X3830238S3309230;2017
John;Macbook Pro;X2020J393983H380;2013
John;iPhone;X38320093X032309;2015
fluffikins;iMac;F392D392033X3232;2013
fluffikins;iPad;FE322230D3223S21;2011`;
const result = data.trim()
.split('\n')
.map((line) => line.split(';'))
.reduce((customers, line) => {
const product = {
item: line[1],
serial: line[2],
year: line[3]
};
const customer = customers.find(({
name
}) => name === line[0]);
if (customer) {
customer.product.push(product);
} else {
customers.push({
name: line[0],
product: [product]
});
}
return customers
}, []);
console.log(result);

Use map and filter to handle items with same value

In the example below, I have an array of objects which contain some basic information about films - a film name and a personal rating.
Then i'm returning the duplicate values (using map and filter) to return new arrays and I can then count the number of items in that new array.
let films = [{
"name": "film 1",
"rating": "5",
}, {
"name": "film 2",
"rating": "1",
}, {
"name": "film 3",
"rating": "2",
}, {
"name": "film 4",
"rating": "2",
}, {
"name": "film 5",
"rating": "5",
}, {
"name": "film 6",
"rating": "4",
}];
let ratingsArray = films.map((element, i) => {
return element.rating;
})
let arr0 = ratingsArray.filter((rating) => {
return rating == 0;
})
let arr1 = ratingsArray.filter((rating) => {
return rating == 1;
})
let arr2 = ratingsArray.filter((rating) => {
return rating == 2;
})
let arr3 = ratingsArray.filter((rating) => {
return rating == 3;
})
let arr4 = ratingsArray.filter((rating) => {
return rating == 4;
})
let arr5 = ratingsArray.filter((rating) => {
return rating == 5;
});
console.log(arr0);
console.log(arr1);
console.log(arr2);
console.log(arr3);
console.log(arr4);
console.log(arr5);
This does actually work but it seems a very repetitive way of writing this code.
Can anyone please suggest a better that I could be doing this?
You could take an object and group the objects by rating.
var films = [{ name: "film 1", rating: "5", }, { name: "film 2", rating: "1", }, { name: "film 3", rating: "2", }, { name: "film 4", rating: "2", }, { name: "film 5", rating: "5", }, { name: "film 6", rating: "4", }],
ratings = Object.create(null);
films.forEach(o => (ratings[o.rating] = ratings[o.rating] || []).push(o));
console.log(ratings);
.as-console-wrapper { max-height: 100% !important; top: 0; }
You can write a function that you can use as the callback in filter. It works similarly to how lodash's pluck method worked. pluck accepts a property key, and value and returns a closure that's used as the callback function when filter iterates over the elements in the array.
let films = [
{ "name": "film 1", "rating": "5" },
{ "name": "film 2", "rating": "1" },
{ "name": "film 3", "rating": "2" },
{ "name": "film 4", "rating": "2" },
{ "name": "film 5", "rating": "5" },
{ "name": "film 6", "rating": "4" }
];
function pluck(key, value) {
return function (el) {
return el[key] === value;
}
}
const rating4 = films.filter(pluck('rating', '2'));
console.log(rating4);
You can then use this as you see fit, whether you want to loop over a set of ratings and store that information in an object, for example, but this is completely up to you. And you can use this function not just on this data set, but all sets where you need to pull out this kind of data.
let characters = [{
"name": "Batman",
"age": 62
}, {
"name": "Supergirl",
"age": 27
}, {
"name": "Tarzan",
"age": 102
}];
function pluck(key, value) {
return function (el) {
return el[key] === value;
}
}
const tarzan = characters.filter(pluck('age', 102));
console.log(tarzan);
One thing tho: you might benefit from having the ratings as integers rather than strings. One thing to consider moving forward.
You need to grouping the films by rating you can do using a object and arrays to store. See the example bellow:
let films = [{
"name": "film 1",
"rating": "5",
}, {
"name": "film 2",
"rating": "1",
}, {
"name": "film 3",
"rating": "2",
}, {
"name": "film 4",
"rating": "2",
}, {
"name": "film 5",
"rating": "5",
}, {
"name": "film 6",
"rating": "4",
}];
var filmsByRating = {};
//group films by rating
films.forEach((film) => {
if(!filmsByRating[film.rating])
filmsByRating[film.rating] = [];
filmsByRating[film.rating].push(film);
});
//print ratings and films
for(var i in filmsByRating){
console.log("Rating:", i);
console.log(filmsByRating[i]);
}
I'm going to combine concepts from other answers and suggestions therein, and generate an Array, using reduce. Some advantages of putting the ratings into an Array instead of an Object include that you will then be able to perform useful Array methods such as reverse or (custom) sort e.g. maybe you want to sort by the rating that has the most films associated with it.
var films = [
{ name: "film 1", rating: "5", },
{ name: "film 2", rating: "1", },
{ name: "film 3", rating: "2", },
{ name: "film 4", rating: "2", },
{ name: "film 5", rating: "5", },
{ name: "film 6", rating: "4", }
];
var ratings = films.reduce(function(result, film) {
var rating = parseInt(film.rating, 10);
var ratedFilms = result[rating] || [];
ratedFilms.push(film);
result[rating] = ratedFilms;
return result;
}, []);
ratings.forEach(function(rating, i) {
console.log(i + ": " + JSON.stringify(rating));
});
RESULT:
1: [{"name":"film 2","rating":"1"}]
2: [{"name":"film 3","rating":"2"},{"name":"film 4","rating":"2"}]
4: [{"name":"film 6","rating":"4"}]
5: [{"name":"film 1","rating":"5"},{"name":"film 5","rating":"5"}]

Categories