Multidimensional use of .map() array function in Javascript - javascript

I'm currently stuck in trying to transform one array to another using an array of headers as a key variable. Somewhat confusing to explain so I think the code might be better.
// Array received from backend
const projects = [
{id: 0001, name: "Test Project 1", projectType: "Quant"},
{id: 0002, name: "Test Project 2", projectType: "Qual"},
{id: 0003, name: "Test Project 3", projectType: "Quant"},
];
I use the first object of the array to create a new array for the headers using Object.keys(projects[0]).. So far so good
I would like to use the DataGrid from Material UI which requires a specific format for their rows and columns data structures. See below.
const columns-MUI = [
{
field: 'firstName',
headerName: 'First name',
width: 150,
editable: true,
},
{
field: 'lastName',
headerName: 'Last name',
width: 150,
editable: true,
},
];
const rows-MUI = [
{ id: 1, lastName: 'Snow', firstName: 'Jon', age: 35 },
{ id: 2, lastName: 'Lannister', firstName: 'Cersei', age: 42 },
{ id: 3, lastName: 'Lannister', firstName: 'Jaime', age: 45 },
{ id: 4, lastName: 'Stark', firstName: 'Arya', age: 16 },
]
I've managed to convert the headers from the result of Object.keys(projects[0]) to the desired column structure as defined by in columns-MUI with the following code when setting the state in a useEffect hook:
setNewColumns(tableHeaders?.map(( header, index ) => {
return {
field: index,
headerName: header,
width: 90
}
}));
Where I'm stuck is transforming the array from projects to rows-MUI because I somehow need to create both the key and value pair dynamically. This is what I've resulted in so far:
let tempProjectsList = [];
projectsList?.map(( project, index) => {
let projectObject = ''
tableHeaders.map(( header, index ) => {
const value = project[header] != null ? `"${project[header]}"` : ""
projectObject += `${header}:${value},`;
})
const parsedObject =`{${projectObject}}`;
tempProjectsList.push(parsedObject);
})
This process treats the key value pair as a string and parses the object once the iteration through the tableHeaders array is complete. There must be a more elegant solution though that I'm missing so I'd much appreciate the help.
I am certain that the "more elegant" solution begins like this but I think I reach the limits of my knowledge of Javascript arrays at this point:
setNewRows(projectsList?.map(( project, index) => {
return tableHeaders.map(( header, index) => {
})
}));
Let me know if this explanation isn't clear and I'll work on supplying demo of some description.

Related

Reduce an array of objects based on an object array property

I need help from some JavaScript/NodeJS experts. I'm using the v14 of NodeJS.
I would like to create a function that takes as an input this kind of array (let's say that it's a list of teams):
[
{
name: 'IT',
tags: ['Department', 'Section', 'Organizational']
},
{
name: 'Male',
tags: ['Gender', 'Organizational']
},
{
name: 'Foo',
tags: []
}
]
... and returns as an output a list of teams by tag name like this:
// Output:
{
Department: 'IT',
Section: 'IT',
Organizational: 'IT, Male',
Gender: 'Male'
}
The order of object keys as well as the order of the team names don't matter. I can do this quite easily with a few lines of code, but I'm quite sure that it would be easy to do using a few of our magic map(), reduce() functions and other utilities like spreading.
Anybody can help me achieve this in an optimized way?
Thank you!
Try this:
const organization = [
{
name: 'IT',
tags: ['Department', 'Section', 'Organizational']
},
{
name: 'Male',
tags: ['Gender', 'Organizational']
},
{
name: 'Foo',
tags: []
}
]
const result = organization.reduce((acum, current) => {
current.tags.forEach(tag => {
if(acum[tag]) acum[tag] = `${acum[tag]}, ${current.name}`
else acum[tag] = current.name
})
return acum
},{})
console.log(result)

how to loop through multiple arrays inside an array and filter a value from it-Javascript

I'm using EXTJS framework for my code.
below is my array structure:
data = [{
id: 22,
rows: [{
id: "673627",
name: "ABS",
address: "536street"
}, {
id: "333",
name: "TEST$$",
address: "536street"
}, {
id: "999",
name: "TEST$$",
address: "536street"
}]
}, {
id: 33,
rows: [{
id: "899",
name: "TES",
address: "536street"
}, {
id: "333",
name: "TEST$$",
address: "536street"
}, {
id: "999",
name: "TES673",
address: "536street"
}]
}]
Now I want to filter the name from this array, whose value I'm comparing with say "TEST$$".
I'm doing this;
Ext.each(data, function(item) {
filter = item.rows.filter(function(name) {
return name.name === "TEST$$";
}, this);
}, this);
console.log(filter);
In this case, it returns only 1 match, where as I have 3 matches for this particular value. It returns the match from the last item in the data array and hence I dont get all the matching values, any idea how this can be looped to get all values matching?
thx!
You're reassigning the filter variable on every iteration over the data array:
filter = item.rows.filter(function(name) {
return name.name === "TEST$$";
}, this);
On the last iteration, there is only one match, the one with id of 333, so that's the only one that you see after running the Ext.each. Try pushing to an external array that doesn't get overwritten instead:
const testItems = [];
Ext.each(data, function(item) {
const filtered = item.rows.filter(row => row.name === "TEST$$")
testItems.push(...filtered);
});
console.log(testItems);
Note that there's no need to pass along the this context.
Another option is to flatMap to extract all rows to a single array first:
const output = data
.flatMap(({ rows }) => rows)
.filter(({ name }) => name === 'TEST$$');

Javascript objects combining with Jquery?

I have an issue with manipulating data in Javascript/jQuery and I could use some help.
I have an array of objects that lools like this:
var projects = [
{title:'project1'},
{title:'project2'},
{title:'project3'},
];
I have another array of objects that looks like this:
ganttEvents = [
{
text: 'some text',
start_date: '2018/06/13',
end_date: '2018/06/14',
id: '1',
readonly: true,
project: 'project1',
category: 'scoping',
}
{
text: 'some text2',
start_date: '2018/06/14',
end_date: '2018/06/15',
id: '1',
readonly: true,
project: 'project2',
category: 'scoping',
}
{
text: 'some text3',
start_date: '2018/06/15',
end_date: '2018/06/16',
id: '1',
readonly: true,
project: 'project2',
category: 'design',
}
{
text: 'some text4',
start_date: '2018/06/13',
end_date: '2018/06/14',
id: '1',
readonly: true,
project: 'project2',
category: 'scoping',
}
{
text: 'some text5',
start_date: '2018/06/14',
end_date: '2018/06/15',
id: '1',
readonly: true,
project: 'project3',
category: 'testing',
}
{
text: 'some text6',
start_date: '2018/06/15',
end_date: '2018/06/16',
id: '1',
readonly: true,
project: 'project3',
category: 'build',
}
];
The project field in the second object will always be one of the objects in the first array.
I then need to end up with an object that looks like this:
source: [
{
name: "project1", // a project defined in the projects array
desc: "scoping", // the category from the ganttEvents array of objects
values: [
{
to: "2018/06/13", // the start_date from the ganttEvents array of objects
from: "2018/06/14", // the end_date from the ganttEvents array of objects
desc: "some text", // the text from the ganttEvents array of objects
label: "some text", // the text from the ganttEvents array of objects
}
]
},
{
name: "project2", // a project defined in the projects array
desc: "scoping", // the category from the ganttEvents array of objects
values: [
{
to: "2018/06/14",
from: "2018/06/15",
desc: "some text2",
label: "some text2",
},
{
to: "2018/06/13",
from: "2018/06/14",
desc: "some text4",
label: "some text4",
},
]
},
{
name: "project3", // a project defined in the projects array
desc: "testing", // the category from the ganttEvents array of objects
values: [
{
to: "2018/06/14",
from: "2018/06/15",
desc: "some text5",
label: "some text5",
}
]
},
{
name: "project3", // a project defined in the projects array
desc: "build", // the category from the ganttEvents array of objects
values: [
{
to: "2018/06/15",
from: "2018/06/16",
desc: "some text6",
label: "some text6",
}
]
},
]
There may be several values at all stages for each project and there maybe projects with no events at all that need to be omitted from the source object.
Please can you assist?
Edit:
The background behind this is that I am pulling a list of events from a SharePoint list using SharePointPlus. This results in the ganttEvents array. I need to plug this in to the jQuery.Gantt library which requires the events to be formatted in a particular way.
jQuery.Gantt
I am sorry but i am relatively new to Javascript (Python programmer usually) I have tried different methods of doing this to no avail.
You can use reduce to group the array into an object. Use the concatenated values of project and category as the key. Use Object.values to convert the object into an array.
var ganttEvents = [{"text":"some text","start_date":"2018/06/13","end_date":"2018/06/14","id":"1","readonly":true,"project":"project1","category":"scoping"},{"text":"some text2","start_date":"2018/06/14","end_date":"2018/06/15","id":"1","readonly":true,"project":"project2","category":"scoping"},{"text":"some text3","start_date":"2018/06/15","end_date":"2018/06/16","id":"1","readonly":true,"project":"project2","category":"design"},{"text":"some text4","start_date":"2018/06/13","end_date":"2018/06/14","id":"1","readonly":true,"project":"project2","category":"scoping"},{"text":"some text5","start_date":"2018/06/14","end_date":"2018/06/15","id":"1","readonly":true,"project":"project3","category":"testing"},{"text":"some text6","start_date":"2018/06/15","end_date":"2018/06/16","id":"1","readonly":true,"project":"project3","category":"build"}];
var result = Object.values(ganttEvents.reduce((c, v) => {
let k = v.project + "-" + v.category;
c[k] = c[k] || {name: v.project,desc: v.category,values: []};
c[k].values.push({to: v.end_date,from: v.start_date,desc: v.text,label: v.text});
return c;
}, {}));
console.log(result);
Without Object.values(), you can loop using for
var ganttEvents = [{"text":"some text","start_date":"2018/06/13","end_date":"2018/06/14","id":"1","readonly":true,"project":"project1","category":"scoping"},{"text":"some text2","start_date":"2018/06/14","end_date":"2018/06/15","id":"1","readonly":true,"project":"project2","category":"scoping"},{"text":"some text3","start_date":"2018/06/15","end_date":"2018/06/16","id":"1","readonly":true,"project":"project2","category":"design"},{"text":"some text4","start_date":"2018/06/13","end_date":"2018/06/14","id":"1","readonly":true,"project":"project2","category":"scoping"},{"text":"some text5","start_date":"2018/06/14","end_date":"2018/06/15","id":"1","readonly":true,"project":"project3","category":"testing"},{"text":"some text6","start_date":"2018/06/15","end_date":"2018/06/16","id":"1","readonly":true,"project":"project3","category":"build"}];
var temp = ganttEvents.reduce((c, v) => {
let k = v.project + "-" + v.category;
c[k] = c[k] || {name: v.project,desc: v.category,values: []};
c[k].values.push({to: v.end_date,from: v.start_date,desc: v.text,label: v.text});
return c;
}, {});
var result = [];
for (var key in temp) result.push(temp[key]);
console.log(result);

