假设下面的对象数组按code
属性以ascii顺序排序:
var codes = [
{ code: '01' },
{ code: '0101' },
{ code: '0102' },
{ code: '010201' },
{ code: '0103' },
{ code: '02' },
{ code: '0201' },
{ code: '0202' },
];
如何将其转换为这样的嵌套数组:
var nestedCodes = [
{
code: '01',
children: [
{ code: '0101' },
{
code: '0102',
children: [
{ code: '010201' }
]
},
{ code: '0103' }
]
},
{
code: '02',
children: [
{ code: '0201' },
{ code: '0202' }
]
}
];
代码的结构就像连接多个0N
一样,N
可以是1到9之间的数字。请注意,代码来自服务器,并且code
旁还有一些其他属性像title
一样,但是在这个问题中都没关系。
这里的主要思想是为jsTree设置适当的格式。
答案 0 :(得分:1)
您可以使用递归解决方案。想法是维护path
(通过带有正则表达式的String.prototype.match
作为数组)和parent
,在其中要为每个递归调用插入code
。
parent
会跟踪您要在“当前”递归调用中选择的节点,并且path
会帮助您构建parent
,因为您会更深入:
function insert(d, path, parent, arr) {
if (path.length === 0) {
arr.push(Object.assign({}, d));
return;
}
var target = arr.find(e => e.code === parent);
target.children = target.children || [];
insert(d, path.slice(1), parent + path[0], target.children);
}
var codes = [
{ code: '01' },
{ code: '0101' },
{ code: '0102' },
{ code: '010201' },
{ code: '0103' },
{ code: '02' },
{ code: '0201' },
{ code: '0202' },
];
var res = codes.reduce((a, c) => {
var p = c.code.match(/(0[1-9])/g);
insert(c, p.slice(1), p[0], a);
return a;
}, []);
console.log(res);
当然,假设是在插入code
时,其父级已经被插入。
答案 1 :(得分:1)
我花了很多时间来编写将构建所需结构的递归函数。找到了答案here
但是要这样做,必须首先向每个parent
数组添加codes
属性。
我这样做的前提是,每个code
的父级都等同于代码本身,除了最后两个字节。
var codes = [{code: '01' },
{code: '0101' },
{code: '0102' },
{code: '010201'},
{code: '0103' },
{code: '02' },
{code: '0201' },
{code: '0202' },
];
// add parents to each code
codes.forEach(function(c) {
if (c.code.length > 2) {
c.parent = c.code.substr(0, c.code.length - 2);
} else {
c.parent = 'root';
}
});
function find_children(arr, parent) {
var out = [];
for (var i in arr) {
if (arr[i].parent == parent) {
var children = find_children(arr, arr[i].code);
if (children.length) {
arr[i].children = children;
}
out.push(arr[i])
}
}
return out;
}
var nested = find_children(codes,'root');
console.log(nested);
答案 2 :(得分:1)
代码有点长,但是在我看来很容易理解。它非常健壮-不需要对数组进行排序,也不需要存在01
来处理0102
(如果需要)。如果不处理这些情况,代码可能会短得多,但是我认为您可能需要此代码。
首先,从数据中创建一个基于对象的树数据结构。该树具有键和值,并且由于按索引访问为O(1),因此构建起来非常有效。接下来,遍历基于对象的树,然后将每一层转换为数组,从而将基于对象的树转换为最终的基于数组的树数据结构。
我还大量使用了递归,因为递归非常适合创建和遍历树。
与其他答案相比,我的算法具有更好的时间复杂度,因为我在创建树时创建了具有O(1)访问权限的字典/对象。其他算法在每个层中进行搜索,效率低下。我的算法以O(N)运行,而这里的其他答案较短,但以O(N ^ 2)运行。
只需将format
函数复制到您的代码中,它应该很好用。
const codes = [
{ code: '01' },
{ code: '0101' },
{ code: '0102' },
{ code: '010201' },
{ code: '0103' },
{ code: '02' },
{ code: '0201' },
{ code: '0202' },
];
function format(codes) {
// Splits the string into an array of 2-character strings.
const SPLIT_REGEX = /.{2}(?=(.{2})+(?!.))|.{2}$/g;
const codeFragments = codes.map(obj => obj.code.match(SPLIT_REGEX));
// 1. Represent the data as a tree which is more efficient to build.
const tree = {};
function createTree(tree, fragments) {
let node = tree;
fragments.forEach(fragment => {
if (!node[fragment]) {
node[fragment] = {};
}
node = node[fragment];
});
}
codeFragments.forEach(fragments => createTree(tree, fragments));
/* tree will have the structure:
{
"01": {
"01": {},
"02": {
"01": {}
},
"03": {}
},
"02": {
"01": {},
"02": {}
}
}
*/
// 2. Convert the tree structure into the desired format.
function generateCodesFromTree(tree, previous) {
const nestedCodes = [];
Object.keys(tree).forEach(treeNode => {
const code = previous + treeNode;
const children = generateCodesFromTree(tree[treeNode], code);
const nestedCode = { code };
if (children.length > 0) {
nestedCode.children = children;
}
nestedCodes.push(nestedCode);
});
return nestedCodes;
}
return generateCodesFromTree(tree, '');
}
console.log(format(codes));
答案 3 :(得分:0)
只能通过使用递归方法来实现。试试这个。
let codes = [
{ code: '01' },
{ code: '0101' },
{ code: '0102' },
{ code: '010201' },
{ code: '0103' },
{ code: '02' },
{ code: '0201' },
{ code: '0202' },
];
roots = codes.filter(c => c.code.length === 2);
roots.forEach(c => assign(c));
console.log(roots);
function assign(code) {
codes.forEach(c => {
if (c !== code) {
if (code.code === c.code.slice(0, code.code.length)) {
code.children = !code.children ? [c] : [...code.children, c];
assign(code.children[code.children.length - 1]);
}
}
});
}