Erstellen Sie ein Baumarray aus einem flachen Array in Javascript

134

Ich habe eine komplexe JSON-Datei, die ich mit Javascript verarbeiten muss, um sie hierarchisch zu gestalten und später einen Baum zu erstellen. Jeder Eintrag des json hat: id: eine eindeutige ID, parentId: die ID des übergeordneten Knotens (die 0 ist, wenn der Knoten eine Wurzel des Baums ist) Ebene: die Ebene der Tiefe im Baum

Die JSON-Daten sind bereits "bestellt". Ich meine, ein Eintrag hat über sich einen übergeordneten Knoten oder einen Bruderknoten und unter sich einen untergeordneten Knoten oder einen Bruderknoten.

Eingabe:

{
    "People": [
        {
            "id": "12",
            "parentId": "0",
            "text": "Man",
            "level": "1",
            "children": null
        },
        {
            "id": "6",
            "parentId": "12",
            "text": "Boy",
            "level": "2",
            "children": null
        },
                {
            "id": "7",
            "parentId": "12",
            "text": "Other",
            "level": "2",
            "children": null
        },
        {
            "id": "9",
            "parentId": "0",
            "text": "Woman",
            "level": "1",
            "children": null
        },
        {
            "id": "11",
            "parentId": "9",
            "text": "Girl",
            "level": "2",
            "children": null
        }
    ],
    "Animals": [
        {
            "id": "5",
            "parentId": "0",
            "text": "Dog",
            "level": "1",
            "children": null
        },
        {
            "id": "8",
            "parentId": "5",
            "text": "Puppy",
            "level": "2",
            "children": null
        },
        {
            "id": "10",
            "parentId": "13",
            "text": "Cat",
            "level": "1",
            "children": null
        },
        {
            "id": "14",
            "parentId": "13",
            "text": "Kitten",
            "level": "2",
            "children": null
        },
    ]
}

Erwartete Ausgabe :

{
    "People": [
        {
            "id": "12",
            "parentId": "0",
            "text": "Man",
            "level": "1",
            "children": [
                {
                    "id": "6",
                    "parentId": "12",
                    "text": "Boy",
                    "level": "2",
                    "children": null
                },
                {
                    "id": "7",
                    "parentId": "12",
                    "text": "Other",
                    "level": "2",
                    "children": null
                }   
            ]
        },
        {
            "id": "9",
            "parentId": "0",
            "text": "Woman",
            "level": "1",
            "children":
            {

                "id": "11",
                "parentId": "9",
                "text": "Girl",
                "level": "2",
                "children": null
            }
        }

    ],    

    "Animals": [
        {
            "id": "5",
            "parentId": "0",
            "text": "Dog",
            "level": "1",
            "children": 
                {
                    "id": "8",
                    "parentId": "5",
                    "text": "Puppy",
                    "level": "2",
                    "children": null
                }
        },
        {
            "id": "10",
            "parentId": "13",
            "text": "Cat",
            "level": "1",
            "children": 
            {
                "id": "14",
                "parentId": "13",
                "text": "Kitten",
                "level": "2",
                "children": null
            }
        }

    ]
}
Franck
quelle
2
Es gibt verschiedene Möglichkeiten, haben Sie schon etwas ausprobiert?
Bfavaretto
Ich gehe davon aus, dass a parentIdof 0bedeutet, dass es keine übergeordnete ID gibt und die oberste Ebene sein sollte.
Donnie D'Amato
Normalerweise erforderten solche Aufgaben umfangreiche Arbeitswissensobjekte. Gute Frage
Gangadhar JANNU

Antworten:

156

Es gibt eine effiziente Lösung, wenn Sie eine Kartensuche verwenden. Wenn die Eltern immer vor ihren Kindern stehen, können Sie die beiden for-Schleifen zusammenführen. Es unterstützt mehrere Wurzeln. Es gibt einen Fehler bei baumelnden Zweigen, kann aber geändert werden, um sie zu ignorieren. Es ist keine Bibliothek eines Drittanbieters erforderlich. Soweit ich das beurteilen kann, ist es die schnellste Lösung.

function list_to_tree(list) {
  var map = {}, node, roots = [], i;
  
  for (i = 0; i < list.length; i += 1) {
    map[list[i].id] = i; // initialize the map
    list[i].children = []; // initialize the children
  }
  
  for (i = 0; i < list.length; i += 1) {
    node = list[i];
    if (node.parentId !== "0") {
      // if you have dangling branches check that map[node.parentId] exists
      list[map[node.parentId]].children.push(node);
    } else {
      roots.push(node);
    }
  }
  return roots;
}

var entries = [{
    "id": "12",
    "parentId": "0",
    "text": "Man",
    "level": "1",
    "children": null
  },
  {
    "id": "6",
    "parentId": "12",
    "text": "Boy",
    "level": "2",
    "children": null
  },
  {
    "id": "7",
    "parentId": "12",
    "text": "Other",
    "level": "2",
    "children": null
  },
  {
    "id": "9",
    "parentId": "0",
    "text": "Woman",
    "level": "1",
    "children": null
  },
  {
    "id": "11",
    "parentId": "9",
    "text": "Girl",
    "level": "2",
    "children": null
  }
];

console.log(list_to_tree(entries));

Wenn Sie sich mit Komplexitätstheorie beschäftigen, lautet diese Lösung Θ (n log (n)). Die rekursive Filterlösung ist Θ (n ^ 2), was bei großen Datenmengen ein Problem sein kann.

Halcyon
quelle
28
Beachten Sie, dass bei dieser Lösung Ihre Knoten speziell bestellt werden müssen, um sicherzustellen, dass die Eltern zuerst in die Karte verschoben werden. Andernfalls schlägt der Suchvorgang fehl. Sie müssen sie also entweder nach der Eigenschaft level sortieren oder benötigen um sie zuerst in die Karte zu schieben. und verwenden Sie eine separate for-Schleife für die Suche. (Ich bevorzuge sortieren, aber wenn Sie keine Level-Eigenschaft haben, könnten die separaten Schleifen eine Option sein)
Sander
Ich fand es zunächst überraschend, dass zusätzliche Informationen, z. B. ein Pfad wie [1, 5, 6], in dem das Array die nachfolgenden Vorfahren sind, nicht effizient darin verwendet werden konnten. Aber
Ced
1
Trotz der guten Antwort ist es komplex. Wenden Sie meine Antwort für nur zwei
Zeilencodes an
Können Sie bitte erklären, warum diese Lösung Θ (n log (n)) ist? Es scheint O (n) Zeit zu dauern.
Amrender Singh
@amrendersingh innerhalb der for-Schleife ist eine Hash-Suche, in mapder (theoretisch) O (log n) ist.
Halcyon
72

