簡體   English   中英

Typescript/Javascript:使用元組作為 Map 的鍵

[英]Typescript/Javascript: using tuple as key of Map

在我的代碼中遇到這個奇怪的錯誤,當使用元組作為我的鍵時,我無法找到從 Map 獲取恆定時間查找的方法。

希望這說明了這個問題,我現在使用的解決方法只是為了讓它工作:

你好.ts:

let map: Map<[number, number], number> = new Map<[number, number], number>()
    .set([0, 0], 48);

console.log(map.get([0,0])); // prints undefined

console.log(map.get(String([0, 0]))); //  compiler:  error TS2345: Argument of type 
// 'string' is not assignable to parameter of type '[number, number]'.

//the work-around:
map.forEach((value: number, key: [number, number]) => {
    if(String(key) === String([0, 0])){
        console.log(value); // prints 48
    }
})

編譯(轉譯?)我正在使用:

tsc hello.ts -target es6

tsc 版本 2.1.6

嘗試了幾件事情使 Map.get() 方法起作用,但沒有取得多大成功。

在 JavaScript(以及作為擴展,TypeScript)中,沒有兩個數組是相等的,除非它們引用同一個數組(即,更改一個的元素也會更改另一個的元素)。 如果您創建一個具有相同元素的新數組,它不會認為它與任何現有數組相等。

因為 Maps 在查找元素時考慮了這種相等性,如果您存儲一個以數組作為鍵的值,則只有再次傳入完全相同的數組引用作為鍵時,才能再次獲取該值:

const map: Map<[ number, number], number> = new Map<[ number, number ], number>();

const a: [ number, number ] = [ 0, 0 ];
const b: [ number, number ] = [ 0, 0 ];

// a and b have the same value, but refer to different arrays so are not equal
a === b; // = false

map.set(a, 123);
map.get(a); // = 123
map.get(b); // = undefined

一種簡單的解決方法是使用字符串或數字作為鍵,因為當它們具有相同的值時,它們總是被認為是相等的:

const map: Map<string, number> = new Map<string, number>();

const a: [ number, number ] = [ 0, 0 ];
const b: [ number, number ] = [ 0, 0 ];

const astr: string = a.join(','); // = '0,0'
const bstr: string = b.join(','); // = '0,0'

// astr and bstr have the same value, and are strings so they are always equal
astr === bstr; // = true

map.set(astr, 123);
map.get(astr); // = 123
map.get(bstr); // = 123

我會創建自己的類來執行此操作,以便我可以輕松使用所有地圖方法:

class MyMap {
    private map = new Map<string, number>();

    set(key: [number, number], value: number): this {
        this.map.set(JSON.stringify(key), value);
        return this;
    }

    get(key: [number, number]): number | undefined {
        return this.map.get(JSON.stringify(key));
    }

    clear() {
        this.map.clear();
    }

    delete(key: [number, number]): boolean {
        return this.map.delete(JSON.stringify(key));
    }

    has(key: [number, number]): boolean {
        return this.map.has(JSON.stringify(key));
    }

    get size() {
        return this.map.size;
    }

    forEach(callbackfn: (value: number, key: [number, number], map: Map<[number, number], number>) => void, thisArg?: any): void {
        this.map.forEach((value, key) => {
            callbackfn.call(thisArg, value, JSON.parse(key), this);
        });
    }
}

操場上的代碼

如您所見,例如forEach將自動為您提供[number, number][number, number]而不是您隨后需要解析的字符串。

用法示例:

let map = new MyMap();
map.set([1, 2], 4);
console.log(map.get([1, 2])) // 4

map.set([3, 4], 20);
map.forEach((v, k) => console.log(k, v));
// prints:
// [1, 2] 4
// [3, 4] 20

在某些情況下(例如,當元組中的第二個值取決於第一個值時)我認為可以使用嵌套映射:

// situation: a map from a tuple of (tableId, rowId) to the row's title

// instead of Map<[number, number], string> where the first number is
// tableId and the second number is rowId, we can have:
const rowTitleMap = Map<number, Map<number, string>>

const title = rowTitleMap.get(2)?.get(4) // can be string or undefined

我不知道這是否適用於 Typescript 或者是否可能存在其他缺點,但這對我來說似乎是一個簡單易用的方法,它將鍵保留為元組:

 const key_map_key_string = (tuple) => JSON.stringify(tuple); const string_identical_tuple_key = (map_for_keying = new Map()) => { let key_map = new Map(); [...map_for_keying.keys()].forEach((key) => key_map.set(key_map_key_string(key), key)); return (tuple) => { const res = key_map.get(key_map_key_string(tuple)); if(res) return res; key_map.set(key_map_key_string(tuple), tuple); return tuple; }; }; const test = () => { let a_map = new Map([ [[1, 2], 'value1'], [[3, 4], 'value2'] ]); const get_key = string_identical_tuple_key(a_map); console.log(a_map.get( get_key([1, 2]) ) === 'value1'); a_map.set(get_key([5, 6]), 'value3'); console.log(a_map.get( get_key([5, 6]) ) === 'value3'); a_map.set(get_key([3, 4]), 'value4'); console.log(JSON.stringify([...a_map])); }; test();

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM