admin管理员组

文章数量:1319480

I need a javascript function to turn an array with file path string to object as follows:

  let files = [
  "Folder/file.ext",
  "Folder/file2.ext",
  "Folder/file3.ext",
  "Folder/nestedfolder/file.ext",
  "Folder2/file1.ext",
  "Folder2/file2.ext",
  "file1.ext",
  "file2.ext",
  "file3.ext",
];

listToTree(files);

And It should output an array with an object as follows:

[
  {
    text: "Folder",
    children: [
      {text: "file.ext"},
      {text: "file1.ext"},
      {text: "file2.ext"},
      {text: "nestedfolder", children: [{text: "file.ext"}]},
    ]
  },
  {
    text: "Folder2",
    children: [
      {text: "file1.ext"},
      {text: "file2.ext"},
    ]
  },
  {text: "file1.ext"},
  {text: "file2.ext"},
  {text: "file3.ext"}
];

Here is the current function I am using. but it is not quite there.

function listToTree(files) {
  let filestmp = files.map(file => {
    if (typeof file === "string") return file;
    return file.path
  });
  let filesl = filestmp.map(fileee => fileToObject(fileee));

  return filesl;
}

function fileToObject(filee) {
  if (filee.includes("/")) {
    // this is a folder
    let count = filee.indexOf("/");
    return {text: filee.substring(0, count), children: [fileToObject(filee.substring(count + 1))]}
  } else {
    // this is a file
    return {text: filee}
  }
}

export default listToTree

it outputs:

[ { text: 'Folder', children: [ { text: 'file.ext' } ] },
  { text: 'Folder', children: [ { text: 'file2.ext' } ] },
  { text: 'Folder', children: [ { text: 'file3.ext' } ] },
  { text: 'Folder',
    children:
     [ { text: 'nestedfolder', children: [ { text: 'file.ext' } ] } ] },
  { text: 'Folder2', children: [ { text: 'file1.ext' } ] },
  { text: 'Folder2', children: [ { text: 'file2.ext' } ] },
  { text: 'file1.ext' },
  { text: 'file2.ext' },
  { text: 'file3.ext' } ]

now as you can see. each file list array getting its own object. I need to bine the files located in the same folder location.

I need a javascript function to turn an array with file path string to object as follows:

  let files = [
  "Folder/file.ext",
  "Folder/file2.ext",
  "Folder/file3.ext",
  "Folder/nestedfolder/file.ext",
  "Folder2/file1.ext",
  "Folder2/file2.ext",
  "file1.ext",
  "file2.ext",
  "file3.ext",
];

listToTree(files);

And It should output an array with an object as follows:

[
  {
    text: "Folder",
    children: [
      {text: "file.ext"},
      {text: "file1.ext"},
      {text: "file2.ext"},
      {text: "nestedfolder", children: [{text: "file.ext"}]},
    ]
  },
  {
    text: "Folder2",
    children: [
      {text: "file1.ext"},
      {text: "file2.ext"},
    ]
  },
  {text: "file1.ext"},
  {text: "file2.ext"},
  {text: "file3.ext"}
];

Here is the current function I am using. but it is not quite there.

function listToTree(files) {
  let filestmp = files.map(file => {
    if (typeof file === "string") return file;
    return file.path
  });
  let filesl = filestmp.map(fileee => fileToObject(fileee));

  return filesl;
}

function fileToObject(filee) {
  if (filee.includes("/")) {
    // this is a folder
    let count = filee.indexOf("/");
    return {text: filee.substring(0, count), children: [fileToObject(filee.substring(count + 1))]}
  } else {
    // this is a file
    return {text: filee}
  }
}

export default listToTree

it outputs:

[ { text: 'Folder', children: [ { text: 'file.ext' } ] },
  { text: 'Folder', children: [ { text: 'file2.ext' } ] },
  { text: 'Folder', children: [ { text: 'file3.ext' } ] },
  { text: 'Folder',
    children:
     [ { text: 'nestedfolder', children: [ { text: 'file.ext' } ] } ] },
  { text: 'Folder2', children: [ { text: 'file1.ext' } ] },
  { text: 'Folder2', children: [ { text: 'file2.ext' } ] },
  { text: 'file1.ext' },
  { text: 'file2.ext' },
  { text: 'file3.ext' } ]

now as you can see. each file list array getting its own object. I need to bine the files located in the same folder location.

Share Improve this question edited Oct 31, 2018 at 16:54 Bubun asked Oct 31, 2018 at 15:27 BubunBubun 4567 silver badges18 bronze badges 4
  • Questions that imply having us write it for you are frowned upon, Take a look at the .split() method of javascript strings, and get to know recursion. Take a shot and ask for help if you run into trouble. – Jim B. Commented Oct 31, 2018 at 15:32
  • This is my current code. but it is not quite there, – Bubun Commented Oct 31, 2018 at 15:35
  • Great. Can you put your current solution in the question, and describe what's not working? – Jim B. Commented Oct 31, 2018 at 15:42
  • already did. check. – Bubun Commented Oct 31, 2018 at 15:45
Add a ment  | 

2 Answers 2

Reset to default 5

Having a tree represented as an array is a little inconvenient because you need to search the array each time to find the appropriate node, which would be inefficient for large arrays. On option is to just build a tree object in one pass and then do a second pass to just take the Object.values. Here's an example of that:

let files = ["Folder/file.ext","Folder/file2.ext","Folder/file3.ext","Folder/nestedfolder/file.ext","Folder2/file1.ext","Folder2/file2.ext","file1.ext","file2.ext","file3.ext",];

function addPath(arr, obj = {}){
    let ponent = arr.shift()
    let current = obj[ponent] || (obj[ponent] = {text:ponent})
    if (arr.length) {
        addPath(arr, current.children || (current.children = {}))
    }
    return obj
}

function makeArray(obj){
    let arr = Object.values(obj)
    arr.filter(item => item.children).forEach(item => {
        item.children = makeArray(item.children)
    })
    return arr
}

// make tree
let treeObj = files.reduce((obj, path) => addPath(path.split('/'), obj), {})
// convert to array
let arr = makeArray(treeObj)

console.log(arr)

An alternative is using find() which will work and may be easier to read…but may be less efficient because you need to search the result array on each pass:

let files = ["Folder/file.ext","Folder/file2.ext","Folder/file3.ext","Folder/nestedfolder/file.ext","Folder2/file1.ext","Folder2/file2.ext","file1.ext","file2.ext","file3.ext",];

function addPath(pathponents, arr ){
    let ponent = pathponents.shift()
    let p = arr.find(item => item.text === ponent)
    if (!p) {
        p =  {text: ponent}
        arr.push(p)
    }
    if(pathponents.length){
       addPath(pathponents, p.children || (p.children = []))
    }
    return arr
}



let res = files.reduce((arr, path) => addPath(path.split('/'), arr), [])

console.log(res)

Here's my take, one function, no recursion:

const listToTree = files =>
  files.map(file => file.split('/'))
  .reduce((out, path) => {
    let top = out;
    while (path.length > 0) {
      let node = path.shift();
      if (top.findIndex(n => n.text === node) === -1) {
        top.push({
          text: node
        });
      }

      if (path.length > 0) {
        let index = top.findIndex(n => n.text === node);
        top[index] = top[index] || {};
        top[index].children = top[index].children || [];
        top[index].children.push({
          text: path[0]
        });
        top = top[index].children;
      }
    }
    return out;
  }, []);

let files = [
  'Folder/file.ext',
  'Folder/file2.ext',
  'Folder/file3.ext',
  'Folder/nestedfolder/file.ext',
  'Folder2/nestedfolder1/nestedfolder2/file1.ext',
  'Folder2/file2.ext',
  'file1.ext',
  'file2.ext',
  'file3.ext'
];

console.log(listToTree(files));

本文标签: javascriptTurn an array with file path to object as mentionedStack Overflow