是否有用于 JavaScript 的 hashmap 库?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/3309760/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-25 00:48:49  来源:igfitidea点击:

Is there a hashmap library for JavaScript?

javascripthashmap

提问by Peeja

In JavaScript, all Objects act a bit like hashmaps. However, the keys to these hashmaps must be strings. If they're not, they're converted with toString(). That means:

在 JavaScript 中,所有对象的行为都有点像 hashmap。但是,这些哈希映射的键必须是字符串。如果不是,则将它们转换为toString(). 这意味着:

var a = {foo: 1};
var b = {bar: 2};
var o = {};
o[a] = 100;
o[b];              // 100
JSON.stringify(o); // '{"[object Object]":100}'

That is, since the toString()of any plain Object is [object Object], they all address the same value.

也就是说,由于toString()任何普通对象的 是[object Object],它们都寻址相同的值。

I'd like to create a hashmap where Objects with the same properties and values address the same value, but objects with different properties or values address different values. That is:

我想创建一个哈希图,其中具有相同属性和值的对象寻址相同的值,但具有不同属性或值的对象寻址不同的值。那是:

var a = {foo: 1};
var b = {bar: 2, baz: 3};
var c = {baz: 3, bar: 2};
var hash = new Hash();
hash.set(a, 100);
hash.get(b);      // undefined
hash.set(b, 200);
hash.get(b);      // 200
hash.get(c);      // 200

My first instinct was to use JSON.stringify()to turn objects into strings, but:

我的第一直觉是使用JSON.stringify()将对象转换为字符串,但是:

var hash = {};
var b = {bar: 2, baz: 3};
var c = {baz: 3, bar: 2};
hash[JSON.stringify(b)] = 100
hash[JSON.stringify(b)] // 100
hash[JSON.stringify(c)] // undefined
JSON.stringify(b)       // '{"bar":2,"baz":3}'
JSON.stringify(c)       // '{"baz":3,"bar":2}'

That is, JSON serialization is order-dependent.

也就是说,JSON 序列化是顺序相关的。

Is there a good library or technique to implement a hashmap like this?

有没有好的库或技术来实现这样的哈希图?

Update:

更新

Equivalently, is there a good hashing function such that:

等效地,是否有一个好的散列函数,使得:

hash({foo: 1, bar: 2}) == hash({bar: 2, foo: 1})

采纳答案by LukeH

Here's a quick proof-of-concept...

这是一个快速的概念验证......

I've hardly tested it at all, and I'm certain that there will be corner-cases that it can't deal with.

我几乎没有测试过它,而且我确信会有它无法处理的极端情况。

Performance will be hideously inefficient because the __createHashfunction needs to recurse through the members of any objects and then sort them, in order to generate a "hash" that meets your requirements.

性能将非常低效,因为该__createHash函数需要递归遍历任何对象的成员,然后对它们进行排序,以生成满足您要求的“散列”。

HashMap = function() {
    this.get = function(key) {
        var hash = this.__createHash(key);
        return this.__map[hash];
    };

    this.set = function(key, value) {
        var hash = this.__createHash(key);
        this.__map[hash] = value;
    };

    this.__createHash = function(key) {
        switch (typeof key) {
            case 'function':
                return 'function';

            case 'undefined':
                return 'undefined';

            case 'string':
                return '"' + key.replace('"', '""') + '"';

            case 'object':
                if (!key) {
                    return 'null';
                }

                switch (Object.prototype.toString.apply(key)) {
                    case '[object Array]':
                        var elements = [];
                        for (var i = 0; i < key.length; i++) {
                            elements.push(this.__createHash(key[i]));
                        }
                        return '[' + elements.join(',') + ']';

                    case '[object Date]':
                        return '#' + key.getUTCFullYear().toString()
                                   + (key.getUTCMonth() + 1).toString()
                                   + key.getUTCDate().toString()
                                   + key.getUTCHours().toString()
                                   + key.getUTCMinutes().toString()
                                   + key.getUTCSeconds().toString() + '#';

                    default:
                        var members = [];
                        for (var m in key) {
                            members.push(m + '=' + this.__createHash(key[m]));
                        }
                        members.sort();
                        return '{' + members.join(',') + '}';
                }

            default:
                return key.toString();
        }
    };

    this.__map = {};
}

回答by CMS

I would recommend you the jshashtableproject from Tim Down.

我会向你推荐Tim Downjshashtable项目 。

回答by mwcz

This is an old question, but ES6 has a feature that may be relevant: Map

这是一个老问题,但 ES6 有一个可能相关的特性: Map

Maps can have arbitrary objects as keys, and arbitrary values as values. The main distinction is that the objects used as keys stay unique, even if objects are identical.

Map 可以将任意对象作为键,将任意值作为值。主要区别在于用作键的对象保持唯一,即使对象相同。

Here's an example:

下面是一个例子:

var map = new WeakMap();

var o1 = {x: 1};
var o2 = {x: 1};

map.set(o1, 'first object');
map.set(o2, 'second object');

// The keys are unique despite the objects being identical.

map.get(o1); // 'first object'
map.get(o2); // 'second object'
map.get({x: 1}); // undefined

JSON.stringifying the objects wouldn't be able to distinguish between o1and o2.

JSON.stringify对象将无法区分o1o2

MDN has more info. There's also a WeakMapwhich doesn't maintain references to the objects used as keys, so they may be garbage collected.

MDN 有更多信息。还有一个WeakMap不维护对用作键的对象的引用,因此它们可能会被垃圾收集。

The Traceur compilerdoesn't yet have official polyfills for Map and Weakmap, but there is an open pull request with polyfills for both. The code for those polyfills (in case anyone wants to add them individually) are here: Mapand WeakMap. Assuming those polyfills work well, you can start using Map or WeakMap today. :)

Traceur编译器还没有为地图和Weakmap官方polyfills,但与polyfills两个开放拉请求。这些 polyfill 的代码(以防有人想单独添加它们)在这里:MapWeakMap。假设这些 polyfill 运行良好,您可以立即开始使用 Map 或 WeakMap。:)

回答by Ingo Bürk

This thread actually led me to find a bug in my current project. However, this is fixed now and my HashMap implementation in my project (https://github.com/Airblader/jsava) will do exactly what you described. Unlike jshashtable, there are no buckets.

这个线程实际上让我在我当前的项目中找到了一个错误。但是,现在已修复,我的项目 ( https://github.com/Airblader/jsava) 中的HashMap 实现将完全按照您的描述执行。与 jshashtable 不同,没有桶。

回答by Dan Stocker

jOrdercould be modified to treat objects with the same properties (but in different order) as identical when performing an index lookup.

可以修改jOrder以在执行索引查找时将具有相同属性(但顺序不同)的对象视为相同。

If you have the object {bar: 2, baz: 3, val: 200}in your list, and you've previously put a fitting index on a jOrder table like this:

如果您{bar: 2, baz: 3, val: 200}的列表中有对象,并且您之前已经在 jOrder 表上放置了一个合适的索引,如下所示:

var table = jOrder(data)
    .index('signature', ['bar', 'baz'], {grouped: true});

Then right now table.where([{bar: 2, baz: 3}])[0].valwill return 200, but table.where([{baz: 3, bar: 2}])[0].valwon't. It wouldn't take much effort though to make it not depend on the order of properties. Let me know if you're interested and I'll push the fix to GitHub as soon as I can.

那么现在table.where([{bar: 2, baz: 3}])[0].val将返回 200,但table.where([{baz: 3, bar: 2}])[0].val不会。让它不依赖于属性的顺序并不需要太多努力。如果您有兴趣,请告诉我,我会尽快将修复程序推送到 GitHub。

回答by Pointy

You could implement your own class with a toStringthat ensures an ordering of keys.

您可以使用toString确保键排序的来实现自己的类。

回答by Andris

Prototype has Hash quite nicely covered http://prototypejs.org/api/hash

Prototype 已经很好地涵盖了 Hash http://prototypejs.org/api/hash

回答by jsn

the answer is to use two arrays, one for keys, one for values.

答案是使用两个数组,一个用于键,一个用于值。

var i = keys.indexOf(key)
if (i == -1)
  {keys.push(key); values.push(value)}
else
  {values[i] = value; }