Wie von @Sander erwähnt, geht die Antwort von @ Halcyon von einem vorsortierten Array aus, das Folgende nicht. (Es wird jedoch davon ausgegangen, dass Sie underscore.js geladen haben - obwohl es in Vanille-Javascript geschrieben sein könnte):

Code

// Example usage
var arr = [
    {'id':1 ,'parentid' : 0},
    {'id':2 ,'parentid' : 1},
    {'id':3 ,'parentid' : 1},
    {'id':4 ,'parentid' : 2},
    {'id':5 ,'parentid' : 0},
    {'id':6 ,'parentid' : 0},
    {'id':7 ,'parentid' : 4}
];

unflatten = function( array, parent, tree ){
    tree = typeof tree !== 'undefined' ? tree : [];
    parent = typeof parent !== 'undefined' ? parent : { id: 0 };
        
    var children = _.filter( array, function(child){ return child.parentid == parent.id; });
    
    if( !_.isEmpty( children )  ){
        if( parent.id == 0 ){
           tree = children;   
        }else{
           parent['children'] = children
        }
        _.each( children, function( child ){ unflatten( array, child ) } );                    
    }
    
    return tree;
}

tree = unflatten( arr );
document.body.innerHTML = "<pre>" + (JSON.stringify(tree, null, " "))
<script src="https://cdnjs.cloudflare.com/ajax/libs/underscore.js/1.9.1/underscore-min.js"></script>

Bedarf

Es wird davon ausgegangen, dass die Eigenschaften 'id' und 'parentid' die ID bzw. die übergeordnete ID angeben. Es müssen Elemente mit der übergeordneten ID 0 vorhanden sein, andernfalls erhalten Sie ein leeres Array zurück. Verwaiste Elemente und ihre Nachkommen sind "verloren"

http://jsfiddle.net/LkkwH/1/

Stephen Harris
quelle
4
Sie können else { parent['children'] = []; }nach der ersten if-Klausel hinzufügen , um sicherzustellen, dass jeder Knoten ein Attribut hat children(es wird leer sein, wenn der Knoten ein Blattknoten ist)
Christopher
2
Ihr Code-Snippet hat perfekt funktioniert, danke !! Das einzige ist: treewird beim rekursiven Aufrufen der Funktion nie als Argument übergeben, daher denke ich, dass die Zeile tree = typeof tree !== 'undefined' ? tree : [];durchlet tree = [];
Oscar Calderon
nullKönnte dies geändert werden, um parent_ids anstelle von 0 zuzulassen ? Edit: Nevermind, ich habe es funktioniert durch die Veränderung id: 0an id: null.
dlinx90
Beachten Sie, dass die obige Antwort zwei Schleifen verwendet und daher verbessert werden könnte. Da ich kein npm-Modul finden konnte, das eine O (n) -Lösung implementiert, habe ich das folgende erstellt (Unit-getestet, 100% Codeabdeckung, nur 0,5 KB groß und enthält Typisierungen). Vielleicht hilft es jemandem: npmjs.com/package/performant-array-to-tree
Philip Stanislaus
4
Für alle Interessierten ist der Code leicht in Vanille zu konvertieren js: jsfiddle.net/LkkwH/853
xec
48

(BONUS1: NODES KÖNNEN ODER KÖNNEN NICHT BESTELLT WERDEN)

(BONUS2: KEINE BIBLIOTHEK VON DRITTANBIETERN BENÖTIGT, PLAIN JS)

(BONUS3: Benutzer "Elias Rabl" sagt, dies sei die schnellste Lösung, siehe seine Antwort unten)

Hier ist es:

const createDataTree = dataset => {
    let hashTable = Object.create(null)
    dataset.forEach( aData => hashTable[aData.ID] = { ...aData, childNodes : [] } )
    let dataTree = []
    dataset.forEach( aData => {
      if( aData.parentID ) hashTable[aData.parentID].childNodes.push(hashTable[aData.ID])
      else dataTree.push(hashTable[aData.ID])
    } )
    return dataTree
}

Hier ist ein Test, der Ihnen helfen kann, die Funktionsweise der Lösung zu verstehen:

it('creates a correct shape of dataTree', () => {

    let dataSet = [
        {
            "ID": 1,
            "Phone": "(403) 125-2552",
            "City": "Coevorden",
            "Name": "Grady"
        },
        {
            "ID": 2,
            "parentID": 1,
            "Phone": "(979) 486-1932",
            "City": "Chełm",
            "Name": "Scarlet"
        }
    ]

    let expectedDataTree = [ 
    {
            "ID": 1,
            "Phone": "(403) 125-2552",
            "City": "Coevorden",
            "Name": "Grady",
            childNodes : [
                {
                    "ID": 2,
                    "parentID": 1,
                    "Phone": "(979) 486-1932",
                    "City": "Chełm",
                    "Name": "Scarlet",
                    childNodes : []
                }
            ]
    } 
    ]

  expect( createDataTree(dataSet) ).toEqual(expectedDataTree)
});
FurkanO
quelle
2
Wäre es nicht genauer, wenn wir childNodesnur bei Bedarf hinzufügen würden ? Indem Sie sie von der ersten entfernen forEachund in die zweite verschieben?
Arpl
@arpl stimmte zu. Das kann man bei Bedarf leicht ändern. Oder wenn Sie der Meinung sind, dass dies die Standardeinstellung sein sollte, kann ich dies ändern.
FurkanO
@FurkanO wirklich schöne Lösung, aber wäre es möglich, mit funktionaler Programmierung (keine Mutationen) irgendwo in die Nähe dieser Leistung zu kommen
Dac0d3r
34

Hatte das gleiche Problem, aber ich konnte nicht sicher sein, ob die Daten sortiert waren oder nicht . Ich konnte keine Bibliothek von Drittanbietern verwenden, daher ist dies nur Vanilla Js. Die Eingabedaten können dem Beispiel von @ Stephen entnommen werden.

 var arr = [
        {'id':1 ,'parentid' : 0},
        {'id':4 ,'parentid' : 2},
        {'id':3 ,'parentid' : 1},
        {'id':5 ,'parentid' : 0},
        {'id':6 ,'parentid' : 0},
        {'id':2 ,'parentid' : 1},
        {'id':7 ,'parentid' : 4},
        {'id':8 ,'parentid' : 1}
      ];
    function unflatten(arr) {
      var tree = [],
          mappedArr = {},
          arrElem,
          mappedElem;

      // First map the nodes of the array to an object -> create a hash table.
      for(var i = 0, len = arr.length; i < len; i++) {
        arrElem = arr[i];
        mappedArr[arrElem.id] = arrElem;
        mappedArr[arrElem.id]['children'] = [];
      }


      for (var id in mappedArr) {
        if (mappedArr.hasOwnProperty(id)) {
          mappedElem = mappedArr[id];
          // If the element is not at the root level, add it to its parent array of children.
          if (mappedElem.parentid) {
            mappedArr[mappedElem['parentid']]['children'].push(mappedElem);
          }
          // If the element is at the root level, add it to first level elements array.
          else {
            tree.push(mappedElem);
          }
        }
      }
      return tree;
    }