loop through elements of array within an object within another array

var data = [
{
Name: "HR",
popularity: 91,
keywords: ["bat", "happy", "success"]
},
{
Name: "biz",
popularity: 3,
keywords: ["sad", "code", "shady"]
},
{
Name: "xyz",
popularity: 80,
keywords: ["alphabetical", "code", "trendy"]
},
{
Name: "catty",
popularity: 536,
keywords: ["code", "startup", "cats"]
}
];
How would I write that function that simply returns all the keywords in one array, regardless of how many objects I add or delete to the data array? I don't want to manually concat each unless I can use a loop.
I mainly want to write a function that can test whether any word is in any of the keywords of the data set and then return it's name or names.
It doesn't really bring you anything to concat the keywords, if you have no link back to the original object, why not create a dictionary which key is based on the keyword, and holds the objects in an array as the value.
It's then very easy to create a search to return results based on 1 keyword
var data = [
{
Name: "HR",
popularity: 91,
keywords: ["bat", "happy", "success"]
},
{
Name: "biz",
popularity: 3,
keywords: ["sad", "code", "shady"]
},
{
Name: "xyz",
popularity: 80,
keywords: ["alphabetical", "code", "trendy"]
},
{
Name: "catty",
popularity: 536,
keywords: ["code", "startup", "cats"]
}
];
function createKeywordSet( data ) {
return data.reduce( (dict, arrayItem) => {
arrayItem.keywords.forEach( keyword => {
if (!dict[keyword]) {
dict[keyword] = [];
}
dict[keyword].push( arrayItem );
} );
return dict;
}, {});
}
function findByKeyword( keywordSet, keyword ) {
return keywordSet[keyword] || [];
}
let set = createKeywordSet( data );
console.log( findByKeyword( set, 'code' ).map( r => r.Name ) );
console.log( findByKeyword( set, 'startup' ).map( r => r.Name ) );
console.log( findByKeyword( set, 'keyword' ).map( r => r.Name ) );
A possibility, but not the only one.
Array#filter
Array#includes
Array#map
function getNames(arrayOfObjects, searchKeyword) {
return arrayOfObjects.filter((object) => {
return object.keywords.includes(searchKeyword);
}).map((object) => object.Name);
}
function includesKeyword(arrayOfObjects, searchKeyword) {
return getNames(arrayOfObjects, searchKeyword).length > 0;
}
const data = [{
Name: "HR",
popularity: 91,
keywords: ["bat", "happy", "success"]
},
{
Name: "biz",
popularity: 3,
keywords: ["sad", "code", "shady"]
},
{
Name: "xyz",
popularity: 80,
keywords: ["alphabetical", "code", "trendy"]
},
{
Name: "catty",
popularity: 536,
keywords: ["code", "startup", "cats"]
}
];
console.log(getNames(data, 'code'));
console.log(getNames(data, 'happy'));
console.log(getNames(data, 'wibble'));
console.log(includesKeyword(data, 'code'));
console.log(includesKeyword(data, 'wibble'));
Welcome to SO, in future try to provide examples of what you have tried and a full description of the problems that you are experiencing. Pseudo code is welcome if you have nothing else.
You can use the map() js function on an array.
What it does: it takes every single element of the array and executs a function.
Here is the code below that will get all the keywords and put them in the array allKeywords:
var allKeywords=[];
data.map((x)=>(allKeywords = allKeywords.concat(x.keywords)));
console.log(allKeywords);
The array allKeywords now has the following:
['bat','happy','success','sad','code','shady','alphabetical','code','trendy','code','startup','cats' ]
What happened?
I use data.map(x => x.keywords ...): to get all the inner arrays of keywords.
I concatenate all inner lists together to give the final output.
This is a functional programming way of thinking.
If you need any help understanding let me know.
Try it out!! Read a little about the map function. It is very useful.
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/map

