Hopefully someone can help me out here.
I am building an angular app with SQLite database which stores existing values. I need to compare these values from a json array received over http.
They should be matched by code, I want to compare the existing values with the update values add the property "active" = 1 otherwise active = 0 .
I tried a double foreach loop below, but I guess what's happening is the index is off so the results are not accurate in my actual application.
I have lodash available if there is some way to do this using that.
Any help would be much appreciated.
How can I get the following output
/*epected output
[{
"name": "Person 1"
"code": '001',
"active": '1'
},
{
"name": "Person 2"
"code": '002',
"active": '1'
},
{
"name": "Person 3"
"code": '003',
"active": '0' // note active 0 since doesnt exist in exsting
}
]*/
and what I tried along with 500 other things.
const existing = [{
"name": "Person 1",
"code": '001',
},
{
"name": "Person 2",
"code": '002',
},
];
const update = [{
"name": "Person 1",
"code": '001',
},
{
"name": "Person 2",
"code": '002',
},
{
"name": "Person 3",
"code": '003',
},
];
existing.forEach(element => {
update.forEach(test => {
if (element.code === test.code) {
element.avtive = true;
} else {
element.avtive = false;
}
});
return element;
});
console.log(existing);
/*epected output
[{
"name": "Person 1"
"code": '001',
"active": '1'
},
{
"name": "Person 2"
"code": '002',
"active": '1'
},
{
"name": "Person 3"
"code": '003',
"active": '0' // note active 0 since doesnt exist in exsting
}
]*/
Here is what should work for you. All existing code are extracted and then, for each updated value it is checked whether code exists in existingCodes array.
const existingCodes = existing.map((e) => e.code);
const result = updated.map((e) => ({
...e,
active: existingCodes.includes(e.code) ? '1' : '0'
});
If includes doesn't work for you on IE, you can replace this line existingCodes.includes(e.code) with existingCodes.filter((code) => code === e.code).length.
I like #radovix answer above, which worked for me, I came up with something slightly more long-winded, but which gives the same end result, but also separate lists of active and inactive:
let active = update.filter(item =>{
return existing.find(exist=> exist.code == item.code);
});
let inactive = update.filter(item =>{
return !existing.find(exist=> exist.code == item.code);
});
active = active.map(item=>({...item, active: '1'}));
inactive= inactive.map(item=>({...item, active: '0'}));
const merged = [...this.active, ...this.inactive];
You can see both ways working here: https://stackblitz.com/edit/angular-merge-arrays-update-property
You can use reduce, find and remove item from update array as
let result= existing.reduce((acc, item)=>{
let found = update.find(c => c.name == item.name);
if (found != undefined) {
const index = update.indexOf(found);
if (index > -1) {
update.splice(index, 1);
}
}
item.active = true;
acc.push(item);
return acc;
},[]);
update.map(c=> c.active = false);
//console.log(update)
result = result.concat(update);
console.log(result);
const existing = [{
"name": "Person 1",
"code": '001',
},
{
"name": "Person 2",
"code": '002',
},
];
const update = [{
"name": "Person 1",
"code": '001',
},
{
"name": "Person 2",
"code": '002',
},
{
"name": "Person 3",
"code": '003',
},
];
let result= existing.reduce((acc, item)=>{
let found = update.find(c => c.name == item.name);
if (found != undefined) {
const index = update.indexOf(found);
if (index > -1) {
update.splice(index, 1);
}
}
item.active = true;
acc.push(item);
return acc;
},[]);
update.map(c=> c.active = false);
//console.log(update)
result = result.concat(update);
console.log(result);
Related
So there is array of objects of below format
let inputs = [
{
"id": "614344d9d9c21c0001e6af2e",
"groupName": "Unassigned",
"parentGroup": "null"
},
{
"id": "614447da152f69c3c1d52f2e",
"groupName": "P1",
"parentGroup": "null"
},
{
"id": "614447da152f69c3c1d52f38",
"groupName": "K1",
"parentGroup": "C1"
},
{
"id": "614447da152f69c3c1d52f3e",
"groupName": "A2",
"parentGroup": "C2"
},
{
"id": "614447da152f69c3c1d52f40",
"groupName": "G1",
"parentGroup": "P2"
},
{
"id": "614447da152f69c3c1d52f46",
"groupName": "F1",
"parentGroup": "null"
},
{
"id": "614447da152f69c3c1d52f30",
"groupName": "P2",
"parentGroup": "null"
},
{
"id": "614447da152f69c3c1d52f36",
"groupName": "C2",
"parentGroup": "P1"
},
{
"id": "614447da152f69c3c1d52f3c",
"groupName": "A1",
"parentGroup": "C2"
},
{
"id": "614447da152f69c3c1d52f34",
"groupName": "C1",
"parentGroup": "P1"
},
{
"id": "614447da152f69c3c1d52f32",
"groupName": "P3",
"parentGroup": "null"
},
{
"id": "614447da152f69c3c1d52f3a",
"groupName": "K2",
"parentGroup": "C1"
},
{
"id": "614447da152f69c3c1d52f42",
"groupName": "GG1",
"parentGroup": "G1"
},
{
"id": "614447da152f69c3c1d52f44",
"groupName": "GGG1",
"parentGroup": "GG1"
}
]
i am trying to create a tree structure of format
{name:'p1',children:[{name:'c1':children:[]}]}
so i sorted all the elements of given array considering element with parentGroup as "null" to be at the top of the array.
let finalArr = [];
inputs.sort((a,b)=> (a.parentGroup === "null") ? -1 : 1);
And for each element of the inputs array, i was iterating below logic
inputs.forEach(ele => {
if(ele.parentGroup === "null"){
let child= {name:ele.groupName,children:[]};
finalArr.push(child);
}else{
finalArr.forEach(item => {
this.findNode(item,ele);
})
}
});
If the 'parentGroup' of element is "null", then create a leaf kind of obj and push the element to 'finalArr' array
Else, then iterate across all the elements of 'finalArr' over a recursion function
public findNode(ele, obj){
if(ele.children.length === 0){
if(ele.name === obj.parentGroup){
let child = {name:obj.groupName, children:[]};
ele.children.push(child);
}
}else{
let j = ele.children.length-1;
this.findNode(ele.children[j--],obj);
}
}
This recursion function will check the element has children or not, if no children, then compare the parentGroup of given obj, with name of element from 'FinalArr'.
if so ,push the current obj to the children of the element of finalArr.
else, that is, when children has more elements, the same recursion will be triggered until depth of the element is reached.
With this i tought i would make a tree structure with given inputs array, but when a parent has more children, of same level, this logic fails,
so the inputs array has 'c1' which is a child of 'p1', but nly the child 'c2' resides, not sure the what is that i missed.
You could take a standard algorithm for getting a tree with given data
const
getTree = (data, id, parent, root, fn = o => o) => {
var t = {};
data.forEach(o => ((t[o[parent]] ??= {}).children ??= []).push(Object.assign(t[o[id]] = t[o[id]] || {}, fn(o))));
return t[root].children;
},
data = [{ id: "614344d9d9c21c0001e6af2e", groupName: "Unassigned", parentGroup: "null" }, { id: "614447da152f69c3c1d52f2e", groupName: "P1", parentGroup: "null" }, { id: "614447da152f69c3c1d52f38", groupName: "K1", parentGroup: "C1" }, { id: "614447da152f69c3c1d52f3e", groupName: "A2", parentGroup: "C2" }, { id: "614447da152f69c3c1d52f40", groupName: "G1", parentGroup: "P2" }, { id: "614447da152f69c3c1d52f46", groupName: "F1", parentGroup: "null" }, { id: "614447da152f69c3c1d52f30", groupName: "P2", parentGroup: "null" }, { id: "614447da152f69c3c1d52f36", groupName: "C2", parentGroup: "P1" }, { id: "614447da152f69c3c1d52f3c", groupName: "A1", parentGroup: "C2" }, { id: "614447da152f69c3c1d52f34", groupName: "C1", parentGroup: "P1" }, { id: "614447da152f69c3c1d52f32", groupName: "P3", parentGroup: "null" }, { id: "614447da152f69c3c1d52f3a", groupName: "K2", parentGroup: "C1" }, { id: "614447da152f69c3c1d52f42", groupName: "GG1", parentGroup: "G1" }, { id: "614447da152f69c3c1d52f44", groupName: "GGG1", parentGroup: "GG1" }],
tree = getTree(data, 'groupName', 'parentGroup', null, ({ groupName: name }) => ({ name }));
console.log(tree);
.as-console-wrapper { max-height: 100% !important; top: 0; }
I think the issue is how finalArr is used to generate the html elements.
When doing console.log(finalArr) it looks like the code block below. So it seems to me like the code you have to build the structure of finalArr is working fine.
// console.log(finalArr)
[
{ "name": "P3", "children": [] },
{
"name": "P2",
"children": [
{
"name": "G1",
"children": [
{ "name": "GG1", "children": [
{ "name": "GGG1", "children": [] }
]
}
]
}
]
},
{ "name": "F1", "children": [] },
{
"name": "P1",
"children": [
{ "name": "C2", "children": [
{ "name": "A1", "children": [] }
]
}
]
},
{ "name": "Unassigned", "children": [] }
]
EDIT
As OP mentioned in the comment C1 was missing. I've introduced a root element that will have the finalArr as its children and changed the findNode to use a for loop instead of forEach. In this way we can also break when we find the node and not continue recursing.
As part of the initial sorting we will sort the inputs by parentGroup so we ensure that a childs parent is added in the tree structure before we try to find it with findNode.
I believe this produces the correct result:
inputs.sort((a, b) => (a.parentGroup === "null" ? -1 : 1));
// Sort by parentGroup
let root = inputs.pop();
let inputsDescending = [root];
let max = inputs.length * inputs.length;
let c = 0;
while (inputs.length > 0 && max > c) {
const child = inputs.pop();
const hasParentGroup = inputsDescending.find(
(parent) => parent.groupName === child.parentGroup
);
if (hasParentGroup || child.parentGroup === "null") {
inputsDescending.push(child);
} else {
inputs.unshift(child);
}
}
let rootEle = { name: "root", children: [] };
inputsDescending.forEach((obj) => {
if (obj.parentGroup === "null") {
let child = { name: obj.groupName, children: [] };
rootEle.children.push(child);
} else {
findNode(rootEle, obj);
}
});
function findNode(ele, obj) {
if (ele.name === obj.parentGroup) {
let child = { name: obj.groupName, children: [] };
ele.children.push(child);
return true;
} else {
const c = ele.children.length;
if (c > 0) {
for (let i = 0; c > i; i++) {
const found = findNode(ele.children[i], obj);
if (found) break;
}
}
}
}
const finalArr = rootEle.children;
Now finalArr looks like this:
[
{ "name": "Unassigned", "children": [] },
{
"name": "P1",
"children": [
{
"name": "C1",
"children": [
{ "name": "K1", "children": [] },
{ "name": "K2", "children": [] }
]
},
{
"name": "C2",
"children": [
{ "name": "A2", "children": [] },
{ "name": "A1", "children": [] }
]
}
]
},
{ "name": "F1", "children": [] },
{
"name": "P2",
"children": [
{ "name": "G1", "children": [
{ "name": "GG1", "children": [] }
]
}
]
},
{ "name": "P3", "children": [] }
]
I have this kind of table (or data structure)
There is parentIdeaId that refers to the id in ideas table itself.
Here's my unstructured data (please bear in mind this is the existing data in the database, not data that is already as it is so I have to query this first under some condition)
[{
"id": "1",
"title": "Title 1",
"parentIdeaId": null
},{
"id": "2",
"title": "Title 2",
"parentIdeaId": 1
},{
"id": "3",
"title": "Title 3",
"parentIdeaId": 2
},{
"id": "4",
"title": "Title 4",
"parentIdeaId": null
}]
I also made a function to find the data (I'm using Prisma in my real code)
function find({ id }) {
return prisma.idea.findUnique({
where: {
id
}
});
}
And a function to find the children
function responseIdeas({ parentIdeaId }) {
return prisma.idea.findMany({
where: {
parentIdeaId
}
});
}
I want the data to be filtered only linked data (by their parentIdeaId) so if I query the id "1" the result would be
[{
"id": "1",
"title": "Title 1",
"parentIdeaId": null
},{
"id": "2",
"title": "Title 2",
"parentIdeaId": 1
}{
"id": "3",
"title": "Title 3",
"parentIdeaId": 2
}]
The id: "4" isn't inserted because it's not related by its parent
Here's what I made:
const data = [
{
id: "1",
title: "Title 1",
parentIdeaId: null
},
{
id: "2",
title: "Title 2",
parentIdeaId: 1
},
{
id: "3",
title: "Title 3",
parentIdeaId: 2
},
{
id: "4",
title: "Title 4",
parentIdeaId: null
}
];
function find({ id }) {
return data.find(e => e.id === id);
}
function responseIdeas({ parentIdeaId }) {
return data.filter(e => e.parentIdeaId == parentIdeaId);
}
async function detail({ id }) {
const findChildren = async ({ id }) => {
const idea = await find({ id });
const responses = await responseIdeas({ parentIdeaId: id });
if (responses.length !== 0) {
const resolveResponses = await Promise.all(
responses.map(async ({ id }) => findChildren({ id }))
);
return [idea, ...resolveResponses];
}
return { ...idea };
};
return findChildren({ id });
}
async function run() {
const result = await detail({ id: "1" });
console.dir(result, { depth: null });
}
run();
But it ended up being like this
[
{
"id": "1",
"title": "Title 1",
"parentIdeaId": null
},
[
{
"id": "2",
"title": "Title 2",
"parentIdeaId": 1
},
{
"id": "3",
"title": "Title 3",
"parentIdeaId": 2
}
]
]
Where did I mess up? Thanks
findChildren potentially returns an array of arrays due to the fact that your returning Promise.all() -> which is a array of promises and some of those promises can be arrays.
So you can use concat to merge the result into the main array e.g like this https://codesandbox.io/s/quizzical-sun-c4khx?file=/src/index.js
I currently store a structure in a javascript Array with nested objects. The structure does not have a parentId parameter which I do need to get the parent of a nested object. The current structure outputs:
[{
"id":1000,
"pageIndex":0,
"type":"page",
"label":"Page 1",
"rows":[
{
"id":1002,
"type":"row 1",
"layout":{
"gutters":true,
"wrapping":false,
"guttersDirect":false,
"parentId":1002
},
"columns":[
{
"id":1003,
"type":"col 1",
"layout":{
"size":3,
"outOf":12,
"parentId":1003
}
},
{
"id":1004,
"type":"col 2",
"layout":{
"size":3,
"outOf":12,
"parentId":1004
},
"elements":[
{
"id":1006,
"type":"text",
"label":"Account ID"
}
]
},
{
"id":1005,
"type":"col 3",
"layout":{
"size":6,
"outOf":12,
"parentId":1005
}
}
]
}
]
}]
I need a function that updates all nested objects' parentId attribute with the parent nested object's id.
I have the following function
_PREV_PARENT_ID = null;
assignParentIds(object){
Object.keys(object).forEach(key => {
console.log(`key: ${key}, value: ${object[key]}`)
if(key === "id"){
this._PREV_PARENT_ID = object[key];
}else if (typeof object[key] === 'object') {
if(!!this._PREV_PARENT_ID){
object[key]['parentId'] = this._PREV_PARENT_ID;
}
this.assignParentIds(object[key])
}
});
}
However, this function fails to set parent ids correctly for items in array
[
{
"id":1000,
"pageIndex":0,
"type":"page",
"label":"Page 1",
"rows":[
{
"id":1002,
"parentId":1000,
"type":"row 1",
"layout":{
"gutters":true,
"wrapping":false,
"guttersDirect":false,
"parentId":1002
},
"columns":[
{
"id":1003,
"parentId":1002, <--- Correct
"type":"col 1",
"layout":{
"size":3,
"outOf":12,
"parentId":1003
}
},
{
"id":1004,
"parentId":1003, <--- In-Correct
"type":"col 2",
"layout":{
"size":3,
"outOf":12,
"parentId":1004
},
"elements":[
{
"id":1006,
"parentId":1004,
"type":"text",
"label":"Account ID"
}
]
},
{
"id":1005,
"parentId":1006, <--- In-Correct
"type":"col 3",
"layout":{
"size":6,
"outOf":12,
"parentId":1005
}
}
]
}
]
}
]
I thought about also potentially ditching parentId attribute and instead to use a function that would return the parent nested, however it also suffers from the same issue (if I call the function on id = 1004, it returns the previous item in the array with id = 1003 instead of returning the object with id 1002.
_PARENT_OBJECT = null;
findParentByChildId(o, id) {
if( o.id === id ){
return o;
}else{
if(o.hasOwnProperty('id')){
this._PARENT_OBJECT = o;
}
}
var result, p;
for (p in o) {
if( o.hasOwnProperty(p) && typeof o[p] === 'object' ) {
result = this.findParentByChildId(o[p], id);
if(result){
return this._PARENT_OBJECT;
}
}
}
return result;
}
Since the use case is about using drag and drop functionality, the parentId will often be updated and seems like an uneccesary extra attribute that we need to keep track of, it would be best if I had a way to call a function findParentByChildId().
What would be the best way to manage this?
I wanted to take a chance to figure it out. I've made a walker function which goes through every level and array and brings the id of the previous level with it. Then when it gets a match on an id it returns the parent id you are looking for. Or when it has no match it returns null.
const data = [{
"id": 1000,
"pageIndex": 0,
"type": "page",
"label": "Page 1",
"rows": [{
"id": 1002,
"type": "row 1",
"layout": {
"gutters": true,
"wrapping": false,
"guttersDirect": false,
"parentId": 1002
},
"columns": [{
"id": 1003,
"type": "col 1",
"layout": {
"size": 3,
"outOf": 12,
"parentId": 1003
}
},
{
"id": 1004,
"type": "col 2",
"layout": {
"size": 3,
"outOf": 12,
"parentId": 1004
},
"elements": [{
"id": 1006,
"type": "text",
"label": "Account ID"
}]
},
{
"id": 1005,
"type": "col 3",
"layout": {
"size": 6,
"outOf": 12,
"parentId": 1005
}
}
]
}]
}];
const walkTree = (entry, matchId, parentId = null) => {
let result = null;
for (const { id, ...rest } of entry) {
if (matchId === id) {
return parentId;
}
parentId = id;
for (const value of Object.values(rest)) {
if (Array.isArray(value)) {
result = walkTree(value, matchId, parentId);
break;
}
}
}
return result;
};
const findParentByChildId = id => walkTree(data, id);
// ID's to look up parents of.
const lookupParents = [
1000,
1002,
1003,
1004,
1005,
1006,
1007
];
// Log results.
for (const id of lookupParents) {
console.log(`Parent of ${id}:`, findParentByChildId(id));
}
{
"id": "1",
"name": "root",
"children": [
{
"id": "1.1",
"name": "Child 1",
"children": [
{
"id": "1.1.1",
"name": "Child 1-1",
"children": [
{
"id": "1-1-1",
"name": "Child 1-1-1",
"children": [
]
}
]
},
{
"id": "1.1.2",
"name": "Child 1-2",
"children": [
]
},
{
"id": "1.1.3",
"name": "Child 1-3",
"children": [
]
}
]
},
{
"id": "1.2",
"name": "Child 2",
"children": [
{
"id": "1.2.1",
"name": "Child 2-2",
"children": [
]
}
]
}
]
}
This is the JSON string as the response. Had to fetch for the parent elements recursively all the parents id.
For instance, input is 1.2.1 then it returns [1.2]
input is 1.1.3 then it returns [1.1, 1]
How can I achieve this?
Just a simple recursion using dfs
const data = JSON.parse('{"id":"1","name":"root","children":[{"id":"1.1","name":"Child 1","children":[{"id":"1.1.1","name":"Child 1-1","children":[{"id":"1-1-1","name":"Child 1-1-1","children":[]}]},{"id":"1.1.2","name":"Child 1-2","children":[]},{"id":"1.1.3","name":"Child 1-3","children":[]}]},{"id":"1.2","name":"Child 2","children":[{"id":"1.2.1","name":"Child 2-2","children":[]}]}]}')
function dfs (target, node) {
if (node.id === target) { return node.id }
if (!node.children) { return false } // we could even skip that line since in your data you seem to have an empty array
const has = node.children.find(c => dfs(target, c))
return has && [node.id].concat(has.id)
}
console.log(dfs('1.2.1', data))
console.log(dfs('1.1.3', data))
You could take an iterative and recursive approach and
chcek if the given data is not an object, then return
check for the id and if found return an empty array, which gets filled by the calling function
iterate children with a short circuit on found and call the function again.
function getParentIds(object, id) {
var ids;
if (!object || typeof object !== 'object') return; // no object
if (object.id === id) return []; // id found
return object.children.some(o => ids = getParentIds(o, id)) // call recursive function
? [...ids, object.id] // if found, take ids
: undefined; // otherwise return falsy
}
var data = { id: "1", name: "root", children: [{ id: "1.1", name: "Child 1", children: [{ id: "1.1.1", name: "Child 1-1", children: [{ id: "1-1-1", name: "Child 1-1-1", children: [] }] }, { id: "1.1.2", name: "Child 1-2", children: [] }, { id: "1.1.3", name: "Child 1-3", children: [] }] }, { id: "1.2", name: "Child 2", children: [{ id: "1.2.1", name: "Child 2-2", children: [] }] }] };
console.log(getParentIds(data, '1.2.1')); // ['1.2']
console.log(getParentIds(data, '1.1.3')); // ['1.1', '1']
console.log(getParentIds(data, 'foo')); // undefined
.as-console-wrapper { max-height: 100% !important; top: 0; }
You would have to parse the complete object to recursively inject the parent ids in child objects. Something like this will do the thing.
function injectParents(data, parents) {
if(!parents) {
parents = [];
}
parents.push(data.id);
data.children.map(child=>{
child.parents = parents;
if(child.children && child.children.length>0) {
child = injectParents(child, Array.from(parents));
}
return child;
});
return data;
}
Then you would normally call it like
const injectedResponse = injectParents(response, null);
you can use
for(let x in arrayName){
//here you can access the json
console.log(arayName(x).id)
}
Is this what are you looking for?
//Input
let input = '1.2.1';
//Data
data = JSON.parse('{"id":"1","name":"root","children":[{"id":"1.1","name":"Child 1","children":[{"id":"1.1.1","name":"Child 1-1","children":[{"id":"1-1-1","name":"Child 1-1-1","children":[]}]},{"id":"1.1.2","name":"Child 1-2","children":[]},{"id":"1.1.3","name":"Child 1-3","children":[]}]},{"id":"1.2","name":"Child 2","children":[{"id":"1.2.1","name":"Child 2-2","children":[]}]}]}')
//Main function start here
function findIdWhereChild(data, input) {
if (data.children?.find(x => x.id == input)) {
return data.id;
}
else {
if (data.children.length > 0) {
for (let i = 0; i < data.children.length; i++) {
let findalResult = findIdWhereChild(data.children[i], input);
if (findalResult) {
return findalResult;
};
};
} else {
return undefined;
}
}
};
//Execution LOGs
console.log(findIdWhereChild(data, input));
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"}]