Eu tenho um arquivo json complexo que eu tenho que manipular com javascript para torná-lo hierárquico, para depois construir uma árvore. Cada entrada do json possui: id: um ID exclusivo, parentId: o ID do nó pai (que é 0 se o nó é a raiz da árvore) nível: o nível de profundidade na árvore
Os dados json já estão "ordenados". Quero dizer que uma entrada terá acima de si um nó pai ou nó irmão e, por si só, um nó filho ou um nó irmão.
Entrada :
{
"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
},
]
}
Saída esperada:
{
"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
}
}
]
}
javascript
arrays
list
tree
Franck
fonte
fonte
parentId
dos0
meios não exista pai e deve ser a camada superior.Respostas:
Existe uma solução eficiente se você usar uma pesquisa de mapa. Se os pais sempre vêm antes de seus filhos, você pode mesclar os dois for-loops. Ele suporta múltiplas raízes. Ocorre um erro nos ramos pendentes, mas pode ser modificado para ignorá-los. Não requer uma biblioteca de terceiros. É, até onde eu sei, a solução mais rápida.
Se você está na teoria da complexidade, esta solução é Θ (n log (n)). A solução de filtro recursivo é Θ (n ^ 2), o que pode ser um problema para grandes conjuntos de dados.
fonte
map
qual (em teoria) é O (log n).Conforme mencionado por @Sander, a resposta do @ Halcyon assume uma matriz pré-classificada, o seguinte não. (No entanto, assume que você carregou underscore.js - embora possa ser escrito em javascript vanilla):
Código
Exigências
Ele assume que as propriedades 'id' e 'parentid' indicam ID e ID pai, respectivamente. Deve haver elementos com o ID pai 0, caso contrário, você obterá uma matriz vazia de volta. Elementos órfãos e seus descendentes estão "perdidos"
http://jsfiddle.net/LkkwH/1/
fonte
else { parent['children'] = []; }
após a primeira se cláusula para garantir que cada nó tem um atributochildren
(ele vai estar vazio se o nó é um nó folha)tree
nunca é passado como argumento ao chamar a função recursivamente, então acho que a linhatree = typeof tree !== 'undefined' ? tree : [];
pode ser substituída por #let tree = [];
null
parent_ids em vez de 0? Edit: Deixaid: 0
pra lá, eu consegui trabalhar alterando o paraid: null
.(BÔNUS1: NÓS PODEM OU NÃO PODEM SER ENCOMENDADOS)
(BÔNUS2: NENHUMA BIBLIOTECA DE TERCEIROS NECESSÁRIA, JS LISO)
(BÔNUS3: O usuário "Elias Rabl" diz que esta é a solução mais rápida, veja a resposta abaixo)
Aqui está:
Aqui está um teste, que pode ajudá-lo a entender como a solução funciona:
fonte
childNodes
apenas quando necessário? Removendo-os do primeiroforEach
e movendo-os para dentro do segundo?Tinha o mesmo problema, mas não podia ter certeza de que os dados foram classificados ou não . Eu não poderia usar uma biblioteca de terceiros, então isso é apenas Js baunilha; Os dados de entrada podem ser obtidos no exemplo de @ Stephen;
JS Fiddle
Matriz plana para árvore
fonte
mappedArr[mappedElem['parentid']]['children']
falhou, pois não é possível acessar ochildren
de indefinido.Use esta abordagem ES6. Funciona como charme
fonte
uma função mais simples list-to-tree-lite
npm install list-to-tree-lite
listToTree(list)
fonte:
jsfiddle
fonte
Você pode lidar com essa questão com apenas duas linhas de codificação:
Teste on-line (consulte o console do navegador para obter a árvore criada)
Requisitos:
1- Instale o lodash 4 (uma biblioteca Javascript para manipular objetos e coleções com métodos de desempenho => como o Linq em c #) Lodash
2- Um flatArray como abaixo:
Obrigado Mr. Bakhshabadi
Boa sorte
fonte
Pode ser uma instalação útil da lista de árvores para pacotes :
ou
Por exemplo, tenha uma lista:
Use a lista de pacotes para a árvore:
Resultado:
fonte
Escrevi um script de teste para avaliar o desempenho das duas soluções mais gerais (o que significa que a entrada não precisa ser classificada com antecedência e que o código não depende de bibliotecas de terceiros), proposto pelos usuários shekhardtu ( consulte a resposta ) e FurkanO ( ver resposta ).
http://playcode.io/316025?tabs=console&script.js&output
A solução da FurkanO parece ser a mais rápida.
fonte
Esta é uma proposta para itens não ordenados. Essa função funciona com um único loop e uma tabela de hash e coleta todos os itens com os respectivos
id
. Se um nó raiz for encontrado, o objeto será adicionado à matriz de resultados.fonte
também faça isso com lodashjs (v4.x)
fonte
Eu gosto da solução JavaScript pura do @ WilliamLeung, mas às vezes você precisa fazer alterações na matriz existente para manter uma referência ao objeto.
Exapmle: https://jsfiddle.net/kqw1qsf0/17/
fonte
fonte
Você pode dar uma olhada no pacote npm tree-util. Também pode ser muito útil se você deseja carregar dados de uma tabela de dados do banco de dados SQL. Você também pode adicionar facilmente dados extras aos nós na árvore criada.
Isenção, eu fiz este pacote.
fonte
Eu tive um problema semelhante há alguns dias atrás, quando tenho que exibir a árvore de pastas da matriz plana. Não encontrei nenhuma solução no TypeScript aqui, por isso espero que seja útil.
Nos meus casos, o pai principal era apenas um, também o array rawData não precisa ser classificado. As soluções baseiam-se em preparar o objeto temporário como
{parentId: [child1, child2, ...] }
exemplo de dados brutos
def da pasta
SOLUÇÃO : Função que retorna estrutura de árvore para argumento plano
fonte
Aqui está uma função auxiliar simples que criei modelada com base nas respostas acima, adaptada ao ambiente Babel:
fonte
Aqui está uma versão modificada do Steven Harris ', que é simples ES5 e retorna um objeto digitado no ID em vez de retornar uma matriz de nós no nível superior e para os filhos.
fonte
Esta é uma versão modificada acima, que funciona com vários itens raiz; eu uso GUIDs para meus IDs e parentIds; portanto, na interface do usuário que os cria, codifico os itens raiz para algo como 0000000-00000-00000-TREE-ROOT-ITEM
árvore de var = não plana (registros "ITEM DE ÁRVORE-ÁRVORE");
fonte
Copiado da Internet http://jsfiddle.net/stywell/k9x2a3g6/
fonte
Você pode usar o pacote npm array-to-tree https://github.com/alferov/array-to-tree . É converter uma matriz simples de nós (com ponteiros para nós pais) em uma estrutura de dados aninhada.
Resolve um problema com a conversão de recuperados de um conjunto de dados do banco de dados em uma estrutura de dados aninhada (por exemplo, árvore de navegação).
Uso:
fonte
isto é o que eu usei em um projeto de reação
uso:
resultado:
fonte
Você pode usar este pacote "treeify" no Github aqui ou no NPM .
Instalação:
$ npm install --save-dev treeify-js
fonte
Minha solução datilografada, talvez isso ajude você:
Exemplo de uso:
fonte
Eu escrevi uma versão ES6 com base na resposta @Halcyon
O princípio desse algoritmo é usar "map" para estabelecer um relacionamento de índice. É fácil encontrar "item" na lista por "parentId" e adicionar "filhos" a cada "item", porque "list" é um relacionamento de referência, de modo que "raízes" criarão relacionamentos com toda a árvore.
fonte
Responda a uma pergunta semelhante:
https://stackoverflow.com/a/61575152/7388356
ATUALIZAR
Você pode usar
Map
objeto introduzido no ES6. Basicamente, em vez de encontrar os pais repetindo a matriz novamente, você apenas obtém o item pai da matriz pelo ID do pai, como obtém itens em uma matriz pelo índice.Aqui está o exemplo simples:
fonte
Com base na resposta de @ FurkanO , criei outra versão que não altera os dados originais (como @ Dac0d3r solicitado). Eu realmente gostei da resposta de @ shekhardtu , mas percebi que precisava filtrar os dados várias vezes. Eu pensei que uma solução poderia ser usar a resposta do FurkanO copiando os dados primeiro. Eu tentei minha versão no jsperf , e os resultados foram infelizmente (muito) sombrios ... Parece que a resposta aceita é realmente boa! Minha versão é bastante configurável e à prova de falhas, então eu a compartilho com vocês de qualquer maneira; aqui está minha contribuição:
Com o parâmetro options, é possível configurar qual propriedade usar como id ou pai. Também é possível configurar o nome da propriedade children, se alguém quiser
"childNodes": []
ou algo assim.O OP poderia simplesmente usar as opções padrão:
Se o ID pai é (Falsas
null
,undefined
valores Falsas ou outros) ou o objeto pai não existe, nós consideramos o objeto a ser um nó raiz.fonte
Tente isto
Teste no Jsfiddle
fonte
Converter matriz de nós em árvore
Função ES6 para converter uma matriz de nós (relacionada pelo ID pai ) - em uma estrutura em árvore:
Gerar lista HTML da árvore de nós
Tendo nossa árvore no lugar, aqui está uma função recursiva para criar os elementos UL> LI:
Hora de demonstração
Aqui está um exemplo com uma matriz linear de nós e usando as duas funções acima:
fonte
Este é um tópico antigo, mas achei que uma atualização nunca é demais. Com o ES6, você pode:
espero que ajude alguém
fonte