如何过滤JavaScript Map?

Phi*_*ßen 15 javascript ecmascript-6

给定ES6 Map和谓词函数,如何安全地删除地图的所有非匹配元素?


我找不到官方的API函数,但我可以想到两个实现.第一个不会尝试就地删除,而是创建一个副本:

// version 1:
function filter(map, pred) {
  const result = new Map();
  for (let [k, v] of map) {
    if (pred(k,v)) {
      result.set(k, v);
    }
  }
  return result;
}

const map = new Map().set(1,"one").set(2,"two").set(3,"three");
const even = filter(map, (k,v) => k % 2 === 0);
console.log([...even]); // Output: "[ [ 2, 'two' ] ]"
Run Code Online (Sandbox Code Playgroud)

另一个就地删除.在我的测试中,它可以工作,但我没有找到保证修改映射不会破坏迭代器(for-of循环):

// version 2:
function deleteIfNot(map, pred) {
  for (let [k, v] of map) {
    if (!pred(k,v)) {
      map.delete(k);
    }
  }
  return map;
}

const map = new Map().set(1,"one").set(2,"two").set(3,"three");
deleteIfNot(map, (k,v) => k % 2 === 0);
console.log([...map]); // Output: "[ [ 2, 'two' ] ]"
Run Code Online (Sandbox Code Playgroud)

题:

  • 所有平台上的第二个版本(就地删除)是否正确?
  • 有没有更好的方法来实现就地过滤器?也许我错过了一些官方API?

Rom*_*man 15

如果我们想使用.filter()迭代器,我们可以应用一个简单的技巧,因为ES6 Maps没有.filter运算符.Axel Rauschmayer博士的方法是:

  • 将地图转换为[key,value]对数组。
  • 映射或过滤数组。
  • 将结果转换回地图。

例:

const map0 = new Map([
  ['a', 1],
  ['b', 2],
  ['c', 3]
]);

const map1 = new Map(
  [...map0]
  .filter(([k, v]) => v < 3 )
);

console.info([...map1]); //[0: ["a", 1], 1: ["b", 2]]
Run Code Online (Sandbox Code Playgroud)

  • 我很好奇与已接受的答案相比,其性能如何。中间数组需要分配吗? (4认同)
  • `[...map0]` 的另一种编写方式是 `Array.from(map0)`。 (4认同)

Est*_*ask 7

在循环内删除条目时,ES6迭代没有问题.

没有特殊的API可以有效地过滤ES6映射条目而无需迭代它们.

如果映射不必是不可变的并且应该就地修改,则在过滤时创建新映射会产生开销.

还有Map forEach,但它也假设也会使用值.

由于地图仅通过其键进行过滤,因此对于入口对象没有用处.可以通过迭代映射键来改进它:

for (let k of map.keys()) {
  if (!(k % 2))
    map.delete(k);
}
Run Code Online (Sandbox Code Playgroud)