使用来自 javascript 的两个数组的不同值创建 objects 的数组

Create array of objects using distinct values from two arrays with javascript

我的问题有点复杂。我有两个数据数组:

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);
     }
 }

有没有没有嵌套循环的方法来做到这一点?

仍然需要两个循环,但它们现在不是嵌套的:

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);
}

虽然它并没有完全缩短,但它的作用基本相同。

如果您愿意,可以使用 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);

Is there a way to do this without nested loops?

没有。 没有错。您的数据采用嵌套格式,因此使用嵌套控制结构使用它是完全自然的。这仍然具有 O(n) 复杂性,其中 n 是数据量(n = al * ni 具有 arr 长度和每个项目的平均 namesIndices 数量)

如果您愿意销毁 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, 等等