LoginSignup
1
1

More than 5 years have passed since last update.

Typescript で Map のキーをタプルにしたいとき

Posted at

Typescript で Map のキーをタプルにしたいとき

自分用メモ. Typescript 使っていると, Map オブジェクトのキーにタプルを指定するとうまく動かなかったので
調べてみると, どうやらキー値の比較に === を使っているのでダメなよう.
とりあえず, これができないと困るので以下のような簡易 Map を実装した.
そのうち Map の残りのメソッドに対応する・・かも.

class TupleMap {
  private _values: Object = {};
  protected _clear(): void {
    this._values = {};
  }
  protected _get(key: Array<any>): any {
    if (key == null || key.length == 0) {
      return false;
    }
    let result: any = this._values[key[0]];
    for (let i = 1; i < key.length; i++) {
      if (result == null) {
        break;
      }
      result = result[key[i]];
    }
    return result;
  }
  protected _has(key: Array<any>): boolean {
    return this._get(key) != null;
  }
  private _zip<T1, T2>(a1: T1[], a2: T2[]): [T1, T2][] {
    let result: [T1, T2][] = [];
    for (let i = 0; i < a1.length; i++) {
      result.push([a1[i], a2[i]]);
    }
    return result;
  }
  protected _delete(key: Array<any>): boolean {
    const hasResult = this._has(key);
    if (!hasResult) {
      return false;
    }
    let stack: Object[] = [this._values];
    let result: any = this._values[key[0]];
    for (let i = 1; i < key.length; i++) {
      stack.push(result);
      result = result[key[i]];
    }
    // 削除
    let objs = this._zip(key, stack).reverse();
    delete objs[0][1][objs[0][0]]; // リーフノードは問答無用で削除
    for (let [k, o] of objs.slice(1, objs.length)) {
      // キーに対応するオブジェクトが空の場合には削除
      if (Object.keys(o[k]).length == 0) {
        delete o[k];
      } else {
        break;
      }
    }

    return true;
  }
  protected _set(key: Array<any>, value: any): this {
    if (key == null || key.length == 0) {
      throw new Error("invalid key given");
    }
    if (!(key[0] in this._values)) {
      this._values[key[0]] = {};
    }
    let obj = this._values[key[0]];
    for (let part of key.slice(1, key.length)) {
      if (!(part in obj)) {
        obj[part] = {};
      }
      obj = obj[part];
    }
    obj[key[key.length - 1]] = value;
    return this;
  }
}

interface TupleInterface<T, U> {
  clear(): void;
  get(key: T): U;
  has(key: T): boolean;
  delete(key: T): boolean;
  set(key: T, value: U): this;
}

export class Tuple2Map<T1, T2, U> extends TupleMap
  implements TupleInterface<[T1, T2], U> {
  public clear(): void {
    this._clear();
  }
  public get(key: [T1, T2]): U {
    return this._get(key);
  }
  public has(key: [T1, T2]): boolean {
    return this._has(key);
  }
  public delete(key: [T1, T2]): boolean {
    return this._delete(key);
  }
  public set(key: [T1, T2], value: U): this {
    return this._set(key, value);
  }
}

export class Tuple3Map<T1, T2, T3, U> extends TupleMap
  implements TupleInterface<[T1, T2, T3], U> {
  public clear(): void {
    this._clear();
  }
  public get(key: [T1, T2, T3]): U {
    return this._get(key);
  }
  public has(key: [T1, T2, T3]): boolean {
    return this._has(key);
  }
  public delete(key: [T1, T2, T3]): boolean {
    return this._delete(key);
  }
  public set(key: [T1, T2, T3], value: U): this {
    return this._set(key, value);
  }
}

export class Tuple4Map<T1, T2, T3, T4, U> extends TupleMap
  implements TupleInterface<[T1, T2, T3, T4], U> {
  public clear(): void {
    this._clear();
  }
  public get(key: [T1, T2, T3, T4]): U {
    return this._get(key);
  }
  public has(key: [T1, T2, T3, T4]): boolean {
    return this._has(key);
  }
  public delete(key: [T1, T2, T3, T4]): boolean {
    return this._delete(key);
  }
  public set(key: [T1, T2, T3, T4], value: U): this {
    return this._set(key, value);
  }
}
export class Tuple5Map<T1, T2, T3, T4, T5, U> extends TupleMap
  implements TupleInterface<[T1, T2, T3, T4, T5], U> {
  public clear(): void {
    this._clear();
  }
  public get(key: [T1, T2, T3, T4, T5]): U {
    return this._get(key);
  }
  public has(key: [T1, T2, T3, T4, T5]): boolean {
    return this._has(key);
  }
  public delete(key: [T1, T2, T3, T4, T5]): boolean {
    return this._delete(key);
  }
  public set(key: [T1, T2, T3, T4, T5], value: U): this {
    return this._set(key, value);
  }
}
1
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
1