How to group multidimensional array objects by value in the component.
I need to group array by page and get the text for every page. I tray to use the map and reduce it but don't get good results. I work on react-native project. JS function groups doesn't work for some reason.
What is the best way to write code for this array?
I have this array:
[
{
number: 1,
englishName: 'Name 1',
items: [
{
text: 'Some text',
page: 1,
},
{
text: 'Some text',
page: 1,
},
],
},
{
number: 2,
englishName: 'Name 2',
items: [
{
text: 'Some text',
page: 2,
},
{
text: 'Some text',
page: 2,
},
],
},
{
number: 3,
englishName: 'Name 3',
items: [
{
text: 'Some text',
page: 3,
},
{
text: 'Some text',
page: 4,
},
],
},
]
I need an array like this
[
{
'page 1': [
{
text: 'Some text',
englishName: 'Name 1',
},
{
text: 'Some text',
englishName: 'Name 2',
},
],
},
{
'page 2': [
{
text: 'Some text',
englishName: 'Name 2',
},
{
text: 'Some text',
englishName: 'Name 2',
},
],
},
....
]
Seems like this will work for you.
This will give you an object:
const allPages = array.reduce((acc, curr) => {
curr.items.forEach((page) => {
var pageKey = `page ${page.page}`
if(!acc[pageKey]){
acc[pageKey] = []
}
acc[pageKey].push({ text: page.text, englishName: curr.englishName })
})
return acc
}, {})
You can convert that object into an array as well:
const finalArr = Object.entries(allPages).map(([page, array]) => {
return {
[page]: array
}
})
See example:
var array = [{
"number": 1,
"englishName": "Name 1",
"items": [
{
"text": "Some text",
"page": 1,
},
{
"text": "Some text",
"page": 1,
}
]
},
{
"number": 2,
"englishName": "Name 2",
"items": [
{
"text": "Some text",
"page": 2,
},
{
"text": "Some text",
"page": 2,
}
]
},
{
"number": 3,
"englishName": "Name 3",
"items": [
{
"text": "Some text",
"page": 3,
},
{
"text": "Some text",
"page": 4,
}
]
}
]
const allPages = array.reduce((acc, curr) => {
curr.items.forEach((page) => {
var pageKey = `page ${page.page}`
if(!acc[pageKey]){
acc[pageKey] = []
}
acc[pageKey].push({ text: page.text, englishName: curr.englishName })
})
return acc
}, {})
const finalArr = Object.entries(allPages).map(([page, array]) => {
return {
[page]: array
}
})
console.log(allPages)
console.log(finalArr)
Related
I'm making a note-taking app in React and I have some data that looks like this. I'm wanting to filter it so that only the objects which contain a tag in an array remain, and the rest are removed.
Raw Data
const obj = {
Mon: [
{ id: 1, content: 'Some text', tag: 'home' },
{ id: 2, content: 'Some text', tag: 'work' },
{ id: 3, content: 'Some text', tag: 'project' },
],
Tue: [
{ id: 4, content: 'Some text', tag: 'project' },
{ id: 5, content: 'Some text', tag: 'moving' },
],
Wed: [
{ id: 6, content: 'Some text', tag: 'home' },
{ id: 7, content: 'Some text', tag: 'home' },
{ id: 8, content: 'Some text', tag: 'work' },
],
};
Desired data after filtering "home" and "work"
Array to use as filtering terms
const filterTags = ['home', 'work']
Data we are left with
{
Mon: [
{ id: 1, content: 'Some text', tag: 'home' },
{ id: 2, content: 'Some text', tag: 'work' },
],
Wed: [
{ id: 6, content: 'Some text', tag: 'home' },
{ id: 7, content: 'Some text', tag: 'home' },
{ id: 8, content: 'Some text', tag: 'work' },
],
};
The reason for wanting to filter using an array is because I want a user to be able to click on the tags for the notes they want to see (these tags are currently stored in a useState()).
With the remaining data after filtering, I plan to map through it and render the relevant elements like this:
<>
{Object.entries(sortedNotesData).map(
([noteDate, noteContent], i) => (
<div key={i}>
<NoteDate noteDate={noteDate} />
<div className="column">
{noteContent
.map((note) => (
<>
<NoteCard
key={note.id}
id={note.id}
content={note.content}
tag={note.tag}
/>
</>
))}
</div>
</div>
)
)}
</>
Any suggestions on a best practice way of filtering the raw data would be brilliant, including whether it would be best to handle the data filtering in a function outside of render(), or whether it can be done inline just before the .map().
Convert the object to an array using Object.entries.
Map over the nested array and filter the values using the filterTags array.
Remove days that have no matching items in them.
Finally convert the nested array back to an object using Object.fromEntries
const obj = {
Mon: [
{ id: 1, content: "Some text", tag: "home" },
{ id: 2, content: "Some text", tag: "work" },
{ id: 3, content: "Some text", tag: "project" },
],
Tue: [
{ id: 4, content: "Some text", tag: "project" },
{ id: 5, content: "Some text", tag: "moving" },
],
Wed: [
{ id: 6, content: "Some text", tag: "home" },
{ id: 7, content: "Some text", tag: "home" },
{ id: 8, content: "Some text", tag: "work" },
],
},
filterTags = ["home", "work"],
filteredObj = Object.fromEntries(
Object.entries(obj)
.map(([key, value]) => [
key,
value.filter(({ tag }) => filterTags.includes(tag)),
])
.filter(([, value]) => value.length)
);
console.log(filteredObj);
You can also keep the days that have no matching items by simply removing the last filter.
const obj = {
Mon: [
{ id: 1, content: "Some text", tag: "home" },
{ id: 2, content: "Some text", tag: "work" },
{ id: 3, content: "Some text", tag: "project" },
],
Tue: [
{ id: 4, content: "Some text", tag: "project" },
{ id: 5, content: "Some text", tag: "moving" },
],
Wed: [
{ id: 6, content: "Some text", tag: "home" },
{ id: 7, content: "Some text", tag: "home" },
{ id: 8, content: "Some text", tag: "work" },
],
},
filterTags = ["home", "work"],
filteredObj = Object.fromEntries(
Object.entries(obj).map(([key, value]) => [
key,
value.filter(({ tag }) => filterTags.includes(tag)),
])
);
console.log(filteredObj);
Similar to SSM's answer, but if you do not wish to include days with no results
Convert the object to an array using Object.entries.
filter the content using includes on the filterTags
only add the day with result of the filter returns 1 or more results
.
const obj = {
Mon: [
{ id: 1, content: 'Some text', tag: 'home' },
{ id: 2, content: 'Some text', tag: 'work' },
{ id: 3, content: 'Some text', tag: 'project' },
],
Tue: [
{ id: 4, content: 'Some text', tag: 'project' },
{ id: 5, content: 'Some text', tag: 'moving' },
],
Wed: [
{ id: 6, content: 'Some text', tag: 'home' },
{ id: 7, content: 'Some text', tag: 'home' },
{ id: 8, content: 'Some text', tag: 'work' },
],
};
const filterTags = ['home', 'work']
//this will hold an object of results
let filteredResults = {};
Object.entries(obj).forEach(day => {
const name = day[0];
const filtered = day[1].filter(content => filterTags.includes(content.tag))
if (filtered.length > 0) {
filteredResults[name] = filtered
}
})
console.log(filteredResults)
Hi guys i have created the following array of objects . And to be honest i am a little bit lost . But please take a look and help me out
[
{
name: "bananaLight",
bananaDefinition: [
{
bananaRef: 'startBanana',
title: 'Start Banana'
},
{
bananaRef: 'endBanana',
title: 'End Banana'
}
]
},
{
name: "bananaFull",
bananaDefinition: [
{
bananaRef: 'bananaSize'
title: 'Banana Size'
},
{
bananaRef: 'startBanana',
title: 'Start Banana'
},
{
bananaRef: 'endBanana',
title: 'End Banana'
}
]
}
]
The idea here is to fetch the array of bananaDefinition bounded with the name bananaLight
You can use find():
const bananaArray = [{
name: "bananaLight",
bananaDefinition: [{
bananaRef: 'startBanana',
title: 'Start Banana'
}, {
bananaRef: 'endBanana',
title: 'End Banana'
}]
}, {
name: "bananaFull",
bananaDefinition: [{
bananaRef: 'bananaSize',
title: 'Banana Size'
}, {
bananaRef: 'startBanana',
title: 'Start Banana'
}, {
bananaRef: 'endBanana',
title: 'End Banana'
}]
}];
const result = bananaArray.find(v => v.name === 'bananaLight').bananaDefinition;
console.log(result);
Based on what you want to do you might want to get it from different ways. here is some of them:
const dataArray = [
{
name: "bananaLight",
bananaDefinition: [
{
bananaRef: "startBanana",
title: "Start Banana",
},
{
bananaRef: "endBanana",
title: "End Banana",
},
],
},
{
name: "bananaFull",
bananaDefinition: [
{
bananaRef: "bananaSize",
title: "Banana Size",
},
{
bananaRef: "startBanana",
title: "Start Banana",
},
{
bananaRef: "endBanana",
title: "End Banana",
},
],
},
];
1
const bananaLightFind = dataArray.find((item) => item.name === "bananaLight");
2
const foundIndex = dataArray.findIndex(item => item.name === "bananaLight")
const bananaLightFindIndex = dataArray[foundIndex];
3
let bananaLightLoop;
dataArray.forEach((item) => {
if (item.name === "bananaLight") {
bananaLightLoop = item;
}
});
This question already has answers here:
merge partially duplicated arrays in javascript (lodash)
(4 answers)
Group array items using object
(19 answers)
Closed 3 years ago.
I have a problem with javascript code
I have an array of the type
var array = [{
name: "Name 1",
id: 1
},
{
name: "Name 2",
id: 2
},
{
name: "Name 3",
id: 3
},
{
name: "Name 1",
id: 4
},
{
name: "Name 1",
id: 5
},
{
name: "Name 2",
id: 6
},
];
I'd like to get this:
var newArray = [{
name: "Name 1",
id: [1, 4, 5]
},
{
name: "Name 2",
id: [2, 6]
},
{
name: "Name 3",
id: 3
},
];
But I can't
I tried with a .find() but it doesn't work
Can you give me some leads please
You can use .reduce() for that. This example produces exactly the same output you expect:
var array = [
{
name: "Name 1",
id: 1
},
{
name: "Name 2",
id: 2
},
{
name: "Name 3",
id: 3
},
{
name: "Name 1",
id: 4
},
{
name: "Name 1",
id: 5
},
{
name: "Name 2",
id: 6
}
];
var output = array.reduce(function(res, curr) {
var existing = res.find(function(el) { return el.name === curr.name; });
if (existing) {
if (Array.isArray(existing.id))
existing.id.push(curr.id);
else
existing.id = [existing.id, curr.id]
} else {
res.push(curr);
}
return res;
}, []);
console.log(output);
You can use reduce() to create an object and then use Object.values to get an array. You can use map() after this to remove the array for those elements which have only a single id.
var array = [{
name: "Name 1",
id: 1
},
{
name: "Name 2",
id: 2
},
{
name: "Name 3",
id: 3
},
{
name: "Name 1",
id: 4
},
{
name: "Name 1",
id: 5
},
{
name: "Name 2",
id: 6
},
];
const res = Object.values(array.reduce((ac, a) => {
if(!ac[a.name]){
ac[a.name] = {...a, id: []}
}
ac[a.name].id.push(a.id);
return ac;
},{})).map(x => ({...x, id: x.id.length === 1 ? x.id[0] : x.id}))
console.log(res)
You can use reduce with a Map, for O(n) performance, as there are no nested loops:
const array = [
{ name: "Name 1", id: 1 },
{ name: "Name 2", id: 2 },
{ name: "Name 3", id: 3 },
{ name: "Name 1", id: 4 },
{ name: "Name 1", id: 5 },
{ name: "Name 2", id: 6 }
]
const out = [...array.reduce((a, o) => {
const e = a.get(o.name)
return (a.set(o.name, e ? Array.isArray(e) ? e.concat(o.id): [e, o.id] : o.id), a)
}, new Map())].map(([k, v]) => ({ name: k, id: v }))
console.log(out)
Try with Array.reduce() like this :
var array = [{
name: "Name 1",
id: 1
},
{
name: "Name 2",
id: 2
},
{
name: "Name 3",
id: 3
},
{
name: "Name 1",
id: 4
},
{
name: "Name 1",
id: 5
},
{
name: "Name 2",
id: 6
},
];
var output = array.reduce((acc, current) => {
if (exist = acc.find(p => p.name == current.name)) {
if(!Array.isArray(exist.id)){
exist.id = [exist.id];
}
exist.id.push(current.id);
} else {
acc.push(current)
}
return acc;
}, []);
console.log(output);
I have two objects. obj2 has texts and obj1 has 3 subIbjId. How can I add the 'id' to obj2 based on obj1?
For example: obj1 has 2 subObjId in the first object(1001, 1002). I want to count the number of subObjId obj1 has and iterate through obj1 and add the key and value of id for the to obj2. If obj1 has two subObjId, then add id: 1 to the first two entries of obj2 and so on.
I am learning javascript and trying to solve some imaginary problems. Any help would be greatly appreciated. Thank you.
var obj1 = { [
{
id: 1,
name: ‘apple’,
subObjId: [ 1001, 1002]
subObjs: [
{
subId: 1001
subName: ‘ant’,
},
{
subId: 1002
subName: ‘ball’,
}
],
},
{
{
id: 2,
name: ‘zebra’,
subObjId: [ 1003]
subObjs: [
{
subId: 1003
subName: ‘cat’,
}
],
},
]
}
var obj2 = { [
{
text: ‘i am a text’
},
{
text: ‘i am some random characters’
},
{
text: ‘i am some numbers’
}
] }
to become
finalObject = { [
{
id: 1,
text: ‘i am a text’
},
{
id: 1,
text: ‘i am some random characters’
},
{
id: 2,
text: ‘i am some numbers’
}
] }
Try this!!
var obj1 = [
{
id: 1,
name: 'apple',
subObjId: [ 1001, 1002]
},
{
id: 2,
name: 'zebra',
subObjId: [ 1003]
}
]
var obj2 = [
{
text: 'i am a text'
},
{
text: 'i am some random characters'
},
{
text: ' am some numbers'
}
]
let index = 0;
let start = 0;
obj1.map(data1=>{
index += data1.subObjId.length;
for(var i=start;i<index;i++){
obj2[i]['id'] = data1.id;
}
start = i;
})
console.log(obj2)
You can use
Array#flatMap to extract an array of all subObjs items
also Array#map them into their parent's id property only.
Perform another mapping operation that copies the contents of a matching object in obj2 and adds an id.
For convenience, this uses the second argument to Array#map, which sets the this context inside the callback.
Also uses destructuring for compactness and spread syntax for making copies:
var obj1 = [ { id: 1, name: 'apple', subObjId: [1001, 1002], subObjs: [ { subId: 1001, subName: 'ant' }, { subId: 1002, subName: 'ball' } ] }, { id: 2, name: 'zebra', subObjId: [1003], subObjs: [ { subId: 1003, subName: 'cat', } ], }, ];
var obj2 = [ { text: 'i am a text' }, { text: 'i am some random characters' }, { text: 'i am some numbers' } ];
var finalObject = obj1
//1. flatMap into a single array
.flatMap(({id, subObjs}) => subObjs
.map(sub => ({id})) //take only the parent ID for each sub object
)// result: [{id: 1}, {id: 1}, {id: 2}]
.map(function({id}, index) {
return { id, ...this[index] } //2. create a new object with the id and the content of a matching object from the other array
}, obj2);// <- set the `this` context for the callback
console.log(finalObject);
It can also be done as a single operation when flatmapping by setting the this context to a copy of the second array (to avoid mutating obj2), then taking items off the front of the new array with Array#shift:
var obj1 = [ { id: 1, name: 'apple', subObjId: [1001, 1002], subObjs: [ { subId: 1001, subName: 'ant' }, { subId: 1002, subName: 'ball' } ] }, { id: 2, name: 'zebra', subObjId: [1003], subObjs: [ { subId: 1003, subName: 'cat', } ], }, ];
var obj2 = [ { text: 'i am a text' }, { text: 'i am some random characters' }, { text: 'i am some numbers' } ];
var finalObject = obj1.flatMap(function({id, subObjs}) {
return subObjs.map(sub => ({ id, ...this.shift() }))
}, [...obj2]);// <- copy obj2 as the `this` context
console.log(finalObject);
Use this snippet
var obj1 = [
{
id: 1,
name: 'apple',
subObjId: [1001, 1002],
subObjs: [{
subId: 1001,
subName: 'ant',
},
{
subId: 1002,
subName: 'ball',
}
],
},
{
id: 2,
name: 'zebra',
subObjId: [1003],
subObjs: [{
subId: 1003,
subName: 'cat',
}],
},
]
var obj2 = [
{
text: 'i am a text'
},
{
text: 'i am some random characters'
},
{
text: 'i am some numbers'
}
]
var finalObject = obj1.map(function (value, index) {
return {
id: value.id,
text: obj2[index].text
}
})
console.log(finalObject)
I would like to convert this json / object to this specific structure below to allow me to use a treeList component.
I've tried to build a recursive function but I didn't find the solution yet.
Thanks for your help
const data = {
parent1: {
child1: { bar: "1" },
child2: "2"
},
parent2: {
child1: "1"
}
}
to
const treeData = [
{
title: "parent1",
key: "parent1",
children: [
{
title: "child1",
key: "child1",
children: [{ title: "bar", key: "bar", value: "1" }]
},
{
title: "child2",
key: "child2",
value: "2"
}
],
},
{
title: "parent2",
key: "parent2",
children: [
{
title: "child1",
key: "child1",
value: "1"
}
]
}
]
You could take an iterative and recursive approach.
function getNodes(object) {
return Object
.entries(object)
.map(([key, value]) => value && typeof value === 'object'
? { title: key, key, children: getNodes(value) }
: { title: key, key, value }
);
}
const data = { parent1: { child1: { bar: "1" }, child2: "2" }, parent2: { child1: "1" } },
result = getNodes(data);
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }
just share sample, a little different from yours. But it give you a hint with recursive function.
https://jsfiddle.net/segansoft/7bdxmys4/1/
function getNestedChildren(arr, parent) {
var out = []
for (var i in arr) {
if (arr[i].parent == parent) {
var children = getNestedChildren(arr, arr[i].id)
if (children.length) {
arr[i].children = children
}
out.push(arr[i])
}
}
return out
}
var flat = [{
id: 1,
title: 'hello',
parent: 0
},
{
id: 2,
title: 'hello',
parent: 0
},
{
id: 3,
title: 'hello',
parent: 1
},
{
id: 4,
title: 'hello',
parent: 3
},
{
id: 5,
title: 'hello',
parent: 4
},
{
id: 6,
title: 'hello',
parent: 4
},
{
id: 7,
title: 'hello',
parent: 3
},
{
id: 8,
title: 'hello',
parent: 2
}
]
var nested = getNestedChildren(flat, 0)
document.write('<pre>' + JSON.stringify(nested, 0, 4) + '</pre>');