1
votes

Du tableau de chemins à l'objet en utilisant la réduction et la récursivité

J'ai besoin de convertir un tableau de chemins:

  const iterRow = (row, obj) => {
    if (Array.isArray(row) && row.length !== 0) {
      const [name, ...pathStack] = row;
      const found = (n) => obj.children.find((i) => i.name === n);

      if (obj.name === name) {
        iterRow(pathStack, obj);
      } else {
        const newLeaf = {
          name,
          id: `${obj.id}.${name}`,
          children: [],
        };
        if (!found(name)) {
          obj.children.push(newLeaf);
        }
        iterRow(pathStack, found(name));
      }
    }
  };
  
const argOptionsProcessed = (rows) => rows.reduce((acc, row) => {
    const path = row.split('.');
    const found = () => acc.find((item) => path[0] === item.name);
    if (!found()) {
      acc.push({ name: path[0], id: path[0], children: [] });
    }
    iterRow(path, found());
    return acc;
  }, []);
  
  
  
const paths = [
"test1",
"test1.test1children",
"test1.test1children.test1subchildren",
"test1.test1children.test1subchildren.test1subsubchildren",
"tets2",
"test2.test2children",
]


console.log(argOptionsProcessed(paths));

en un objet avec la structure suivante:

{
  name: "test1",
  id: "test1",
  children: [...test1 children],
}

J'essaye avec un réducteur et une fonction récursive par élément de tableau, cela fonctionne mais est assez lent. Toutes les suggestions pour améliorer ce code sont les bienvenues. Merci d'avance.

const paths = [
  "test1",
  "test1.test1children"
]


3 commentaires

Cette question convient peut-être mieux à codereview.stackexchange.com


Btw je ne suis pas sûr si votre code fonctionne. Je récupère 3 objets au lieu de 2. L'objet avec l'id test2 est contenu deux fois.


Et mieux vaut fournir une explication abstraite de l'algorithme que vous avez utilisé, afin que les gens puissent vous aider à améliorer cet algorithme et ne pas comprendre tout votre code.


3 Réponses :


1
votes

Vous pouvez le faire sans récursivité en utilisant les méthodes forEach et reduction et un objet pour conserver les niveaux imbriqués.

const paths = [
  "test1",
  "test1.test1children",
  "test1.test1children.test1subchildren",
  "test1.test1children.test1subchildren.test1subsubchildren",
  "test2",
  "test2.test2children",
]

const result = []
const levels = { result }

paths.forEach(path => {
  let id = '';

  path.split('.').reduce((r, name, i, a) => {
    id += (id ? '.' : '') + name;

    if (!r[name]) {
      r[name] = { result: [] }
      r.result.push({ name, id, children: r[name].result })
    }

    return r[name]
  }, levels)
})

console.log(result)


1 commentaires

Vous avez raison! Merci beaucoup! Je vais essayer dans mon propre code merci encore



0
votes

Vous pouvez adopter une approche plus courte en réduisant le tableau et le chemin et en recherchant le même nom.

.as-console-wrapper { max-height: 100% !important; top: 0; }
const
    getTree = data => data.reduce((tree, path) => {
        path.split('.').reduce((t, name, i, a) => {
            let temp = t.find(q => q.name === name);
            if (!temp) t.push(temp = { name, id: a.slice(0, i + 1).join('.'), children: [] });
            return temp.children;
        }, tree);
        return tree;
    }, []),
    paths = ["test1", "test1.test1children", "test1.test1children.test1subchildren", "test1.test1children.test1subchildren.test1subsubchildren", "tets2", "test2.test2children"]

console.log(getTree(paths));


0 commentaires

0
votes

Voici une autre solution.

.as-console-wrapper { top: 0; max-height: 100% !important; }
const paths = [
  "test1",
  "test1.test1children",
  "test1.test1children.test1subchildren",
  "test1.test1children.test1subchildren.test1subsubchildren",
  "test2",
  "test2.test2children",
];

console.log(untangle(paths));

function untangle(paths) {
  return paths.reduce( (a, v) => {
    const path = v.split(".");
    if (path.length < 2) {
      const l0 = path[0];
      let level0 = {name: l0, id: l0, children: []};
      let tryChildren = paths
        .filter( p => ~p.indexOf(".") && p.startsWith(l0) )
      if (tryChildren.length) {
        tryChildren = tryChildren.map( p => p.substr( p.indexOf(".")+1 ) );
        level0.children = level0.children.concat(untangle(tryChildren));
      }
      a.push(level0);
    }
    return a;
  }, []);
}


0 commentaires