如何有效地构建这个数组?

时间:2016-12-10 12:32:50

标签: javascript arrays node.js

我有一个对象数组,例如:

[
  { a: 3, b: 2, c: 5, d: 6, e: 8 },
  { a: 1, b: 5, c: 3, d: 1, e: 2 }
]

现在我想将其转换为仅包含特定属性值的数组,但不包含对象本身。例如,如果我对abcd感兴趣,结果应如下所示:

[ 3, 2, 5, 6, 1, 5, 3, 1 ]

我目前的做法如下:

const result = _.flatten(data.map(item => [ item.a, item.b, item.c, item.d ]));

是否有更好的(即更高效,甚至更可读)的方式来获得结果?

5 个答案:

答案 0 :(得分:5)

你所拥有的东西对我来说似乎很容易理解,并且很有效足够。但是你可以通过避免所有那些临时数组而不是循环两次来提高效率:

const result = [];
data.forEach(item => result.push(item.a, item.b, item.c, item.d));

示例:

const data = [
  { a: 3, b: 2, c: 5, d: 6, e: 8 },
  { a: 1, b: 5, c: 3, d: 1, e: 2 }
];
const result = [];
data.forEach(item => result.push(item.a, item.b, item.c, item.d));
console.log(result);

有些引擎有效push 非常,而其他引擎并非如此。如果效率是一项关键要求,那么您需要尝试在目标环境中将其与此进行比较:

const result = [];
let index = 0;
let n, l, item;
for (n = 0, l = data.length; n < l; ++n) {
  item = data[n];
  result[index++] = item.a;
  result[index++] = item.b;
  result[index++] = item.c;
  result[index++] = item.d;
}

有三点需要注意:

  1. 直接推送到阵列而不是使用push
  2. 使用简单的for循环代替forEach。使用forEach的绝对开销非常小,以至于从人的角度来看几乎不存在,但是在紧密循环中它的相对开销非常大。
  3. i循环之外声明litemfor。如果我们在for内声明它们,则会在每次循环迭代时重新创建它们,从而增加了开销。 (ES2015对let声明的语义是强大而有用的,但在这种特殊情况下,我们不需要开销。)
  4. 示例:

    const data = [
      { a: 3, b: 2, c: 5, d: 6, e: 8 },
      { a: 1, b: 5, c: 3, d: 1, e: 2 }
    ];
    const result = [];
    let index = 0;
    let n, l, item;
    for (n = 0, l = data.length; n < l; ++n) {
      item = data[n];
      result[index++] = item.a;
      result[index++] = item.b;
      result[index++] = item.c;
      result[index++] = item.d;
    }
    console.log(result);

答案 1 :(得分:1)

您可以使用映射键减少。

&#13;
&#13;
var array = [{ a: 3, b: 2, c: 5, d: 6, e: 8 }, { a: 1, b: 5, c: 3, d: 1, e: 2 }],
    keys = ['a', 'b', 'c', 'd'],
    result = array.reduce((r, a) => r.concat(keys.map(k => a[k])), []);

console.log(result);
&#13;
&#13;
&#13;

答案 2 :(得分:1)

您可以Array.prototype.map()来自阵列中对象的所需键,并将其与Function.prototype.apply()Array.prototype.concat()合并:

&#13;
&#13;
final View view = inflater.inflate(R.layout.fragment_add_user, container, false);
&#13;
&#13;
&#13;

答案 3 :(得分:1)

在ES6中,并没有提出效率要求,你可以写

const input = [
  { a: 3, b: 2, c: 5, d: 6, e: 8 },
  { a: 1, b: 5, c: 3, d: 1, e: 2 }
];

console.log([].concat(...input.map(({a, b, c, d}) => [a, b, c, d])));

如果你真的对效率感兴趣,那就没有什么可以打败

var result = [];
for (let i = 0; i < input.length; i++) {
  const o = input[i];
  result.push(o.a, o.b, o.c, o.d);
}

虽然另一个答案指出,但值得pushresult[cnt++] = val进行基准测试。

答案 4 :(得分:0)

您可以使用2个嵌套的forEach循环来推送输入数组的每个元素的目标值。我在这里提出一个函数接收作为参数的初始数组和作为另一个数组的属性:

var inflate = (data, options) => {
  var results = [];
  data.forEach(x => options.forEach(y => results.push(x[y])));
  return results;
}

console.log(inflate([{ a: 3, b: 2, c: 5, d: 6, e: 8 }, { a: 1, b: 5, c: 3, d: 1, e: 2 }] ,["a","b","c","d"]));