var tree = unflatten(arr);
document.body.innerHTML = "<pre>" + (JSON.stringify(tree, null, " "))

JS Fiddle

Flaches Array zum Baum

alexandru.pausan
quelle
In einigen Fällen schlug dies mappedArr[mappedElem['parentid']]['children']fehl, da der Zugriff auf childrenundefined nicht möglich ist.
Al-Mothafar
Wie würde ich bei der Eltern-ID beginnen: 1?
Winni
30

Verwenden Sie diesen ES6-Ansatz. Funktioniert wie Charme

// Data Set
// One top level comment 
const comments = [{
    id: 1,
    parent_id: null
}, {
    id: 2,
    parent_id: 1
}, {
    id: 3,
    parent_id: 1
}, {
    id: 4,
    parent_id: 2
}, {
    id: 5,
    parent_id: 4
}];

const nest = (items, id = null, link = 'parent_id') =>
  items
    .filter(item => item[link] === id)
    .map(item => ({ ...item, children: nest(items, item.id) }));

console.log(
  nest(comments)
)

shekhardtu
quelle
2
Die kürzeste und beste Antwort, denke ich
Java-Man-Skript
2
Sloooow im Vergleich zu FurkanOs Antwort
Geza Turi
16

eine einfachere Funktion list-to-tree-lite

npm install list-to-tree-lite

listToTree(list)

Quelle:

function listToTree(data, options) {
    options = options || {};
    var ID_KEY = options.idKey || 'id';
    var PARENT_KEY = options.parentKey || 'parent';
    var CHILDREN_KEY = options.childrenKey || 'children';

    var tree = [],
        childrenOf = {};
    var item, id, parentId;

    for (var i = 0, length = data.length; i < length; i++) {
        item = data[i];
        id = item[ID_KEY];
        parentId = item[PARENT_KEY] || 0;
        // every item may have children
        childrenOf[id] = childrenOf[id] || [];
        // init its children
        item[CHILDREN_KEY] = childrenOf[id];
        if (parentId != 0) {
            // init its parent's children object
            childrenOf[parentId] = childrenOf[parentId] || [];
            // push it into its parent's children object
            childrenOf[parentId].push(item);
        } else {
            tree.push(item);
        }
    };

    return tree;
}

jsfiddle

William Leung
quelle
10

Sie können diese Frage mit nur zwei Zeilen behandeln:

_(flatArray).forEach(f=>
           {f.nodes=_(flatArray).filter(g=>g.parentId==f.id).value();});

var resultArray=_(flatArray).filter(f=>f.parentId==null).value();

Online testen (siehe Browser-Konsole für erstellten Baum)

Bedarf:

