有没有办法让对象过滤器传递没有命名引用的对象?

时间:2017-09-26 00:33:11

标签: javascript arrays sorting

我有以下javascript代码产生所需的结果,即返回objectsArray中的第3和第4个对象,因为它们都包含最大距离。但是,我想知道在调用 objectsArray.filter 时是否有办法不必重新键入数组的名称?我不是想偷懒,只是避免冗余和引入拼写错误的可能性。

function meetsMax(obj) {

    return obj.distance === Math.max.apply(Math, this.map(function(o) { return o.distance; }));
}

const objectsArray = [{ "distance": 1, "name": "first" }, { "distance": 2, "name": "second" }, { "distance": 3, "name": "third" }, { "distance": 3, "name": "fourth" }];

const objMax = objectsArray.filter(meetsMax, objectsArray);

console.log("objMax:", objMax);

我当然不介意任何其他关于使代码更高效和更高效的指针。

4 个答案:

答案 0 :(得分:1)

为什么不使用for循环?它会比你的代码更快。



"use strict";

let start = performance.now();
for (let z = 0; z < 1000; z++) {
    function meetsMax(obj) {

        return obj.distance === Math.max.apply(Math, this.map(function(o) { return o.distance; }));
    }

    const objectsArray = [{ "distance": 1, "name": "first" }, { "distance": 2, "name": "second" }, { "distance": 3, "name": "third" }, { "distance": 3, "name": "fourth" }];

    const objMax = objectsArray.filter(meetsMax, objectsArray);
}
let fin = performance.now() - start;
console.log(fin); // 3.25ms
&#13;
&#13;
&#13;

&#13;
&#13;
"use strict";

let start = performance.now();
for (let z = 0; z < 1000; z++) {
    let a = [{ "distance": 1, "name": "first" }, { "distance": 2, "name": "second" }, { "distance": 3, "name": "third" }, { "distance": 3, "name": "fourth" }];
    let maxDistance = 0;
    let result = [];

    for (let i = 0, max = a.length; i < max; i++) {
        if (a[i].distance > maxDistance) {
            maxDistance = a[i].distance;
        }
    }

    for (let i = 0, max = a.length; i < max; i++) {
        if (a[i].distance === maxDistance) {
            result.push(a[i]);
        }
    }
}
let fin = performance.now() - start;
console.log(fin); // 1.28ms
&#13;
&#13;
&#13;

答案 1 :(得分:1)

JavaScript中的函数调用有一些开销,因此本机代码更有效率和高性能:

var a = [ { "distance": 1, "name": "first" }, { "distance": 2, "name": "second" }, 
          { "distance": 3, "name": "third" }, { "distance": 3, "name": "fourth" } ]

for (var o = a[0], objMax = [o], m = o.distance, d, i = 1; i < a.length; i++) 
    if ((d = (o = a[i]).distance) > m) { objMax = [o]; m = d }
    else if (d === m) objMax[objMax.length] = o

console.log(JSON.stringify(objMax))

还有更短,效率更低的替代方案:

var a = [ { "distance": 1, "name": "first" }, { "distance": 2, "name": "second" }, 
          { "distance": 3, "name": "third" }, { "distance": 3, "name": "fourth" } ]

var d, b = []; a.forEach(o => (b[d = o.distance] = b[d] || []).push(o))

console.log(JSON.stringify(b[b.length - 1]))

答案 2 :(得分:0)

.filter将三个参数传递给数组:当前值,当前值的索引和数组本身。因此,您可以将过滤器功能更改为:

function meetsMax(obj, index, objectsArray) {

    return obj.distance === Math.max.apply(Math, objectsArray.map(function(o) { return o.distance; }));
}

并使用

致电.filter
 objectsArray.filter(meetsMax);

始终read the documentation您正在使用的功能。

  

我当然不介意任何其他关于使代码更高效和更高效的指针。

如果你,只计算一次最大距离,而不是每次迭代数组。例如。你可以这样做:

function filterMax(arr, extractor) {
    const max = arr.reduce(function(max, item) {
      return max < extractor(item) ? extractor(item) : max;
    }, extractor(arr[0]));
    return arr.filter(function(item) {
      return extractor(item) === max;
    });
}

并将其命名为

filterMax(objectsArray, function(obj) { return obj.distance; });

function filterMax(arr, extractor) {
  const max = arr.reduce(function(max, item) {
    return max < extractor(item) ? extractor(item) : max;
  }, extractor(arr[0]));
  return arr.filter(function(item) {
    return extractor(item) === max;
  });
}

const objectsArray = [{ "distance": 1, "name": "first" }, { "distance": 2, "name": "second" }, { "distance": 3, "name": "third" }, { "distance": 3, "name": "fourth" }];

console.log(filterMax(objectsArray, function(obj) {
  return obj.distance;
}));

答案 3 :(得分:0)

根据MDN's Array.prototype.filter(),数组名称是this内部值的可选覆盖。

所以回答原来的问题:

  

我想知道在调用objectsArray.filter时是否有办法不必重新输入数组的名称?

是的,你可以放心地把它留下来。

var filter = function(x) { if (x > 5) return true; };
var arr = [ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
alert(arr.filter(filter).join(","));

甚至更简单(虽然难以阅读):

alert([ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10].filter(function(x) { if (x > 5) return true; }));

您特别询问了object,但是您没有过滤对象,而是过滤对象数组,因此同样适用。

console.log([ {foo: 1}, {foo: 2}, {foo: 3}, {foo: 4}, {foo: 5}, {foo: 6}, {foo: 7}, {foo: 8}, {foo: 9}, {foo: 10}].filter(function(x) { if (x.foo > 5) return true; }));