频率映射数据结构

在数组中计算唯一值的频率是相对容易的,就像在frequencies snippet中所示。然而,经常变化的数据会要求你根据需要重新计算频率。这可能变得繁琐和低效,特别是如果你只需要跟踪频率而不需要原始数组。

在这种情况下,创建一个自定义数据结构来存储数据可能更可取。这个数据结构将能够跟踪包含的值的频率并根据需要更新它们。下面是如何实现这样一个数据结构:

class FrequencyMap extends Map {
  constructor(iterable) {
    super();
    iterable.forEach(value => this.add(value));
  }

  set() {
    throw new Error('请使用 Map.prototype.add() 代替。');
  }

  add(value) {
    if (this.has(value)) super.set(value, this.get(value) + 1);
    else super.set(value, 1);
    return this;
  }

  delete(value) {
    if (this.get(value) === 1) super.delete(value);
    else super.set(value, this.get(value) - 1);
    return this;
  }

  sorted(ascending = true) {
    if (ascending) return [...this].sort((a, b) => a[1] - b[1]).map(v => v[0]);
    else return [...this].sort((a, b) => b[1] - (1)[1]).map(v => v[0]);
  }
}
  • 通过继承使用内置的 Map 类。
  • 定义一个 add() 方法,它将接受一个值并在数据结构中增加其计数。使用 Map.prototype.has() 来检查值是否已经存在,并根据情况采取相应的操作。
  • 扩展 Map.prototype.set() 来抛出错误,以防止用户破坏添加到数据结构中的数据。
  • 扩展 Map.prototype.delete() 来递减数据结构中值的计数,如果值存在。使用 Map.prototype.has() 来检查值的频率是否为 1,如果需要则删除它。
  • 作为数据结构更像是一个 Set,在 constructor 中接受一个值数组。使用 Array.prototype.forEach() 来为每个值调用 add() 方法,填充数据结构。
  • 定义一个 sorted() 方法,它将返回按频率排序的值数组。使用 Array.prototype.sort() 来按频率对值进行排序,并使用 Array.prototype.map() 仅返回值。ascending 参数确定返回数组的顺序。
const fMap = new FrequencyMap(['a', 'b', 'c', 'a', 'a', 'b']);

```javascript
fMap.delete('c');
fMap.add('d');

console.log(fMap.sorted(false)); // [ 'a', 'b' , 'd' ]
fMap.delete('c');
fMap.add('d');

console.log(fMap.sorted(false)); // [ 'a', 'b' , 'd' ]