1- Installieren Sie lodash 4 (eine Javascript-Bibliothek zum Bearbeiten von Objekten und Sammlungen mit performanten Methoden => wie die Linq in c #) Lodash

2- Ein flatArray wie unten:

    var flatArray=
    [{
      id:1,parentId:null,text:"parent1",nodes:[]
    }
   ,{
      id:2,parentId:null,text:"parent2",nodes:[]
    }
    ,
    {
      id:3,parentId:1,text:"childId3Parent1",nodes:[]
    }
    ,
    {
      id:4,parentId:1,text:"childId4Parent1",nodes:[]
    }
    ,
    {
      id:5,parentId:2,text:"childId5Parent2",nodes:[]
    }
    ,
    {
      id:6,parentId:2,text:"childId6Parent2",nodes:[]
    }
    ,
    {
      id:7,parentId:3,text:"childId7Parent3",nodes:[]
    }
    ,
    {
      id:8,parentId:5,text:"childId8Parent5",nodes:[]
    }];

Vielen Dank, Herr Bakhshabadi

Viel Glück

Iman Bahrampour
quelle
8

Es kann nützlich sein, die Paketliste in den Baum zu installieren:

bower install list-to-tree --save

oder

npm install list-to-tree --save

Zum Beispiel Liste haben:

var list = [
  {
    id: 1,
    parent: 0
  }, {
    id: 2,
    parent: 1
  }, {
    id: 3,
    parent: 1
  }, {
    id: 4,
    parent: 2
  }, {
    id: 5,
    parent: 2
  }, {
    id: 6,
    parent: 0
  }, {
    id: 7,
    parent: 0
  }, {
    id: 8,
    parent: 7
  }, {
    id: 9,
    parent: 8
  }, {
    id: 10,
    parent: 0
  }
];

Verwenden Sie die Paketliste zum Baum:

var ltt = new LTT(list, {
  key_id: 'id',
  key_parent: 'parent'
});
var tree = ltt.GetTree();

Ergebnis:

[{
  "id": 1,
  "parent": 0,
  "child": [
    {
      "id": 2,
      "parent": 1,
      "child": [
        {
          "id": 4,
          "parent": 2
        }, {
          "id": 5, "parent": 2
        }
      ]
    },
    {
      "id": 3,
      "parent": 1
    }
  ]
}, {
  "id": 6,
  "parent": 0
}, {
  "id": 7,
  "parent": 0,
  "child": [
    {
      "id": 8,
      "parent": 7,
      "child": [
        {
          "id": 9,
          "parent": 8
        }
      ]
    }
  ]
}, {
  "id": 10,
  "parent": 0
}];
DenQ
quelle
1
Beachten Sie, dass von Antworten nur mit Links abgeraten wird. SO-Antworten sollten der Endpunkt einer Suche nach einer Lösung sein (im Gegensatz zu einem weiteren Zwischenstopp von Referenzen, die im Laufe der Zeit veralten). Bitte erwägen Sie, hier eine eigenständige Zusammenfassung hinzuzufügen und den Link als Referenz
beizubehalten
Ich verstehe nicht warum die -1, ich denke, dass es eine gute Lösung ist, aber leider finde ich das Paket nicht in gitHub oder in einem anderen öffentlichen Repository
oriaj
Vielen Dank für Ihre Aufmerksamkeit für das Paket. Ich habe vor, es später zu erweitern. Hier ist ein Link zum Repository github.com/DenQ/list-to-tree
DenQ
@oriaj Ich bin froh, dass das Projekt davon profitiert. Die Pläne einiger Ideen
DenQ
Funktioniert gut, danke @DenQ. Ich wünschte, es hätte mehr Testabdeckung!
IliasT
3

Ich habe ein Testskript geschrieben, um die Leistung der beiden allgemeinsten Lösungen zu bewerten (was bedeutet, dass die Eingabe nicht vorher sortiert werden muss und der Code nicht von Bibliotheken von Drittanbietern abhängt), das von den Benutzern shekhardtu vorgeschlagen wurde ( siehe Antwort ). und FurkanO ( siehe Antwort ).

http://playcode.io/316025?tabs=console&script.js&output

Die Lösung von FurkanO scheint die schnellste zu sein.

/*
** performance test for /programming/18017869/build-tree-array-from-flat-array-in-javascript
*/

// Data Set (e.g. nested comments)
var comments = [{
    id: 1,
    parent_id: null
}, {
    id: 2,
    parent_id: 1
}, {
    id: 3,
    parent_id: 4
}, {
    id: 4,
    parent_id: null
}, {
    id: 5,
    parent_id: 4
}];

// add some random entries
let maxParentId = 10000;
for (let i=6; i<=maxParentId; i++)
{
  let randVal = Math.floor((Math.random() * maxParentId) + 1);
  comments.push({
    id: i,
    parent_id: (randVal % 200 === 0 ? null : randVal)
  });
}

// solution from user "shekhardtu" (https://stackoverflow.com/a/55241491/5135171)
const nest = (items, id = null, link = 'parent_id') =>
  items
    .filter(item => item[link] === id)
    .map(item => ({ ...item, children: nest(items, item.id) }));
;

// solution from user "FurkanO" (https://stackoverflow.com/a/40732240/5135171)
const createDataTree = dataset => {
    let hashTable = Object.create(null)
    dataset.forEach( aData => hashTable[aData.id] = { ...aData, children : [] } )
    let dataTree = []
    dataset.forEach( aData => {
      if( aData.parent_id ) hashTable[aData.parent_id].children.push(hashTable[aData.id])
      else dataTree.push(hashTable[aData.id])
    } )
    return dataTree
};


/*
** lets evaluate the timing for both methods
*/
let t0 = performance.now();
let createDataTreeResult = createDataTree(comments);
let t1 = performance.now();
console.log("Call to createDataTree took " + Math.floor(t1 - t0) + " milliseconds.");

t0 = performance.now();
let nestResult = nest(comments);
t1 = performance.now();
console.log("Call to nest took " + Math.floor(t1 - t0) + " milliseconds.");




//console.log(nestResult);
//console.log(createDataTreeResult);

// bad, but simple way of comparing object equality
console.log(JSON.stringify(nestResult)===JSON.stringify(createDataTreeResult));

Elias Rabl
quelle
2

Dies ist ein Vorschlag für ungeordnete Artikel. Diese Funktion arbeitet mit einer einzelnen Schleife und einer Hash-Tabelle und sammelt alle Elemente mit ihren id. Wenn ein Stammknoten gefunden wird, wird das Objekt dem Ergebnisarray hinzugefügt.

function getTree(data, root) {
    var o = {};
    data.forEach(function (a) {
        if (o[a.id] && o[a.id].children) {
            a.children = o[a.id].children;
        }
        o[a.id] = a;
        o[a.parentId] = o[a.parentId] || {};
        o[a.parentId].children = o[a.parentId].children || [];
        o[a.parentId].children.push(a);
    });
    return o[root].children;
}

var data = { People: [{ id: "12", parentId: "0", text: "Man", level: "1", children: null }, { id: "6", parentId: "12", text: "Boy", level: "2", children: null }, { id: "7", parentId: "12", text: "Other", level: "2", children: null }, { id: "9", parentId: "0", text: "Woman", level: "1", children: null }, { id: "11", parentId: "9", text: "Girl", level: "2", children: null }], Animals: [{ id: "5", parentId: "0", text: "Dog", level: "1", children: null }, { id: "8", parentId: "5", text: "Puppy", level: "2", children: null }, { id: "10", parentId: "13", text: "Cat", level: "1", children: null }, { id: "14", parentId: "13", text: "Kitten", level: "2", children: null }] },
    tree = Object.keys(data).reduce(function (r, k) {
        r[k] = getTree(data[k], '0');
        return r;
    }, {});

console.log(tree);
.as-console-wrapper { max-height: 100% !important; top: 0; }

Nina Scholz
quelle
1

mach es auch mit lodashjs (v4.x)

function buildTree(arr){
  var a=_.keyBy(arr, 'id')
  return _
   .chain(arr)
   .groupBy('parentId')
   .forEach(function(v,k){ 
     k!='0' && (a[k].children=(a[k].children||[]).concat(v));
   })
   .result('0')
   .value();
}
walter ye
quelle
1

Ich mag die reine JavaScript-Lösung von @ WilliamLeung, aber manchmal müssen Sie Änderungen am vorhandenen Array vornehmen, um einen Verweis auf das Objekt beizubehalten.

function listToTree(data, options) {
  options = options || {};
  var ID_KEY = options.idKey || 'id';
  var PARENT_KEY = options.parentKey || 'parent';
  var CHILDREN_KEY = options.childrenKey || 'children';

  var item, id, parentId;
  var map = {};
    for(var i = 0; i < data.length; i++ ) { // make cache
    if(data[i][ID_KEY]){
      map[data[i][ID_KEY]] = data[i];
      data[i][CHILDREN_KEY] = [];
    }
  }
  for (var i = 0; i < data.length; i++) {
    if(data[i][PARENT_KEY]) { // is a child
      if(map[data[i][PARENT_KEY]]) // for dirty data
      {
        map[data[i][PARENT_KEY]][CHILDREN_KEY].push(data[i]); // add child to parent
        data.splice( i, 1 ); // remove from root
        i--; // iterator correction
      } else {
        data[i][PARENT_KEY] = 0; // clean dirty data
      }
    }
  };
  return data;
}

Beispiel: https://jsfiddle.net/kqw1qsf0/17/

Hex.style
quelle
1

var data = [{"country":"india","gender":"male","type":"lower","class":"X"},
			{"country":"china","gender":"female","type":"upper"},
			{"country":"india","gender":"female","type":"lower"},
			{"country":"india","gender":"female","type":"upper"}];
var seq = ["country","type","gender","class"];
var treeData = createHieArr(data,seq);
console.log(treeData)
function createHieArr(data,seq){
	var hieObj = createHieobj(data,seq,0),
		hieArr = convertToHieArr(hieObj,"Top Level");
		return [{"name": "Top Level", "parent": "null",
				     "children" : hieArr}]
	function convertToHieArr(eachObj,parent){
		var arr = [];
		for(var i in eachObj){
			arr.push({"name":i,"parent":parent,"children":convertToHieArr(eachObj[i],i)})
		}
		return arr;
	}
	function createHieobj(data,seq,ind){
		var s = seq[ind];
		if(s == undefined){
			return [];
		}
		var childObj = {};
		for(var ele of data){
			if(ele[s] != undefined){
				if(childObj[ele[s]] == undefined){
					childObj[ele[s]] = [];
				}
				childObj[ele[s]].push(ele);
			}
		}
		ind = ind+1;
		for(var ch in childObj){
			childObj[ch] = createHieobj(childObj[ch],seq,ind)
		}
		return childObj;
	}
}

karthik reddy
quelle
Ich habe diese Funktion erstellt, um Daten von einem Array von Objekten in eine Baumstruktur zu konvertieren, die für ein interaktives d3-Baumdiagramm erforderlich ist. Mit nur 40 Codezeilen konnte ich die Ausgabe erhalten. Ich habe diese Funktion auf effiziente Weise geschrieben, indem ich rekursive Funktionalität in js verwendet habe. Versuchen Sie und teilen Sie mir Ihr Feedback mit. Danke dir!!!!
Karthik Reddy
Vielen Dank für die Antwort. Es funktioniert perfekt für meine d3-Baumtopologie. Jetzt muss ich die Knotenfarbe basierend auf den Werten des Knotens ändern. Deshalb muss ich einen Flag-Wert im JSON übergeben . Wie mache ich das? {"Name": "Top Level", "Flag": 1, "Parent": "Null", "Children": [{"Name": "Indien", "Flag": 0 , "Eltern": "Top Level", "Kinder": [
Puneeth Kumar
1

Vielleicht sehen Sie sich das npm-Paket tree-util an Sie sich Es kann auch sehr praktisch sein, wenn Sie Daten aus einer SQL DB-Datentabelle laden möchten. Sie können den Knoten im erstellten Baum auch problemlos zusätzliche Daten hinzufügen.

Haftungsausschluss, ich habe dieses Paket gemacht.

Kristian Abrahamsen
quelle
1

Ich hatte vor ein paar Tagen ein ähnliches Problem, als ich einen Ordnerbaum aus einem flachen Array anzeigen musste. Ich habe hier keine Lösung in TypeScript gesehen, daher hoffe ich, dass sie hilfreich ist.

In meinen Fällen waren die Haupteltern nur eine, auch das rawData-Array muss nicht sortiert werden. Lösungen basieren auf der Vorbereitung von temporären Objekten wie {parentId: [child1, child2, ...] }

Beispiel Rohdaten

const flatData: any[] = Folder.ofCollection([
  {id: '1', title: 'some title' },
  {id: '2', title: 'some title', parentId: 1 },
  {id: '3', title: 'some title', parentId: 7 },
  {id: '4', title: 'some title', parentId: 1 },
  {id: '5', title: 'some title', parentId: 2 },
  {id: '6', title: 'some title', parentId: 5 },
  {id: '7', title: 'some title', parentId: 5 },

]);

def des Ordners

export default class Folder {
    public static of(data: any): Folder {
        return new Folder(data);
    }

    public static ofCollection(objects: any[] = []): Folder[] {
        return objects.map((obj) => new Folder(obj));
    }

    public id: string;
    public parentId: string | null;
    public title: string;
    public children: Folder[];

    constructor(data: any = {}) {
        this.id = data.id;
        this.parentId = data.parentId || null;
        this.title = data.title;
        this.children = data.children || [];
    }
}

LÖSUNG : Funktion, die die Baumstruktur für ein flaches Argument zurückgibt

    public getTree(flatData: any[]): Folder[] {
        const addChildren = (item: Folder) => {
            item.children = tempChild[item.id] || [];
            if (item.children.length) {
                item.children.forEach((child: Folder) => {
                    addChildren(child);
                });
            }
        };

        const tempChild: any = {};
        flatData.forEach((item: Folder) => {
            const parentId = item.parentId || 0;
            Array.isArray(tempChild[parentId]) ? tempChild[parentId].push(item) : (tempChild[parentId] = [item]);
        });

        const tree: Folder[] = tempChild[0];
        tree.forEach((base: Folder) => {
            addChildren(base);
        });
        return tree;
    }
Oskar Kosowski
quelle
0

Hier ist eine einfache Hilfsfunktion, die ich nach dem Vorbild der obigen Antworten erstellt habe und die auf eine Babel-Umgebung zugeschnitten ist:

import { isEmpty } from 'lodash'

export default function unflattenEntities(entities, parent = {id: null}, tree = []) {

  let children = entities.filter( entity => entity.parent_id == parent.id)

  if (!isEmpty( children )) {
    if ( parent.id == null ) {
      tree = children
    } else {
      parent['children'] = children
    }
    children.map( child => unflattenEntities( entities, child ) )
  }

  return tree

}
Eric D. Fields
quelle
0

Hier ist eine modifizierte Version von Steven Harris ', die einfach ES5 ist und ein Objekt zurückgibt, das auf der ID verschlüsselt ist, anstatt ein Array von Knoten sowohl auf der obersten Ebene als auch für die Kinder zurückzugeben.

unflattenToObject = function(array, parent) {
  var tree = {};
  parent = typeof parent !== 'undefined' ? parent : {id: 0};

  var childrenArray = array.filter(function(child) {
    return child.parentid == parent.id;
  });

  if (childrenArray.length > 0) {
    var childrenObject = {};
    // Transform children into a hash/object keyed on token
    childrenArray.forEach(function(child) {
      childrenObject[child.id] = child;
    });
    if (parent.id == 0) {
      tree = childrenObject;
    } else {
      parent['children'] = childrenObject;
    }
    childrenArray.forEach(function(child) {
      unflattenToObject(array, child);
    })
  }

  return tree;
};

var arr = [
    {'id':1 ,'parentid': 0},
    {'id':2 ,'parentid': 1},
    {'id':3 ,'parentid': 1},
    {'id':4 ,'parentid': 2},
    {'id':5 ,'parentid': 0},
    {'id':6 ,'parentid': 0},
    {'id':7 ,'parentid': 4}
];
tree = unflattenToObject(arr);
Nehresman
quelle
0

Dies ist eine modifizierte Version des oben genannten, die mit mehreren Stammelementen funktioniert. Ich verwende GUIDs für meine IDs und übergeordneten IDs. In der Benutzeroberfläche, die sie erstellt, codiere ich Stammelemente fest in etwas wie 0000000-00000-00000-TREE-ROOT-ITEM

var tree = unflatten (Datensätze, "TREE-ROOT-ITEM");

function unflatten(records, rootCategoryId, parent, tree){
    if(!_.isArray(tree)){
        tree = [];
        _.each(records, function(rec){
            if(rec.parentId.indexOf(rootCategoryId)>=0){        // change this line to compare a root id
            //if(rec.parentId == 0 || rec.parentId == null){    // example for 0 or null
                var tmp = angular.copy(rec);
                tmp.children = _.filter(records, function(r){
                    return r.parentId == tmp.id;
                });
                tree.push(tmp);
                //console.log(tree);
                _.each(tmp.children, function(child){
                    return unflatten(records, rootCategoryId, child, tree);
                });
            }
        });
    }
    else{
        if(parent){
            parent.children = _.filter(records, function(r){
                return r.parentId == parent.id;
            });
            _.each(parent.children, function(child){
                return unflatten(records, rootCategoryId, child, tree);
            });
        }
    }
    return tree;
}
Nick Licata
quelle
0

Aus dem Internet kopiert http://jsfiddle.net/stywell/k9x2a3g6/

    function list2tree(data, opt) {
        opt = opt || {};
        var KEY_ID = opt.key_id || 'ID';
        var KEY_PARENT = opt.key_parent || 'FatherID';
        var KEY_CHILD = opt.key_child || 'children';
        var EMPTY_CHILDREN = opt.empty_children;
        var ROOT_ID = opt.root_id || 0;
        var MAP = opt.map || {};
        function getNode(id) {
            var node = []
            for (var i = 0; i < data.length; i++) {
                if (data[i][KEY_PARENT] == id) {
                    for (var k in MAP) {
                        data[i][k] = data[i][MAP[k]];
                    }
                    if (getNode(data[i][KEY_ID]) !== undefined) {
                        data[i][KEY_CHILD] = getNode(data[i][KEY_ID]);
                    } else {
                        if (EMPTY_CHILDREN === null) {
                            data[i][KEY_CHILD] = null;
                        } else if (JSON.stringify(EMPTY_CHILDREN) === '[]') {
                            data[i][KEY_CHILD] = [];
                        }
                    }
                    node.push(data[i]);
                }
            }
            if (node.length == 0) {
                return;
            } else {
                return node;
            }
        }
        return getNode(ROOT_ID)
    }

    var opt = {
        "key_id": "ID",              //节点的ID
        "key_parent": "FatherID",    //节点的父级ID
        "key_child": "children",     //子节点的名称
        "empty_children": [],        //子节点为空时,填充的值  //这个参数为空时,没有子元素的元素不带key_child属性;还可以为null或者[],同理
        "root_id": 0,                //根节点的父级ID
        "map": {                     //在节点内映射一些值  //对象的键是节点的新属性; 对象的值是节点的老属性,会赋值给新属性
            "value": "ID",
            "label": "TypeName",
        }
    };
Stywell
quelle
0

Sie können das npm-Paket array-to-tree https://github.com/alferov/array-to-tree verwenden . Es konvertiert ein einfaches Array von Knoten (mit Zeigern auf übergeordnete Knoten) in eine verschachtelte Datenstruktur.

Behebt ein Problem bei der Konvertierung von aus einer Datenbank abgerufenen Datensätzen in eine verschachtelte Datenstruktur (dh einen Navigationsbaum).

Verwendung:

var arrayToTree = require('array-to-tree');

var dataOne = [
  {
    id: 1,
    name: 'Portfolio',
    parent_id: undefined
  },
  {
    id: 2,
    name: 'Web Development',
    parent_id: 1
  },
  {
    id: 3,
    name: 'Recent Works',
    parent_id: 2
  },
  {
    id: 4,
    name: 'About Me',
    parent_id: undefined
  }
];

arrayToTree(dataOne);

/*
 * Output:
 *
 * Portfolio
 *   Web Development
 *     Recent Works
 * About Me
 */
Денищук Павло Миколайович
quelle
0

Das habe ich in einem Reaktionsprojekt verwendet

// ListToTree.js
import _filter from 'lodash/filter';
import _map from 'lodash/map';

export default (arr, parentIdKey) => _map(_filter(arr, ar => !ar[parentIdKey]), ar => ({
  ...ar,
  children: _filter(arr, { [parentIdKey]: ar.id }),
}));

Verwendung:

// somewhere.js
import ListToTree from '../Transforms/ListToTree';

const arr = [
   {
      "id":"Bci6XhCLZKPXZMUztm1R",
      "name":"Sith"
   },
   {
      "id":"C3D71CMmASiR6FfDPlEy",
      "name":"Luke",
      "parentCategoryId":"ltatOlEkHdVPf49ACCMc"
   },
   {
      "id":"aS8Ag1BQqxkO6iWBFnsf",
      "name":"Obi Wan",
      "parentCategoryId":"ltatOlEkHdVPf49ACCMc"
   },
   {
      "id":"ltatOlEkHdVPf49ACCMc",
      "name":"Jedi"
   },
   {
      "id":"pw3CNdNhnbuxhPar6nOP",
      "name":"Palpatine",
      "parentCategoryId":"Bci6XhCLZKPXZMUztm1R"
   }
];
const response = ListToTree(arr, 'parentCategoryId');

Ausgabe:

[
   {
      "id":"Bci6XhCLZKPXZMUztm1R",
      "name":"Sith",
      "children":[
         {
            "id":"pw3CNdNhnbuxhPar6nOP",
            "name":"Palpatine",
            "parentCategoryId":"Bci6XhCLZKPXZMUztm1R"
         }
      ]
   },
   {
      "id":"ltatOlEkHdVPf49ACCMc",
      "name":"Jedi",
      "children":[
         {
            "id":"C3D71CMmASiR6FfDPlEy",
            "name":"Luke",
            "parentCategoryId":"ltatOlEkHdVPf49ACCMc"
         },
         {
            "id":"aS8Ag1BQqxkO6iWBFnsf",
            "name":"Obi Wan",
            "parentCategoryId":"ltatOlEkHdVPf49ACCMc"
         }
      ]
   }
]```
Cristi Milea
quelle
0

Sie können dieses "treeify" -Paket von Github hier oder NPM verwenden .

Installation:

$ npm install --save-dev treeify-js

user11415035
quelle
0

Meine Typoskript-Lösung hilft Ihnen vielleicht:

type ITreeItem<T> = T & {
    children: ITreeItem<T>[],
};

type IItemKey = string | number;

function createTree<T>(
    flatList: T[],
    idKey: IItemKey,
    parentKey: IItemKey,
): ITreeItem<T>[] {
    const tree: ITreeItem<T>[] = [];

    // hash table.
    const mappedArr = {};
    flatList.forEach(el => {
        const elId: IItemKey = el[idKey];

        mappedArr[elId] = el;
        mappedArr[elId].children = [];
    });

    // also you can use Object.values(mappedArr).forEach(...
    // but if you have element which was nested more than one time
    // you should iterate flatList again:
    flatList.forEach((elem: ITreeItem<T>) => {
        const mappedElem = mappedArr[elem[idKey]];

        if (elem[parentKey]) {
            mappedArr[elem[parentKey]].children.push(elem);
        } else {
            tree.push(mappedElem);
        }
    });

    return tree;
}

Anwendungsbeispiel:

createTree(yourListData, 'id', 'parentId');
Zemil
quelle
0

Ich habe eine ES6-Version geschrieben, die auf der Antwort von @Halcyon basiert

const array = [
  {
    id: '12',
    parentId: '0',
    text: 'one-1'
  },
  {
    id: '6',
    parentId: '12',
    text: 'one-1-6'
  },
  {
    id: '7',
    parentId: '12',
    text: 'one-1-7'
  },

  {
    id: '9',
    parentId: '0',
    text: 'one-2'
  },
  {
    id: '11',
    parentId: '9',
    text: 'one-2-11'
  }
];

// Prevent changes to the original data
const arrayCopy = array.map(item => ({ ...item }));

const listToTree = list => {
  const map = {};
  const roots = [];

  list.forEach((v, i) => {
    map[v.id] = i;
    list[i].children = [];
  });

  list.forEach(v => (v.parentId !== '0' ? list[map[v.parentId]].children.push(v) : roots.push(v)));

  return roots;
};

console.log(listToTree(arrayCopy));

Das Prinzip dieses Algorithmus besteht darin, "map" zu verwenden, um eine Indexbeziehung herzustellen. Es ist einfach, "Element" in der Liste mit "parentId" zu finden und jedem "Element" "Kinder" hinzuzufügen, da "Liste" eine Referenzbeziehung ist, sodass "Wurzeln" Beziehungen zum gesamten Baum aufbauen.

weiya ou
quelle
0

Antwort auf eine ähnliche Frage:

https://stackoverflow.com/a/61575152/7388356

AKTUALISIEREN

Sie können Mapein in ES6 eingeführtes Objekt verwenden. Anstatt Eltern zu finden, indem Sie das Array erneut durchlaufen, erhalten Sie das übergeordnete Element aus dem Array anhand der ID des Elternteils, so wie Sie Elemente in einem Array anhand des Index erhalten.

Hier ist das einfache Beispiel:

const people = [
  {
    id: "12",
    parentId: "0",
    text: "Man",
    level: "1",
    children: null
  },
  {
    id: "6",
    parentId: "12",
    text: "Boy",
    level: "2",
    children: null
  },
  {
    id: "7",
    parentId: "12",
    text: "Other",
    level: "2",
    children: null
  },
  {
    id: "9",
    parentId: "0",
    text: "Woman",
    level: "1",
    children: null
  },
  {
    id: "11",
    parentId: "9",
    text: "Girl",
    level: "2",
    children: null
  }
];

function toTree(arr) {
  let arrMap = new Map(arr.map(item => [item.id, item]));
  let tree = [];

  for (let i = 0; i < arr.length; i++) {
    let item = arr[i];

    if (item.parentId !== "0") {
      let parentItem = arrMap.get(item.parentId);

      if (parentItem) {
        let { children } = parentItem;

        if (children) {
          parentItem.children.push(item);
        } else {
          parentItem.children = [item];
        }
      }
    } else {
      tree.push(item);
    }
  }

  return tree;
}

let tree = toTree(people);

console.log(tree);

Bearbeiten Sie crazy-williams-glgj3

Yusufbek
quelle
1
Während dieser Link die Frage beantworten kann, ist es besser, die wesentlichen Teile der Antwort hier aufzunehmen und den Link als Referenz bereitzustellen. Nur-Link-Antworten können ungültig werden, wenn sich die verknüpfte Seite ändert. - Aus dem Rückblick
JeffRSon
Ok, fügte die Hauptidee hinzu und gab ein Beispielbeispiel,
Yusufbek
0

Basierend auf der Antwort von @ FurkanO habe ich eine andere Version erstellt, die die ursprünglichen Daten nicht mutiert (wie @ Dac0d3r angefordert). Die Antwort von @ shekhardtu hat mir sehr gut gefallen , aber mir wurde klar, dass sie viele Male durch die Daten filtern musste. Ich dachte, eine Lösung könnte darin bestehen, die Antwort von FurkanO zu verwenden, indem zuerst die Daten kopiert werden. Ich habe meine Version in jsperf ausprobiert und die Ergebnisse waren leider (sehr) trostlos ... Es scheint, dass die akzeptierte Antwort wirklich gut ist! Meine Version ist ziemlich konfigurierbar und ausfallsicher, also teile ich sie trotzdem mit euch. Hier ist mein Beitrag:

function unflat(data, options = {}) {
    const { id, parentId, childrenKey } = {
        id: "id",
        parentId: "parentId",
        childrenKey: "children",
        ...options
    };
    const copiesById = data.reduce(
        (copies, datum) => ((copies[datum[id]] = datum) && copies),
        {}
    );
    return Object.values(copiesById).reduce(
        (root, datum) => {
            if ( datum[parentId] && copiesById[datum[parentId]] ) {
                copiesById[datum[parentId]][childrenKey] = [ ...copiesById[datum[parentId]][childrenKey], datum ];
            } else {
                root = [ ...root, datum ];
            }
            return root
        }, []
    );
}

const data = [
    {
        "account": "10",
        "name": "Konto 10",
        "parentAccount": null
    },{
        "account": "1010",
        "name": "Konto 1010",
        "parentAccount": "10"
    },{
        "account": "10101",
        "name": "Konto 10101",
        "parentAccount": "1010"
    },{
        "account": "10102",
        "name": "Konto 10102",
        "parentAccount": "1010"
    },{
        "account": "10103",
        "name": "Konto 10103",
        "parentAccount": "1010"
    },{
        "account": "20",
        "name": "Konto 20",
        "parentAccount": null
    },{
        "account": "2020",
        "name": "Konto 2020",
        "parentAccount": "20"
    },{
        "account": "20201",
        "name": "Konto 20201",
        "parentAccount": "2020"
    },{
        "account": "20202",
        "name": "Konto 20202",
        "parentAccount": "2020"
    }
];

const options = {
    id: "account",
    parentId: "parentAccount",
    childrenKey: "children"
};

console.log(
    "Hierarchical tree",
    unflat(data, options)
);

Mit dem Parameter options kann konfiguriert werden, welche Eigenschaft als ID oder übergeordnete ID verwendet werden soll. Es ist auch möglich, den Namen der Eigenschaft child zu konfigurieren, wenn jemand möchte "childNodes": []oder etwas.

OP könnte einfach Standardoptionen verwenden:

input.People = unflat(input.People);

Wenn die übergeordnete ID falsy (ist null, undefinedoder andere falsy Werte) oder das übergeordnete Objekt existiert nicht, betrachten wir das Objekt ein Wurzelknoten sein.

Pekaaw
quelle
-1
  1. ohne Drittanbieter-Bibliothek
  2. Array muss nicht vorbestellt werden
  3. Sie können jeden Teil des Baumes erhalten, den Sie wollen

Versuche dies

function getUnflatten(arr,parentid){
  let output = []
  for(const obj of arr){
    if(obj.parentid == parentid)

      let children = getUnflatten(arr,obj.id)

      if(children.length){
        obj.children = children
      }
      output.push(obj)
    }
  }

  return output
 }

Testen Sie es auf Jsfiddle

nicht angeschlossen
quelle
-1

Konvertieren Sie das Knotenarray in einen Baum

ES6-Funktion zum Konvertieren eines Array von Knoten (bezogen auf die übergeordnete ID ) - in eine Baumstruktur:

/**
 * Convert nodes list related by parent ID - to tree.
 * @syntax getTree(nodesArray [, rootID [, propertyName]])
 *
 * @param {Array} arr   Array of nodes
 * @param {integer} id  Defaults to 0
 * @param {string} p    Property name. Defaults to "parent_id"
 * @returns {Object}    Nodes tree
 */

const getTree = (arr, p = "parent_id") => arr.reduce((o, n) => {

  if (!o[n.id]) o[n.id] = {};
  if (!o[n[p]]) o[n[p]] = {};
  if (!o[n[p]].nodes) o[n[p]].nodes= [];
  if (o[n.id].nodes) n.nodes= o[n.id].nodes;

  o[n[p]].nodes.push(n);
  o[n.id] = n;

  return o;
}, {});

Generieren Sie eine HTML-Liste aus dem Knotenbaum

Wenn unser Baum vorhanden ist, ist hier eine rekursive Funktion zum Erstellen der UL> LI-Elemente:

/**
 * Convert Tree structure to UL>LI and append to Element
 * @syntax getTree(treeArray [, TargetElement [, onLICreatedCallback ]])
 *
 * @param {Array} tree Tree array of nodes
 * @param {Element} el HTMLElement to insert into
 * @param {function} cb Callback function called on every LI creation
 */

const treeToHTML = (tree, el, cb) => el.append(tree.reduce((ul, n) => {
  const li = document.createElement('li');

  if (cb) cb.call(li, n);
  if (n.nodes?.length) treeToHTML(n.nodes, li, cb);

  ul.append(li);
  return ul;
}, document.createElement('ul')));

Demo-Zeit

Hier ist ein Beispiel mit einem linearen Array von Knoten und der Verwendung der beiden oben genannten Funktionen:

const getTree = (arr, p = "parent_id") => arr.reduce((o, n) => {
  if (!o[n.id]) o[n.id] = {};
  if (!o[n[p]]) o[n[p]] = {};
  if (!o[n[p]].nodes) o[n[p]].nodes = [];
  if (o[n.id].nodes) n.nodes = o[n.id].nodes;
  o[n[p]].nodes.push(n);
  o[n.id] = n;
  return o;
}, {});


const treeToHTML = (tree, el, cb) => el.append(tree.reduce((ul, n) => {
  const li = document.createElement('li');
  if (cb) cb.call(li, n);
  if (n.nodes?.length) treeToHTML(n.nodes, li, cb);
  ul.append(li);
  return ul;
}, document.createElement('ul')));


// DEMO TIME:

const nodesList = [
  {id: 10,  parent_id: 4,  text: "Item 10"}, // PS: Order does not matters
  {id: 1,   parent_id: 0,  text: "Item 1"},  
  {id: 4,   parent_id: 0,  text: "Item 4"},
  {id: 3,   parent_id: 5,  text: "Item 3"},
  {id: 5,   parent_id: 4,  text: "Item 5"},
  {id: 2,   parent_id: 1,  text: "Item 2"},
];
const myTree = getTree(nodesList)[0].nodes; // Get nodes of Root (0)

treeToHTML(myTree, document.querySelector("#tree"), function(node) {
  this.textContent = `(${node.parent_id} ${node.id}) ${node.text}`;
  this._node = node;
  this.addEventListener('click', clickHandler);
});

function clickHandler(ev) {
  if (ev.target !== this) return;
  console.clear();
  console.log(this._node.id);
};
<div id="tree"></div>

Roko C. Buljan
quelle
-1

Dies ist ein alter Thread, aber ich dachte, ein Update tut nie weh. Mit ES6 können Sie Folgendes tun:

const data = [{
    id: 1,
    parent_id: 0
}, {
    id: 2,
    parent_id: 1
}, {
    id: 3,
    parent_id: 1
}, {
    id: 4,
    parent_id: 2
}, {
    id: 5,
    parent_id: 4
}, {
    id: 8,
    parent_id: 7
}, {
    id: 9,
    parent_id: 8
}, {
    id: 10,
    parent_id: 9
}];

const arrayToTree = (items=[], id = null, link = 'parent_id') => items.filter(item => id==null ? !items.some(ele=>ele.id===item[link]) : item[link] === id ).map(item => ({ ...item, children: arrayToTree(items, item.id) }))
const temp1=arrayToTree(data)
console.log(temp1)

const treeToArray = (items=[], key = 'children') => items.reduce((acc, curr) => [...acc, ...treeToArray(curr[key])].map(({ [`${key}`]: child, ...ele }) => ele), items);
const temp2=treeToArray(temp1)

console.log(temp2)

hoffe es hilft jemandem

josesuero
quelle