Reputation: 59
I'm new to javascript and react I have an array of data as follows
const data = [
{
folder_name: "folder 002",
file_name: "anh 1.jpg"
},
{
folder_name: "folder 002",
file_name: "anh 2.jpg"
},
{
folder_name: "folder 002",
file_name: "anh 3.jpg"
},
{
folder_name: "folder 002",
file_name: "anh 4.jpg"
},
{
folder_name: "folder 001",
file_name: "anh 1.jpg"
},
{
folder_name: "folder 001",
file_name: "anh 2.jpg"
},
{
folder_name: "folder 001",
file_name: "anh 3.jpg"
}
]
Please help me split into array like this. Please help me to return the array like this The result I wanted
const images = [
{
folder_name: 'folder 001',
file_name: ['anh 1','anh 2','anh 3']
},
{
folder_name: 'folder 002',
file_name: ['anh 1','anh 2','anh 3','anh 4']
}
]
Thanks you very much
Upvotes: 0
Views: 180
Reputation: 63524
const data=[{folder_name:"folder 002",file_name:"anh 1.jpg"},{folder_name:"folder 002",file_name:"anh 2.jpg"},{folder_name:"folder 002",file_name:"anh 3.jpg"},{folder_name:"folder 002",file_name:"anh 4.jpg"},{folder_name:"folder 001",file_name:"anh 1.jpg"},{folder_name:"folder 001",file_name:"anh 2.jpg"},{folder_name:"folder 001",file_name:"anh 3.jpg"}];
// Iterate over the data with `reduce`
// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/reduce
const out = data.reduce((acc, c) => {
// Grab the folder_name as the key
const { folder_name: key, file_name } = c;
// If the key doesn't exist on the accumulator
// create a new object with a file_name array
acc[key] = acc[key] || { folder_name: key, file_name: [] };
// Push the filename into the new object array
acc[key].file_name.push(file_name);
// Return the accumulator
return acc;
}, {});
// Grab the object values (an array) from the
// returned object
console.log(Object.values(out));
Upvotes: 2
Reputation: 110
The short one:
let result = array.reduce((accumulator,c)=>{
!accumulator.find(w=>w.folder_name == c.folder_name)?
accumulator.push({folder_name: c.folder_name, file_name: [c.file_name]}):
accumulator.find(w=>w.folder_name == c.folder_name).file_name.push(c.file_name)
return accumulator
},[])
Using Reduce function makes it easy and readable. Reduce function iterates first parameter (which is a function) as much as the length of array
. We pass an empty list as a second parameter to the Reduce function. It is also the accumulator
parameter. Reduce function updates the list a.k.a accumulator
in every iteration. It means Reduce returns of the previous iteration's accumulator
in each one.
e.g: accumulator.push(5)
will return a list contains the number 5 as the length of array
, because we pushed the number 5 to the list in every iteration.
The parameter c
is the current element being processed in the array.
e.g: The first iteration of Reduce gives array[0]
in the parameter c
, the second one gives array[1]
, and so on. In this case, c
is an object list.
Moreover, we use Conditional Operator in the function we have passed as a first parameter. Conditional Operator is the short version of the If-else statement.
!accumulator.find(w=>w.folder_name == c.folder_name)
We search if the list accumulator
contains an object that has the same key-value with the parameter c
(which is one of the elements of array
- depends on the index of iteration).
If we do not find any folder_name
equals to c
's one, we push a new object that contains those values
accumulator.push({folder_name: c.folder_name, file_name: [c.file_name]})
If we find any folder_name
equals to c
's one, we get this object with the help of find
and add necessary values to this object
accumulator.find(w=>w.folder_name == c.folder_name).file_name.push(c.file_name)
In conclusion, after checking every c
(Current Value) in accumulator
and adding necessary values to accumulator
in each iteration, we return accumulator
. It passes accumulator
to the next iteration and at the end, it returns accumulator
itself
Upvotes: 2
Reputation: 21
let folderNames = [];
data.forEach(each=>{
if(!folderNames.includes( each["folder_name"])){
folderNames.push(each["folder_name"]);
});
let image = [];
folderNames.forEach(item=>{
let fileNames = data.filter((i) => i["folderName"] === item && i["file_name"]);
let tempObj = {};
tempObj["folder_name"] = item;
tempObj["file_name"] = fileNames;
image.push(tempObj);
});
Upvotes: 1
Reputation: 1410
Not sure it's best implementation but it works
const images = [{
folder_name: "folder 001",
file_name: "ab",
},
{
folder_name: "folder 001",
file_name: "ab",
},
{
folder_name: "folder 002",
file_name: "ab",
}]
const converted_images = []
let folders = [];
images.forEach(img => {
folders.includes(img.folder_name) ? null: folders.push(img.folder_name)
})
folders.forEach(folder => {
let arr = images.filter(image => image.folder_name === folder)
let file_name = [];
arr.forEach(obj => {
file_name.push(obj.file_name)
})
let object = {
folder_name: folder,
file_name: file_name
}
converted_images.push(object)
});
console.log(converted_images)
Upvotes: 1
Reputation: 60
Try this function out
const splitArray = array => {
const folders = [];
let fileName = [];
for (let i = 0; i < array.length; i++) {
const folderName = array[i].folder_name;
const index = folderName[folderName.length - 1] * 1 - 1;
if (folders[index] === undefined) {
fileName = [];
}
fileName.push(array[i].file_name);
folders[index] = {};
folders[index]['folder_name'] = folderName;
folders[index]['file_name'] = [...fileName];
}
return folders;
};
Upvotes: 1
Reputation: 20431
You can reduce and findIndex to achieve this :
let ans = data.reduce((cum,x)=>{
let exists = cum.findIndex((a)=>{
if(a['folder_name'] == x['folder_name'])
return true;
});
if(exists==-1){
cum.push({
folder_name : x['folder_name'],
file_name : [x['file_name']]
})
}
else{
cum[exists]['file_name'].push(x['file_name']);
}
return cum;
},[]);
Reduce converts the array to a single value by applying the same function to all elements. The second param []
is the initial value to start with.
For each element in the data array, I am checking if the respective folder element exists in the cum
array. (cum
array is changing at every iteration.) Now, if it does I am pushing to that elements property or else i am pushing a whole new element in the cum
array.
Note: The order differs from your expected answer. You can use custom sort()
to help fix that.
Upvotes: 1
Reputation: 895
I'm not sure that it's the best way to imploment this. But it works!
const input = [
{ folderName: "folder1", fileName: "file11" },
{ folderName: "folder1", fileName: "file12" },
{ folderName: "folder1", fileName: "file13" },
{ folderName: "folder2", fileName: "file21" },
{ folderName: "folder2", fileName: "file22" },
{ folderName: "folder2", fileName: "file23" },
];
const output = [];
const folderNames = [];
input.forEach((item) => {
if (!folderNames.includes(item.folderName)) folderNames.push(item.folderName);
});
folderNames.forEach((item) => output.push({ folderName: item, fileNames: [] }));
output.forEach((item, index) => {
const files = input.filter((i) => i.folderName === item.folderName);
item.fileNames = [...files.map((i) => i.fileName)];
});
console.log(output);
Sorry about some change in keys of your object.I tried to write something similar to your object.
Upvotes: 1
Reputation: 182
Why don't you just make a map of the folders? So it would look like this:
const images = {
"folder 001": {
"folder_names": [
"anh 1",
"anh 2",
"anh 3"
]
},
"folder 002": {
"folder_names": [
"anh 1",
"anh 2",
"anh 3",
"anh 4"
]
}
}
The spacing is a bit weird because I actually made that, then did stringify with tabs.
Anyways, the way you'd want to do that is
let images = {};
for(let row of database){
if(row["folder_name"] != undefined){
if(images[row["folder_name"]] == undefined){
images[row["folder_name"]] = {};
images[row["folder_name"]].file_names = [];
}
}
images[row["folder_name"]].file_names.concat(row["file_name"]);
}
Upvotes: 0