Ich habe ein JSON-Objekt mit verschachtelten Kindern, das ich mithilfe von lodash reduzieren und ändern möchte. Im Idealfall hat der überarbeitete JSON einen Wert für die ursprüngliche Ebene, auf der sich die verschachtelten Kinder befanden, und zeigt ihren ursprünglichen Pfad an.

Hier ist ein Beispiel für JSON:

var data = [
    {id: 0, name: 'Australia', children: [
        {id: 10, name: 'Melbourne', children: []},
        {id: 11, name: 'Sydney', children: [
            {id: 100, name: 'Surry Hills', children: []},
            {id: 102, name: 'Darlinghurst', children: []}
        ]},
        {id: 13, name: 'Kambalda', children: []}
    ]},
    {id: 1, name: 'Spain', children: [
        {id: 20, name: 'Barcelona', children: []},
        {id: 21, name: 'Madrid', children: []}
    ]},
    {id: 3, name: 'UK', children: [
        {id: 30, name: 'London', children: [
            {id: 302, name: 'Knightsbridge', children: []},
            {id: 309, name: 'West End', children: []}
        ]},
        {id: 33, name: 'Leeds', children: []},
        {id: 35, name: 'Manchester', children: []}
    ]}
];

Und der transformierte JSON, den ich generieren möchte, ist:

 [
    {id: 0, name: 'Australia', level: 0, pathname: 'Australia'},
    {id: 10, name: 'Melbourne', level: 1, pathname: 'Australia > Melbourne'},
    {id: 11, name: 'Sydney', level: 1, pathname: 'Australia > Sydney'},
    {id: 100, name: 'Surry Hills', level: 2, pathname: 'Australia > Sydney > Surry Hills'},
    {id: 102, name: 'Darlinghurst', level: 2, pathname: 'Australia > Sydney > Darlinghurst'},
    {id: 13, name: 'Kambalda', level: 1, pathname: 'Australia > Kambalda'},
    {id: 1, name: 'Spain', level: 0, pathname: 'Spain'},
    {id: 20, name: 'Barcelona', level: 1, pathname: 'Spain > Barcelona'},
    {id: 21, name: 'Madrid', level: 1, pathname: 'Spain > Madrid'},
    {id: 3, name: 'UK', level: 0, pathname: 'UK'},
    {id: 30, name: 'London', level: 1, pathname: 'UK > London'},
    {id: 302, name: 'Knightsbridge', level: 2, pathname: 'UK > London > Knightsbridge'},
    {id: 309, name: 'West End', level: 2, pathname: 'UK > London > West End'},
    {id: 33, name: 'Leeds', level: 1, pathname: 'UK > Leeds'},
    {id: 35, name: 'Manchester', level: 1, pathname: 'UK > Manchester'}
]

Ich habe mit _.chain, _.flatten und _.pluck gespielt und konnte nichts in die Nähe bringen.

4
lukemcd 20 Aug. 2015 im 23:25

4 Antworten

Beste Antwort

Sie können eine einfache rekursive Hilfsfunktion verwenden, die ein Array von Arrays erzeugt, und dann _.flattenDeep verwenden, um es zu reduzieren. Das macht was du willst:

function flattenMyTree(tree) {
    function recurse(nodes, path) {
        return _.map(nodes, function(node) {
            var newPath = _.union(path, [node.name]);
            return [
                _.assign({pathname: newPath.join(' > '), level: path.length}, _.omit(node, 'children')),
                recurse(node.children, newPath)
            ];
        });
    }
    return _.flattenDeep(recurse(tree, []));
}
7
mik01aj 26 Aug. 2015 im 13:19

Sie können die data - Sammlung in einem neuen Sammlungsarray rekursiv reduzieren. Tippen Sie einfach auf jeden Rückruf für jedes Element, um die Nachkommen rekursiv aufzurufen. Die folgende Lösung verwendet eine verzögerte Auswertung, um bestimmte Felder hinzuzufügen und zu entfernen.

DEMO

var data = [/*...*/];

function getPathHelper(collection, newCollection, path, level) {
  return _.reduce(collection, function(newCollection, item) {
    path += (path? ' > ': '') + item.name;
    newCollection.push(
      _(item)
        .tap(_.partial(getPathHelper, item.children || [], newCollection, path, level + 1))
        .omit('children')
        .set('pathname', path)
        .set('level', level)
        .value()
    );
    return newCollection;
  }, newCollection);
}

function getPath(collection) {
  return _.sortBy(getPathHelper(collection, [], '', 0), 'pathname');
}

console.log(getPath(data));
0
ryeballar 26 Aug. 2015 im 09:46

Dieser gibt Ihnen die erwartete Antwort, aber es ist nicht im idealen funktionalen Stil; Die Idee ist, das Array von außen zu reduzieren. Bei jeder Iteration der while() - Schleife wird das Array um eine Ebene abgeflacht. Elemente dieser Ebene werden an das result angehängt, und untergeordnete Elemente dieser Elemente werden an das children Array angehängt. In der nächsten Iteration reduzieren wir diese Kinder. Wenn das Array children keine weiteren Elemente enthält, haben wir die Verarbeitung der letzten Ebene abgeschlossen. Schließlich sortieren wir die Elemente nach pathname, wodurch Eltern und ihre Kinder effektiv zusammengefasst werden.

var current = data;
var level = 0;
var result = [];
var children = [];

while(current.length > 0) {
    result = result.concat(_.map(current, function(item) {
        if (!_.isArray(item.path)) {
            item.path = [];
        }
        item.path.push(item.name);
        children = children.concat(_.map(item.children, function(child) {
            child.path = item.path.slice();
            return child;
        }));

        item.level = level;
        item.pathname = item.path.join(" > ");

        delete item.path;
        delete item.children;

        return item;
    }));

    current = children;
    children = [];
    level++;
}

result.sort(function(a, b) {
    return a.pathname.localeCompare(b.pathname);
});

console.log(result);
0
Matjaž Drolc 20 Aug. 2015 im 21:37

Dies basiert auf der Antwort von @ mik01aj, wird jedoch in jedem Schritt abgeflacht und ohne das leere Standardarray für {{X0} } Parameter:

var data = [
    {id: 0, name: 'Australia', children: [
        {id: 10, name: 'Melbourne', children: []},
        {id: 11, name: 'Sydney', children: [
            {id: 100, name: 'Surry Hills', children: []},
            {id: 102, name: 'Darlinghurst', children: []}
        ]},
        {id: 13, name: 'Kambalda', children: []}
    ]},
    {id: 1, name: 'Spain', children: [
        {id: 20, name: 'Barcelona', children: []},
        {id: 21, name: 'Madrid', children: []}
    ]},
    {id: 3, name: 'UK', children: [
        {id: 30, name: 'London', children: [
            {id: 302, name: 'Knightsbridge', children: []},
            {id: 309, name: 'West End', children: []}
        ]},
        {id: 33, name: 'Leeds', children: []},
        {id: 35, name: 'Manchester', children: []}
    ]}
];

function flattenMyTree(tree) {
    function recurse(nodes, path) {
        return _.flatMap(nodes, function(node) {
            var newPath = _.union(path, [node.name]);
            return _.concat([
                _.assign({
                        pathname: newPath.join(' > '),
                        level: newPath.length - 1
                    },
                    _.omit(node, 'children'))
                ],
                recurse(node.children, newPath)
            );
        });
    }
    return recurse(tree);
}

console.log(flattenMyTree(data));
<script src="https://cdn.jsdelivr.net/npm/lodash@4.17.11/lodash.min.js"></script>
0
Guillermo Gutiérrez 4 Juli 2019 im 22:45