Nguyễn Văn Huy
Nguyễn Văn Huy

Reputation: 59

handling arrays in javascript

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

Answers (8)

Andy
Andy

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

Tunjay
Tunjay

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

Suman Mondal
Suman Mondal

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

Sanmeet
Sanmeet

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

MinaMaherNicola
MinaMaherNicola

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

Tushar Shahi
Tushar Shahi

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

Amin
Amin

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

Leif Messinger LOAF
Leif Messinger LOAF

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

Related Questions