JavaScript Map键值对不区分大小写的搜索

Dev*_*vid 1 typescript

我在TypeScript中使用Map字典,并且我希望有get属性并具有不区分大小写的属性。我该如何工作?

    let envVariables = new Map<string, string>();
    envVariables.set('OS', 'Windows_NT');
    envVariables.set('USERNAME', 'SYSTEM');
    if (this.envVariables.has('UserName')) {
      // this should work with case insensitive search
    }
Run Code Online (Sandbox Code Playgroud)

在C#中,Dictionary构造函数只需要StringComparer.OrdinalIgnoreCase,然后字典将不区分大小写。

Kse*_*Ann 7

这是我使用 TypeScript 创建的“真正的”不区分大小写映射的变体:它包含一个存储原始密钥的私有映射。

export class CaseInsensitiveMap<TKey, TVal> extends Map<TKey, TVal> {
    private keysMap = new Map<TKey, TKey>();

    constructor(iterable?: Iterable<[TKey, TVal]>){
        super();
        if (iterable) {
            for (const [key, value] of iterable) {
                this.set(key, value);
            }
        }
    }

    set(key: TKey, value: TVal): this {
        const keyLowerCase = typeof key === 'string'
            ? key.toLowerCase() as any as TKey
            : key;
        this.keysMap.set(keyLowerCase, key);

        return super.set(keyLowerCase, value);
    }

    get(key: TKey): TVal | undefined {
        return typeof key === 'string'
            ? super.get(key.toLowerCase() as any as TKey)
            : super.get(key);
    }

    has(key: TKey): boolean {
        return typeof key === 'string'
            ? super.has(key.toLowerCase() as any as TKey)
            : super.has(key);
    }

    delete(key: TKey): boolean {
        const keyLowerCase = typeof key === 'string'
            ? key.toLowerCase() as any as TKey
            : key;
        this.keysMap.delete(keyLowerCase);

        return super.delete(keyLowerCase);
    }
    
    clear(): void {
        this.keysMap.clear();
        super.clear();
    }

    keys(): IterableIterator<TKey> {
        return this.keysMap.values();
    }

    *entries(): IterableIterator<[TKey, TVal]> {
        const keys = this.keysMap.values();
        const values = super.values();
        for (let i = 0; i < super.size; i++) {
            yield [keys.next().value, values.next().value];
        }
    }

    forEach(callbackfn: (value: TVal, key: TKey, map: Map<TKey, TVal>) => void): void {
        const keys = this.keysMap.values();
        const values = super.values();
        for (let i = 0; i < super.size; i++) {
            callbackfn(values.next().value, keys.next().value, this);
        }
    }

    [Symbol.iterator](): IterableIterator<[TKey, TVal]> {
        return this.entries();
    }
}
Run Code Online (Sandbox Code Playgroud)

  • @XouDo 如果您想保留原始钥匙盒,原始钥匙数组会很方便。所以这是 true-case-insensitive-map,而不是 lower-case-map。 (4认同)
  • @XouDo因为在我的用例中,最好以用户创建值的方式存储值。 (2认同)

Est*_*ask 5

Map不支持此行为。可以扩展它以便以不区分大小写的方式存储和查找密钥。由于Map内部set在构造上使用,因此这是唯一需要增强的方法。

在带有es5target的TypeScript中扩展时,应以特殊方式对待本机类。可以这样完成:

interface CaseInsensitiveMap<T, U> extends Map<T, U> {} 
class CaseInsensitiveMap<T, U> {
  constructor(entries?: Array<[T, U]> | Iterable<[T, U]>) {
    return Reflect.construct(Map, arguments, CaseInsensitiveMap);
  }

  set (key: T, value: U): this {
    if (typeof key === 'string') {
      key = <T><any>key.toLowerCase();
    }
    return Map.prototype.set.call(this, key, value);
  }
}
Run Code Online (Sandbox Code Playgroud)