Javascript 将对象数组转换为树
Javascript convert array of objects to tree
我正在尝试转换这个结构:
var initial = [
{ Phase: "Phase 1", Step: "Step 1", Task: "Task 1", Value: "5" },
{ Phase: "Phase 1", Step: "Step 1", Task: "Task 2", Value: "10" },
{ Phase: "Phase 1", Step: "Step 2", Task: "Task 1", Value: "15" },
{ Phase: "Phase 1", Step: "Step 2", Task: "Task 2", Value: "20" },
{ Phase: "Phase 2", Step: "Step 1", Task: "Task 1", Value: "25" },
{ Phase: "Phase 2", Step: "Step 1", Task: "Task 2", Value: "30" },
{ Phase: "Phase 2", Step: "Step 2", Task: "Task 1", Value: "35" },
{ Phase: "Phase 2", Step: "Step 2", Task: "Task 2", Value: "40" }
];
给这个:
var example = {
"Phase 1": {
"Step 1": {
"Task 1": { Phase: "Phase 1", Step: "Step 1", Task: "Task 1", Value: "5" },
"Task 2": { Phase: "Phase 1", Step: "Step 1", Task: "Task 2", Value: "10" }
} ,
"Step 2": {
"Task 1": { Phase: "Phase 1", Step: "Step 2", Task: "Task 1", Value: "15" },
"Task 2": { Phase: "Phase 1", Step: "Step 2", Task: "Task 2", Value: "20" }
}
} ,
"Phase 2": {
"Step 1": {
"Task 1": { Phase: "Phase 2", Step: "Step 1", Task: "Task 1", Value: "25" },
"Task 2": { Phase: "Phase 2", Step: "Step 1", Task: "Task 2", Value: "30" },
} ,
"Step 2": {
"Task 1": { Phase: "Phase 2", Step: "Step 2", Task: "Task 1", Value: "35" },
"Task 2": { Phase: "Phase 2", Step: "Step 2", Task: "Task 2", Value: "40" }
}
}
};
所以我可以很容易地提取这样的值example['Phase 2']['Step 1']['Task 1']['Value']
我已经使用像这样的 groupBy
函数完成了第一步:
function groupBy(d, arr) {
return arr.reduce(function(acc, i) {
var p = i[d];
var temp = acc[p] || [];
temp.push(i);
acc[p] = temp;
return acc;
}, {})
}
所以当我这样做时 var groupedByPhase = groupBy('Phase', initial);
我得到 groupedByPhase
:
{
"Phase 1" : [
{ Phase: "Phase 1", Step: "Step 1", Task: "Task 1", Value: "5" },
{ Phase: "Phase 1", Step: "Step 1", Task: "Task 2", Value: "10" },
{ Phase: "Phase 1", Step: "Step 2", Task: "Task 1", Value: "15" },
{ Phase: "Phase 1", Step: "Step 2", Task: "Task 2", Value: "20" },
],
"Phase 2": [
{ Phase: "Phase 2", Step: "Step 1", Task: "Task 1", Value: "25" },
{ Phase: "Phase 2", Step: "Step 1", Task: "Task 2", Value: "30" },
{ Phase: "Phase 2", Step: "Step 2", Task: "Task 1", Value: "35" },
{ Phase: "Phase 2", Step: "Step 2", Task: "Task 2", Value: "40" }
]
}
我也设法使用此功能按步骤分组:
function groupByInNestedObj(item, obj) {
var x = {};
for (var i in obj) {
x[i] = groupBy(item, obj[i]);
}
return x;
}
调用时可以获取groupByInNestedObj('Step', groupBy('Phase', initial))
{
"Phase 1" : {
"Step 1": [
{ Phase: "Phase 1", Step: "Step 1", Task: "Task 1", Value: "5" },
{ Phase: "Phase 1", Step: "Step 1", Task: "Task 2", Value: "10" }],
"Step 2": [
{ Phase: "Phase 1", Step: "Step 2", Task: "Task 1", Value: "15" },
{ Phase: "Phase 1", Step: "Step 2", Task: "Task 2", Value: "20" },
]},
"Phase 2": {
"Step 1:" [
{ Phase: "Phase 2", Step: "Step 1", Task: "Task 1", Value: "25" },
{ Phase: "Phase 2", Step: "Step 1", Task: "Task 2", Value: "30" }],
"Step 2:"[
{ Phase: "Phase 2", Step: "Step 2", Task: "Task 1", Value: "35" },
{ Phase: "Phase 2", Step: "Step 2", Task: "Task 2", Value: "40" }
]}
}
然而我有点卡在这里,做下一个。
理想情况下,我希望能够做到 groupBy("Task", groupBy("Step", groupBy("Phase", initial)))
以便 groupBy 分组在树的最深层。
欢迎任何建议!
注意:我确实尝试了第二步来实现这个功能
function groupByInNestedObj2 (item, obj) {
var x = {};
for(var i in obj) {
for (var j in obj[i]) {
x[i][j] = groupBy(item, obj[i][j]);
}
}
return x;
}
但是好像不行。
注2:前一个函数的第二个版本有效,但并不纯粹,因为它修改了通过它传递的对象
function groupByInNestedObj2 (item, obj) {
var x = {};
for(var i in obj) {
x[i] = obj[i]
for (var j in x[i]) {
x[i][j] = groupBy('Task', x[i][j]);
}
}
return x;
}
所以当我这样做时 var groupByPhaseAndStepAndTask = groupByInNestedObj2('Task', groupByPhaseAndStep)
groupByPhaseAndStep 也被修改了,这是一个不良的副作用。仍在努力。
您可以尝试使用 .reduce
并检查对象是否存在,就像这样
var initial = [
{ Phase: "Phase 1", Step: "Step 1", Task: "Task 1", Value: "5" },
{ Phase: "Phase 1", Step: "Step 1", Task: "Task 2", Value: "10" },
{ Phase: "Phase 1", Step: "Step 2", Task: "Task 1", Value: "15" },
{ Phase: "Phase 1", Step: "Step 2", Task: "Task 2", Value: "20" },
{ Phase: "Phase 2", Step: "Step 1", Task: "Task 1", Value: "25" },
{ Phase: "Phase 2", Step: "Step 1", Task: "Task 2", Value: "30" },
{ Phase: "Phase 2", Step: "Step 2", Task: "Task 1", Value: "35" },
{ Phase: "Phase 2", Step: "Step 2", Task: "Task 2", Value: "40" }
];
var result = initial.reduce(function (prev, current) {
prev[current.Phase] = prev[current.Phase] || {};
prev[current.Phase][current.Step] = prev[current.Phase][current.Step] || {};
prev[current.Phase][current.Step][current.Task] = current;
return prev;
}, {});
console.log(JSON.stringify(result, null, 2));
我们可以用一个 for 循环来做到这一点:
var initial = [
{ Phase: "Phase 1", Step: "Step 1", Task: "Task 1", Value: "5" },
{ Phase: "Phase 1", Step: "Step 1", Task: "Task 2", Value: "10" },
{ Phase: "Phase 1", Step: "Step 2", Task: "Task 1", Value: "15" },
{ Phase: "Phase 1", Step: "Step 2", Task: "Task 2", Value: "20" },
{ Phase: "Phase 2", Step: "Step 1", Task: "Task 1", Value: "25" },
{ Phase: "Phase 2", Step: "Step 1", Task: "Task 2", Value: "30" },
{ Phase: "Phase 2", Step: "Step 2", Task: "Task 1", Value: "35" },
{ Phase: "Phase 2", Step: "Step 2", Task: "Task 2", Value: "40" }
];
var final = {}
initial.forEach(function(d){
if (!final[d.Phase]) //phase not present so make an object
final[d.Phase] = {};
if (!final[d.Phase][d.Step]) //step not present so make an object
final[d.Phase][d.Step] = {};
if (!final[d.Phase][d.Step][d.Task])//task not present so make an object and store the object
final[d.Phase][d.Step][d.Task] = d;
})
console.log(final)
使用 lodash 和这个的更通用的方法 answer:
var initial = [
{ Phase: "Phase 1", Step: "Step 1", Task: "Task 1", Value: "5" },
{ Phase: "Phase 1", Step: "Step 1", Task: "Task 2", Value: "10" },
{ Phase: "Phase 1", Step: "Step 2", Task: "Task 1", Value: "15" },
{ Phase: "Phase 1", Step: "Step 2", Task: "Task 2", Value: "20" },
{ Phase: "Phase 2", Step: "Step 1", Task: "Task 1", Value: "25" },
{ Phase: "Phase 2", Step: "Step 1", Task: "Task 2", Value: "30" },
{ Phase: "Phase 2", Step: "Step 2", Task: "Task 1", Value: "35" },
{ Phase: "Phase 2", Step: "Step 2", Task: "Task 2", Value: "40" }
];
_.mixin({
groupByMulti: function(obj, values, context) {
if (!values.length) return obj;
var byFirst = _.groupBy(obj, _.head(values), context);
for (var prop in byFirst) {
byFirst[prop] = _.groupByMulti(byFirst[prop], _.tail(values), context);
}
return byFirst;
}
});
var tree = _(initial).groupByMulti(['Phase', 'Step', 'Task']);
$('#pre').append(JSON.stringify(tree, null, 3));
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.0.0/lodash.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<pre id='pre'></pre>
我正在尝试转换这个结构:
var initial = [
{ Phase: "Phase 1", Step: "Step 1", Task: "Task 1", Value: "5" },
{ Phase: "Phase 1", Step: "Step 1", Task: "Task 2", Value: "10" },
{ Phase: "Phase 1", Step: "Step 2", Task: "Task 1", Value: "15" },
{ Phase: "Phase 1", Step: "Step 2", Task: "Task 2", Value: "20" },
{ Phase: "Phase 2", Step: "Step 1", Task: "Task 1", Value: "25" },
{ Phase: "Phase 2", Step: "Step 1", Task: "Task 2", Value: "30" },
{ Phase: "Phase 2", Step: "Step 2", Task: "Task 1", Value: "35" },
{ Phase: "Phase 2", Step: "Step 2", Task: "Task 2", Value: "40" }
];
给这个:
var example = {
"Phase 1": {
"Step 1": {
"Task 1": { Phase: "Phase 1", Step: "Step 1", Task: "Task 1", Value: "5" },
"Task 2": { Phase: "Phase 1", Step: "Step 1", Task: "Task 2", Value: "10" }
} ,
"Step 2": {
"Task 1": { Phase: "Phase 1", Step: "Step 2", Task: "Task 1", Value: "15" },
"Task 2": { Phase: "Phase 1", Step: "Step 2", Task: "Task 2", Value: "20" }
}
} ,
"Phase 2": {
"Step 1": {
"Task 1": { Phase: "Phase 2", Step: "Step 1", Task: "Task 1", Value: "25" },
"Task 2": { Phase: "Phase 2", Step: "Step 1", Task: "Task 2", Value: "30" },
} ,
"Step 2": {
"Task 1": { Phase: "Phase 2", Step: "Step 2", Task: "Task 1", Value: "35" },
"Task 2": { Phase: "Phase 2", Step: "Step 2", Task: "Task 2", Value: "40" }
}
}
};
所以我可以很容易地提取这样的值example['Phase 2']['Step 1']['Task 1']['Value']
我已经使用像这样的 groupBy
函数完成了第一步:
function groupBy(d, arr) {
return arr.reduce(function(acc, i) {
var p = i[d];
var temp = acc[p] || [];
temp.push(i);
acc[p] = temp;
return acc;
}, {})
}
所以当我这样做时 var groupedByPhase = groupBy('Phase', initial);
我得到 groupedByPhase
:
{
"Phase 1" : [
{ Phase: "Phase 1", Step: "Step 1", Task: "Task 1", Value: "5" },
{ Phase: "Phase 1", Step: "Step 1", Task: "Task 2", Value: "10" },
{ Phase: "Phase 1", Step: "Step 2", Task: "Task 1", Value: "15" },
{ Phase: "Phase 1", Step: "Step 2", Task: "Task 2", Value: "20" },
],
"Phase 2": [
{ Phase: "Phase 2", Step: "Step 1", Task: "Task 1", Value: "25" },
{ Phase: "Phase 2", Step: "Step 1", Task: "Task 2", Value: "30" },
{ Phase: "Phase 2", Step: "Step 2", Task: "Task 1", Value: "35" },
{ Phase: "Phase 2", Step: "Step 2", Task: "Task 2", Value: "40" }
]
}
我也设法使用此功能按步骤分组:
function groupByInNestedObj(item, obj) {
var x = {};
for (var i in obj) {
x[i] = groupBy(item, obj[i]);
}
return x;
}
调用时可以获取groupByInNestedObj('Step', groupBy('Phase', initial))
{
"Phase 1" : {
"Step 1": [
{ Phase: "Phase 1", Step: "Step 1", Task: "Task 1", Value: "5" },
{ Phase: "Phase 1", Step: "Step 1", Task: "Task 2", Value: "10" }],
"Step 2": [
{ Phase: "Phase 1", Step: "Step 2", Task: "Task 1", Value: "15" },
{ Phase: "Phase 1", Step: "Step 2", Task: "Task 2", Value: "20" },
]},
"Phase 2": {
"Step 1:" [
{ Phase: "Phase 2", Step: "Step 1", Task: "Task 1", Value: "25" },
{ Phase: "Phase 2", Step: "Step 1", Task: "Task 2", Value: "30" }],
"Step 2:"[
{ Phase: "Phase 2", Step: "Step 2", Task: "Task 1", Value: "35" },
{ Phase: "Phase 2", Step: "Step 2", Task: "Task 2", Value: "40" }
]}
}
然而我有点卡在这里,做下一个。
理想情况下,我希望能够做到 groupBy("Task", groupBy("Step", groupBy("Phase", initial)))
以便 groupBy 分组在树的最深层。
欢迎任何建议!
注意:我确实尝试了第二步来实现这个功能
function groupByInNestedObj2 (item, obj) {
var x = {};
for(var i in obj) {
for (var j in obj[i]) {
x[i][j] = groupBy(item, obj[i][j]);
}
}
return x;
}
但是好像不行。
注2:前一个函数的第二个版本有效,但并不纯粹,因为它修改了通过它传递的对象
function groupByInNestedObj2 (item, obj) {
var x = {};
for(var i in obj) {
x[i] = obj[i]
for (var j in x[i]) {
x[i][j] = groupBy('Task', x[i][j]);
}
}
return x;
}
所以当我这样做时 var groupByPhaseAndStepAndTask = groupByInNestedObj2('Task', groupByPhaseAndStep)
groupByPhaseAndStep 也被修改了,这是一个不良的副作用。仍在努力。
您可以尝试使用 .reduce
并检查对象是否存在,就像这样
var initial = [
{ Phase: "Phase 1", Step: "Step 1", Task: "Task 1", Value: "5" },
{ Phase: "Phase 1", Step: "Step 1", Task: "Task 2", Value: "10" },
{ Phase: "Phase 1", Step: "Step 2", Task: "Task 1", Value: "15" },
{ Phase: "Phase 1", Step: "Step 2", Task: "Task 2", Value: "20" },
{ Phase: "Phase 2", Step: "Step 1", Task: "Task 1", Value: "25" },
{ Phase: "Phase 2", Step: "Step 1", Task: "Task 2", Value: "30" },
{ Phase: "Phase 2", Step: "Step 2", Task: "Task 1", Value: "35" },
{ Phase: "Phase 2", Step: "Step 2", Task: "Task 2", Value: "40" }
];
var result = initial.reduce(function (prev, current) {
prev[current.Phase] = prev[current.Phase] || {};
prev[current.Phase][current.Step] = prev[current.Phase][current.Step] || {};
prev[current.Phase][current.Step][current.Task] = current;
return prev;
}, {});
console.log(JSON.stringify(result, null, 2));
我们可以用一个 for 循环来做到这一点:
var initial = [
{ Phase: "Phase 1", Step: "Step 1", Task: "Task 1", Value: "5" },
{ Phase: "Phase 1", Step: "Step 1", Task: "Task 2", Value: "10" },
{ Phase: "Phase 1", Step: "Step 2", Task: "Task 1", Value: "15" },
{ Phase: "Phase 1", Step: "Step 2", Task: "Task 2", Value: "20" },
{ Phase: "Phase 2", Step: "Step 1", Task: "Task 1", Value: "25" },
{ Phase: "Phase 2", Step: "Step 1", Task: "Task 2", Value: "30" },
{ Phase: "Phase 2", Step: "Step 2", Task: "Task 1", Value: "35" },
{ Phase: "Phase 2", Step: "Step 2", Task: "Task 2", Value: "40" }
];
var final = {}
initial.forEach(function(d){
if (!final[d.Phase]) //phase not present so make an object
final[d.Phase] = {};
if (!final[d.Phase][d.Step]) //step not present so make an object
final[d.Phase][d.Step] = {};
if (!final[d.Phase][d.Step][d.Task])//task not present so make an object and store the object
final[d.Phase][d.Step][d.Task] = d;
})
console.log(final)
使用 lodash 和这个的更通用的方法 answer:
var initial = [
{ Phase: "Phase 1", Step: "Step 1", Task: "Task 1", Value: "5" },
{ Phase: "Phase 1", Step: "Step 1", Task: "Task 2", Value: "10" },
{ Phase: "Phase 1", Step: "Step 2", Task: "Task 1", Value: "15" },
{ Phase: "Phase 1", Step: "Step 2", Task: "Task 2", Value: "20" },
{ Phase: "Phase 2", Step: "Step 1", Task: "Task 1", Value: "25" },
{ Phase: "Phase 2", Step: "Step 1", Task: "Task 2", Value: "30" },
{ Phase: "Phase 2", Step: "Step 2", Task: "Task 1", Value: "35" },
{ Phase: "Phase 2", Step: "Step 2", Task: "Task 2", Value: "40" }
];
_.mixin({
groupByMulti: function(obj, values, context) {
if (!values.length) return obj;
var byFirst = _.groupBy(obj, _.head(values), context);
for (var prop in byFirst) {
byFirst[prop] = _.groupByMulti(byFirst[prop], _.tail(values), context);
}
return byFirst;
}
});
var tree = _(initial).groupByMulti(['Phase', 'Step', 'Task']);
$('#pre').append(JSON.stringify(tree, null, 3));
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.0.0/lodash.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<pre id='pre'></pre>