我的问题更多一些。我有两个数据数组:
var arr = [
{title: "foo", namesIndices: [0,1]},
{title: "bar", namesIndices: [2]},
{title: "baz", namesIndices: [3,4]}
];
var names = [
{name: "John", website: "someUrl"},
{name: "Mike", website: "someUrl"},
{name: "Jane", website: "someUrl"},
{name: "Ali", website: "someUrl"},
{name: "Robert", website: "someUrl"}
];
其中namesIndices将引用names数组中的索引,该索引将与具有其标题的人员对应。为了使这个人的姓名和网站与正确的标题相匹配,以制作这个数组:
var person = [
{name: "John", title: "foo", website: "someUrl"},
{name: "Mike", title: "foo", website: "someUrl"},
{name: "Jane", title: "bar", website: "someUrl"},
{name: "Ali", title: "baz", website: "someUrl"},
{name: "Robert", title: "baz", website: "someUrl"}
];
我不得不遍历第一个数组,然后遍历arr.namesIndices:
var person = [];
for (var i = 0; i < arr.length; i++) {
for (var j = 0; j < arr[i].namesIndices.length; j++) {
var personObj = {};
personObj.title= arr[i].title;
personObj.name = names[arr[i].namesIndices[j]].name;
personObj.website= names[arr[i].namesIndices[j]].website;
person.push(personObj);
}
}
有没有办法在没有嵌套循环的情况下做到这一点?
答案 0 :(得分:1)
如果您愿意,可以使用reduce()
和map()
完全避免显式循环。
var arr = [
{title: "foo", namesIndices: [0,1]},
{title: "bar", namesIndices: [2]},
{title: "baz", namesIndices: [3,4]}
];
var names = [
{name: "John", website: "someUrl"},
{name: "Mike", website: "someUrl"},
{name: "Jane", website: "someUrl"},
{name: "Ali", website: "someUrl"},
{name: "Robert", website: "someUrl"}
];
var person = arr.reduce(function (accumulator, titleAndIndices, arrIndex) {
var newEntries = titleAndIndices.namesIndices.map(function (index) {
var rv = names[index];
rv.title = arr[arrIndex].title;
return rv;
});
return accumulator.concat(newEntries);
}, []);
console.log(person);
答案 1 :(得分:0)
仍然需要两个循环,但它们现在没有嵌套:
var arr = [
{title: "foo", namesIndices: [0, 1]},
{title: "bar", namesIndices: [2]},
{title: "baz", namesIndices: [3, 4, 5]}
];
var names = [
{name: "John", website: "someUrl"},
{name: "Mike", website: "someUrl"},
{name: "Jane", website: "someUrl"},
{name: "Ali", website: "someUrl"},
{name: "Robert", website: "someUrl"}
];
var people = [];
var makePeople = function(title, indices){
for(var i = 0; i < indices.length; i++){
people.push({
name: names[indices[i]].name,
title: title,
website: names[indices[i]].website
});
}
}
for(var i = 0; i < arr.length; i++){
makePeople(arr[i].title, arr[i].nameIndices);
}
虽然它并不完全相同,而且基本上也是一样的。
答案 2 :(得分:0)
有没有办法在没有嵌套循环的情况下做到这一点?
没有。并且没有错误。您的数据采用嵌套格式,因此使用嵌套控件结构使用它是完全自然的。这仍然有O(n)
个复杂性,其中n
是数据量(n = al * ni
长度为arr
,每个项目的平均namesIndices
数< / p>
答案 3 :(得分:0)
如果您愿意销毁arr
数组并重新调整您的names
数组(如接受的答案所做的那样),您可以通过简单的递归函数实现目标。我认为这是无环路的,因为它没有使用循环语法。我认为,除了为每个数组索引编写一个单独的进程的硬编码之外,还有尽可能接近无循环的程度。
递归功能
var person = (function func(obj) {
names[obj.namesIndices.pop()].title = obj.title;
return obj.namesIndices.length ? func(obj) : arr.length ? func(arr.pop()) : names;
})(arr.pop());
如果您使函数跟踪数组索引而不是使用pop(),则可以保留原始数组,但我没有耐心这样做:)。
如果您可以容忍单个循环,那么您可以使用条件语句替换嵌套的循环,以确定要递增的计数器。与前面的示例不同,此示例不会更改原始数组。
单循环
var person = [];
for(var a = arr.length - 1, n = arr[a].namesIndices.length - 1, obj, i;;) {
i = arr[a].namesIndices[n];
obj = names[i];
person[i] = {name: obj.name, website: obj.website, title: arr[a].title};
if(n) n--;
else if(a) n = arr[--a].namesIndices.length - 1;
else break;
}
我还没有正确测试这两种技术的性能,但我相信它至少可以与嵌套循环的性能相媲美,并且优于任何涉及像reduce
这样的数组迭代方法的解决方案。 ,map
,forEach
等