简体   繁体   中英

Javascript map with two values in the key

I have 3 dropdowns on my page, the options in the 3rd dropdown depend on the choices in the first two dropdowns.

So I am wondering if there is a way to implement a map in javaScript with a 2-dimensional key? Like <Key1, Key2> -> Value .

I think an easy way is to concatenate two keys into one string. Is there any way that is more decent?

Thanks.

You could have an object that contains more objects:

var options = {
    'option 1': {
        'option 1.1': [
            'option 1.1.1',
            'option 1.1.2',
            'option 1.1.3',
            'option 1.1.4'
        ],
        'option 1.2': [
            'option 1.2.1',
            /* etc. */
};

Then, you would access the options for the third dropdown as options[firstSelectedValue][secondSelectedValue] .


EDIT: Here's a demo, too , using some new features that you may need to implement if you're browsing using Internet Explorer 8 or lower :)

You can set a key as an array. Just create your array [key1, key2]; Then set that value as your key and relate it to your value.

obj[[key1,key2]] = "my value";

Here is a jsFiddle http://jsfiddle.net/TwQLW/

I was looking for a similar data structure, but could not find. I have been working with TypeScript, so I have developed a solution using TypeScript.

export class TwoMapKey<T> {
    private __map__: object;

    constructor() {
        this.__map__ = new Object();
        this.get = this.get.bind(this);
        this.set = this.set.bind(this);
        this.remove = this.remove.bind(this);
        this.keys = this.keys.bind(this);
        this.nestedKeys = this.nestedKeys.bind(this);
        this.clear = this.clear.bind(this);
    }

    public get(key: string, nestedKey: string): T {
        if (!this.__map__[key] || this.__map__[key] && !this.__map__[key][nestedKey])
            return;

        return this.__map__[key][nestedKey];
    }

    public set(key: string, nestedKey: string, value: T): void {
        if (!this.__map__[key]) {
            this.__map__[key] = new Object();
        }

        Object.defineProperty(this.__map__[key], nestedKey, { value: value, configurable: true, enumerable: true });
    }

    public remove(key, nestedKey): void {
        if (!this.__map__[key]) {
            return;
        }

        delete this.__map__[key][nestedKey];
    }

    public keys(): string[] {
        return Object.getOwnPropertyNames(this.__map__);
    }

    public nestedKeys(): Array<string[]> {
        return Object.getOwnPropertyNames(this.__map__).map(key => Object.keys(this.__map__[key]));
    }

    public clear(): void {
        Object.getOwnPropertyNames(this.__map__).forEach(property => {
            delete this.__map__[property];
        });
    } }

You can simply create a map with two keys as below:

let twoKeyMap = new TwoKeyMap<any>();
twoKeyMap.set('mainKey1', 'nestedKey1', {value: 'value'});

Its not as efficent as a HashMap. You should be able to convert the same in ES6 or ES5 easily.

What is wrong with concatenating the two keys? All you need is to be sure, that the concatenated keys are unique, and I guess that this can easily be achieved by separating the two values with a character that is not used by any of the two keys.

I created a generic data structure for this purpose as I had a similar problem:

https://github.com/vikashmadhow/map

I know quite some time has passed since this question was asked; hopefully this might be of help to others.

You can achieve this by adding the two keys as a key array on a hash object using ES6 syntax. Then you can search using array filter and regular expression:

const key1 = "key1";
const key2 = "key2";
const value = "whatever";

const hashObject = {};
const firstEntry = [key1, key2];
const secondEntry = [key2, key1];
const entryValue = { value };

hashObject[firstEntry] = entryValue;
hashObject[secondEntry] = entryValue;

const regByFirstKey = new RegExp(`${key1},.`);
const regBySecondKey = new RegExp(`.,${key2}`);

const keysArray = Object.keys(hashObject);

const resultByFirstKey = (keysArray.filter((key) => regByFirstKey.test(key)))[0];
const resultBySecondKey = (keysArray.filter((key) => regBySecondKey.test(key)))[0];

resultByFirstKey ? console.log(hashObject[resultByFirstKey].value) : undefined;
resultBySecondKey ? console.log(hashObject[resultBySecondKey].value) : undefined;

There is no other way. JS map is plain object, so the key the same as property name. Even if you try to use eg. array as a key, it'll be converted to string. You should concat this string with some special char between or store values in array, and scan it on every access.

/**
 * type Keys = 'key1' | 'key2';
 * const twoKeysMap = new Map<Keys, number>();    
 */
const twoKeysMap = new Map<'key1' | 'key2', number>();

twoKeysMap.set('key1', 1); // -> ok
twoKeysMap.set('key2', 2); // -> ok
twoKeysMap.set('key3', 3); // -> error

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM