2016-11-09 3 views
0

У меня есть динамически созданный объект JavaScript, который состоит из вложенных объектов и массивов. Я не смог найти подходящий способ перечислить все вложенные объекты, поскольку этот конкретный объект создается динамически.Как пройти через этот вложенный объект?

Вот объект:

var tagdata = { 
    "Sentence": [{ 
     "NP": [{ 
      "NMP": "cat" 
     }, { 
      "NMP": "dog" 
     }] 
    }, { 
     "VP": [{ 
      "KPD": "tree" 
     }, { 
      "NP": [{ 
       "NMP": "ball" 
      }, { 
       "NMP": "bat" 
      }] 
     },{ 
      "NP": [{ 
       "NMP": "ground" 
      }, { 
       "NMP": "time" 
      }] 
     }] 
    }] 
}; 

Выход я требую выглядит следующим образом:

[{ key: 1, text: 'Sentence' }, 
{ key: 2, text: 'NP', parent: 1 }, 
{ key: 3, text: 'VP', parent: 1 }, 
{ key: 4, text: 'NMP', parent: 2 }, 
{ key: 5, text: 'NMP', parent: 2 }, 
{ key: 6, text: 'KPD', parent: 3 }, 
{ key: 7, text: 'NP', parent: 3 }, 
{ key: 8, text: 'NP', parent: 3 }, 
{ key: 9, text: 'cat', parent: 4 }, 
{ key: 10, text: 'dog', parent: 5 }, 
{ key: 11, text: 'tree', parent: 6 }, 
{ key: 12, text: 'NMP', parent: 7 }, 
{ key: 13, text: 'NMP', parent: 7 }, 
{ key: 14, text: 'NMP', parent: 8 }, 
{ key: 15, text: 'NMP', parent: 8 }, 
{ key: 16, text: 'ball', parent: 12}, 
{ key: 17, text: 'bat', parent: 13}, 
{ key: 18, text: 'ground', parent: 14}, 
{ key: 19, text: 'time', parent: 15},] 

Эти данные будут использоваться в дереве, так что порядок может быть различным, но key: родительские отношения должны поддерживаться. Вот код, я попытался с:

let newtags=[{key:1,text:'Sentence'}]; 
tagdata["Sentence"].map((elem,x) => {  
    newtags.push({key:x,text:Object.keys(elem)[0],parent:x}); 
    if(Object.keys(elem)[0].length !== 0){ 
    var y=x+1; 
    newtags.push({key:y,text:Object.values(elem)[0][x],parent:y}); 
    }  
}); 

console.log(newtags); 

ответ

2

Ваш код работает на первый уровень, но в своей попытке пройти один уровень глубже вы будете назначать повторяющееся ключевых значения (y=x+1 при x будет иметь то значение в следующей итерации метода .map()).

Что вам нужно здесь, это рекурсивная функция, которая называет себя для работы с вложенными уровнями так же, как любой другой уровень.

Вы можете использовать этот ES6, функционального программирования решения для этого:

function listItems(obj) { 
 
    var key = 0; 
 
    return (function recurse(obj, parent = undefined) { 
 
     return Object(obj) !== obj ? { key: ++key, text: obj, parent } 
 
      : Array.isArray(obj) ? Object.keys(obj).reduce((acc, text) => 
 
        acc.concat(recurse(obj[text], parent)), []) 
 
      : Object.keys(obj).reduce((acc, text) => 
 
        acc.concat({ key: ++key, text, parent }, 
 
           recurse(obj[text], key)), []); 
 
    })(obj); 
 
} 
 

 
// Sample data 
 
var tagdata = { 
 
    "Sentence": [{ 
 
     "NP": [{ "NMP": "cat" }, { "NMP": "dog" }] 
 
    }, { 
 
     "VP": [{ 
 
      "KPD": "tree" 
 
     }, { 
 
      "NP": [{ "NMP": "ball" }, { "NMP": "bat" }] 
 
     },{ 
 
      "NP": [{ "NMP": "ground" }, { "NMP": "time" }] 
 
     }] 
 
    }] 
 
}; 
 

 
// Extract the objects and output: 
 
console.log(listItems(tagdata));
.as-console-wrapper { max-height: 100% !important; top: 0; }

+0

Спасибо, что это сработало как шарм. btw ive добавил новый атрибут json вот так: {key: ++ key, fill: blueA400, stroke: "# 4d90fe", текст: obj, parent} , так как его созданный динамически ive решил вызвать функцию внутри json "fill: this.fillcolor (tagname)", но когда я вызываю эту функцию, это говорит, что fillcolor не определен. любая причина, почему я получаю это ?. функция работает довольно хорошо вне json.эта функция используется для возврата цвета в зависимости от имени узла – TRomesh

+0

Трудно сказать, что не так с вашим дополнением. Как вы можете видеть, комментарии не идеальны для того, чтобы говорить о коде. Убедитесь, что контекст действительно таков, что 'это' то, что вы думаете. Не стесняйтесь создавать новый вопрос. Если вы хотите, вы можете сослаться на него, и я могу посмотреть. – trincot