Filtering a list of objects by a child array in Angular 2

I have data that looks like this
[
{id: 1234,
Name: 'John',
Tags: ['tag1', 'tag2']
},
{id: 1235,
Name: 'Mike',
Tags: ['tag1', 'tag3']
}
]
I want to be able to type into a search bar and filter the data to search for related tags. There was a built in filter pipe for this in angular 1 but it looks like it has been removed in angular 2. I've been looking into custom pipes but the only way I can think to do it is with a nested loop that loops over all of the objects then loops through the tags. Am I thinking about this wrong. Is there an easier way to do this or a built in function that would work for this?
You can just use normal javascript APIs to get that behaviour:
data = [
{id: 1234,
Name: 'John',
Tags: ['tag1', 'tag2']
},
{id: 1235,
Name: 'Mike',
Tags: ['tag1', 'tag3']
}
];
filterDataByTag(searchTerm: string) {
// filter the data array, based on some condition
return this.data.filter(item => {
// only include an item in the filtered results
// if that item's Tags property includes the searchTerm
// includes is a built in array method in ES2016
return item.Tags.includes(searchTerm);
});
}
In my example, i'm harding coding the data, but you can adjust to suit your situation. The key point is the function returns a filtered list of the data based on the searchTerm, so you can just call this method each time you want to refresh your filtered list (for eg on the input event of your search field)
You should reorganize data into a reverse index store :
export interface StoreData {
Tag: string;
Peoples: People[] = [];
}
const store: StoreData[] = [];
export interface People {
id: number;
Name: string;
Tags: string[];
}
loadPeopleStore(peoples: People) {
peoples.forEach(p => {
p.Tags.forEach(t => {
let storeData = store.filter(d => d.Tag === t);
if(storeData.length == 1) {
storeData[0].Peoples.push(p);
} else {
store.push({Tag: t, Peoples[p]});
}
}
}
}
initYourPipe() {
let peoples: People[] = [
{id: 1234,
Name: 'John',
Tags: ['tag1', 'tag2']
},
{id: 1235,
Name: 'Mike',
Tags: ['tag1', 'tag3']
}
]
this.loadPeopleStore(peoples);
}

Categories

Resources