【问题标题】:ES6 Map: transform valuesES6 Map:转换值
【发布时间】:2018-07-12 06:20:11
【问题描述】:

我正在做一个项目,我经常需要转换 ES6 映射中的每个值:

const positiveMap = new Map(
  [
    ['hello', 1],
    ['world', 2]
  ]
);

const negativeMap = new Map<string, number>();
for (const key of positiveMap.keys()) {
  negativeMap.set(key, positiveMap.get(key) * -1);
}

只是想知道是否有更好的方法来做到这一点?理想情况下是像Array.map() 这样的单行。

奖励积分(不是真的),如果它在打字稿中编译!

【问题讨论】:

  • @AluanHaddad .entries() 返回一个迭代器,而不是一个键/值对数组。那是行不通的。
  • @PatrickRoberts 你是对的。 (用手击中头部)
  • 对于任何关心(关于微基准)的人来说,使用 .forEach 手动复制在 V8 上要快一个数量级。原地变异要快另一个数量级。并不是说它真的很重要

标签: javascript typescript es6-map


【解决方案1】:

您可以使用 Array.from 2nd 参数,一个地图样式的回调:

const positiveMap = new Map([['hello', 1],['world', 2]]),
    negativeMap = new Map(Array.from(positiveMap, ([k, v]) => [k, -v]));

console.log([...negativeMap]);

【讨论】:

  • 它节省了在启动映射之前创建中间数组。
  • 知道为什么这会引发类型错误(在打字稿中)吗? typescriptlang.org/play/…
  • 看起来我可以在 array.from 末尾使用 as [string, number] 强制类型
【解决方案2】:

您可以使用扩展语法... 将其转换为数组,应用map() 方法,然后再次将其转换为Map

const positiveMap = new Map([['hello', 1],['world', 2]]);

const negativeMap = new Map([...positiveMap].map(([k, v]) => [k, v * -1]))
console.log([...negativeMap])

【讨论】:

  • 非常好!正是我想要的。我过去曾遇到过 ts-jest 没有正确地在地图上转换扩展运算符的问题......但这与手头的问题并不真正相关
  • @NSjonas 你可以使用Array.from 而不是[...]
  • 关于如何使其在 TS 中编译的任何想法? typescriptlang.org/play/…*%20-1%5D))%0D%0Aconsole.log(%5B...negativeMap%5D)
  • nvm,只需要用` as [string, number]`强制返回数组即可
【解决方案3】:

如果您愿意,您可以使用自己的类扩展 Map,并包含像数组一样通用迭代它的功能:

class ArrayMap extends Map {
  map (fn, thisArg) {
    const { constructor: Map } = this;
    const map = new Map();
    
    for (const [key, value] of this.entries()) {
      map.set(key, fn.call(thisArg, value, key, this));
    }
    
    return map;
  }
  
  forEach (fn, thisArg) {
    for (const [key, value] of this.entries()) {
      fn.call(thisArg, value, key, this);
    }
  }
  
  reduce (fn, accumulator) {
    const iterator = this.entries();
    
    if (arguments.length < 2) {
      if (this.size === 0) throw new TypeError('Reduce of empty map with no initial value');
      accumulator = iterator.next().value[1];
    }
    
    for (const [key, value] of iterator) {
      accumulator = fn(accumulator, value, key, this);
    }
    
    return accumulator;
  }
  
  every (fn, thisArg) {
    for (const [key, value] of this.entries()) {
      if (!fn.call(thisArg, value, key, this)) return false;
    }
    
    return true;
  }
  
  some (fn, thisArg) {
    for (const [key, value] of this.entries()) {
      if (fn.call(thisArg, value, key, this)) return true;
    }
    
    return false;
  }
  
  // ...
}

const positiveMap = new ArrayMap(
  [
    ['hello', 1],
    ['world', 2]
  ]
);
const negativeMap = positiveMap.map(value => -value);

negativeMap.forEach((value, key) => console.log(key, value));

我免费投入了reduce()every()some()。实施尽可能多或尽可能少的您喜欢或需要的方法。

【讨论】:

  • 您对仅通过原型扩展(使用全局types.d.ts)有何想法?坏主意?
  • 我对 TypeScript 几乎没有经验,但我的一般建议是,如果您要引入新功能,请将其放入新类中,这样您就不会呈现与现有类型定义不兼容的原生类.
【解决方案4】:

你可以有一个基于 trincot 的回答的通用 typescript 函数

function transformMap<K, V, U>(source: Map<K, V>, func: (key: K, value: V) => U): Map<K, U> {
  return new Map(Array.from(source, (v) => [v[0], func(v[0], v[1])]));
}

并像这样使用它

transformMap(positiveMap, (key, value) => -value)

【讨论】:

    猜你喜欢
    • 2016-08-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-04-09
    • 1970-01-01
    相关资源
    最近更新 更多