1

Я думаю, что это делает то, что вы хотите. Он использует рекурсивный алгоритм, который обрабатывает случай, когда у вас есть массив отдельно от случая, когда у вас есть объект. Базовый случай только строки обрабатывается в processChild.

let state = []; 
 

 
function processChild(child, parent) { 
 
    if (Array.isArray(child)) { 
 
    return processArray(child, parent); 
 
    } 
 

 
    if (typeof(child) == 'object') { 
 
    return processObject(child, parent); 
 
    } 
 

 
    let tag = { 
 
    key: state.length + 1, 
 
    text: child, 
 
    }; 
 
    if (parent) { 
 
    tag.parent = parent; 
 
    } 
 
    state.push(tag); 
 
} 
 

 
function processObject(object, parent) { 
 
    parent = parent || 0; 
 

 
    let keys = Object.keys(object); 
 
    for (let i = 0; i < keys.length; i++) { 
 
    //console.log(keys[i]); 
 
    let tagIndex = state.length + 1; 
 
    let text = keys[i]; 
 
    let tag = { 
 
     key: tagIndex, 
 
     text: text, 
 
    }; 
 
    if (parent) { 
 
     tag.parent = parent; 
 
    } 
 

 
    state.push(tag); 
 

 
    let child = object[keys[i]]; 
 
    processChild(child, tagIndex); 
 
    } 
 
} 
 

 
function processArray(array, parent) { 
 
    parent = parent || 0; 
 
    for (let i = 0; i < array.length; i++) { 
 
    //console.log(array[i]); 
 
    let child = array[i]; 
 
    //console.log('Child', child); 
 
    processChild(child, parent); 
 
    } 
 
} 
 

 
function process(){ 
 
    let initialState = JSON.parse(input.innerHTML); 
 
    processChild(initialState); 
 
    code.innerHTML = JSON.stringify(state).replace(/},/g,'},\n'); 
 
}
#input{ 
 
    width: 100%; 
 
    height: 200px; 
 
}
<textarea id="input"> 
 
    { 
 
    "Sentence": [{ 
 
    "NP": [{ 
 
     "NMP": "cat" 
 
    }, { 
 
     "NMP": "dog" 
 
    }] 
 
    }, { 
 
    "VP": [{ 
 
     "KPD": "tree" 
 
    }, { 
 
     "NP": [{ 
 
     "NMP": "ball" 
 
     }, { 
 
     "NMP": "bat" 
 
     }] 
 
    }, { 
 
     "NP": [{ 
 
     "NMP": "ground" 
 
     }, { 
 
     "NMP": "time" 
 
     }] 
 
    }] 
 
    }] 
 
} 
 
</textarea> 
 
<button onClick="process()">Process</button> 
 
<pre id="code"></pre>

1

Просто для удовольствия, не-рекурсивный подход.

  • Один массив отслеживает конечные результаты (results)
  • Один массив отслеживает данные, к процессу
  • Когда вложенные данные найдены, то, завернутый в «обеспеченной пункта» и добавил к todo массива
  • Повторяйте до тех пор, никакие пункты не осталось

var tagData = [{Sentence:[{NP:[{NMP:"cat"},{NMP:"dog"}]},{VP:[{KPD:"tree"},{NP:[{NMP:"ball"},{NMP:"bat"}]},{NP:[{NMP:"ground"},{NMP:"time"}]}]}]}]; 
 

 
var isNode = n => Array.isArray(n); 
 
var isLeaf = n => !isNode(n); 
 
var todoItem = parent => node => ({ parent, node }); 
 

 
var flatten = function(arr) { 
 
    var result = [], 
 
     todo = arr.map(todoItem(0)), 
 
     current, node, parent, key, innerNode; 
 

 
    while (todo.length) { 
 
    ({node, parent} = todo.pop()); 
 
    key = result.length + 1; 
 

 
    Object.keys(node).forEach(k => { 
 
     innerNode = node[k]; 
 
     result.push({ key, parent, text: k }); 
 

 
     if (isLeaf(innerNode)) { 
 
     result.push({ 
 
      key: key + 1, 
 
      parent: key, 
 
      text: innerNode 
 
     }); 
 
     } else { 
 
     todo = todo.concat(
 
      innerNode.map(todoItem(key))); 
 
     } 
 
    }); 
 
    }; 
 

 
    return result; 
 
}; 
 

 
// Print output 
 
console.log(
 
    flatten(tagData) 
 
    .map(o => [ 
 
    "key: " + (o.key < 10 ? " " : "") + o.key, 
 
    "parent: " + (o.parent < 10 ? " " : "") + o.parent, 
 
    o.text 
 
    ].join(" | ")) 
 
);
.as-console-wrapper { 
 
    min-height: 100%; 
 
}

Смежные вопросы