使用javascript从两个数组中使用不同的值创建对象数组

时间:2015-04-22 22:36:33

标签: javascript arrays loops nested-loops

我的问题更多一些。我有两个数据数组:

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

有没有办法在没有嵌套循环的情况下做到这一点?

4 个答案:

答案 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这样的数组迭代方法的解决方案。 ,mapforEach