为 cljc 项目复制 Java 的 String.hashCode() 方法
Replicating Java's String.hashCode() method for a cljc project
我有一个项目应该同时作为 clj 和 cljs 项目工作,它目前使用 Java String 的 hashCode 进行哈希处理,我无法更改它。我需要找到一种方法来为 cljs 场景实现相同的解决方案。
我有实现相同哈希过程的 javascript 所需的代码,我认为理想情况下我想将此函数用于 clj 和 cljs 场景,因为它是最快的哈希方法我知道的具体方式。
hashCode = function(stringToHash){
let hash = 0;
if (stringToHash.length === 0) return hash;
let char;
for (i = 0; i < p1.length; i++) {
char = stringToHash.charCodeAt(i);
hash = ((hash << 5) - hash) + char;
hash = hash & hash; // Convert to 32bit integer
}
return hash;
};
另一种选择是在纯 clojure 中重新创建哈希算法,但我认为这会导致性能下降。所以我的问题是如何在我的 cljc 项目中正确地要求这个 js 方法,或者如何在 clojure 中重新创建相同的算法。
这是我的`hashCode.js
goog.provide('hashCode');
/**
* @param {string} stringToHash
* @return {number}
*/
hashCode.hashCode = function(stringToHash){
let hash = 0;
if (stringToHash.length === 0) return hash;
let char;
for (i = 0; i < p1.length; i++) {
char = stringToHash.charCodeAt(i);
hash = ((hash << 5) - hash) + char;
hash = hash & hash; // Convert to 32bit integer
}
return hash;
};
我试过在我的 core.cljc
文件中这样要求 [hashCode :as hs]
但无济于事。
这是一个解决方案:
(ns tst.demo.core
(:use demo.core tupelo.core tupelo.test)
(:require [tupelo.core :as t]) )
(defn str->hashcode
"Work-alike impl of Java String.hashCode() fn"
[str-val]
(let [char-codes (mapv int str-val)
step-fn (fn step-fn [hash-in char-code]
(let [hash-out (+ char-code
(-
(bit-shift-left hash-in 5)
hash-in))
hash-out (bit-and hash-out 0xFFFFFFFF)]
hash-out))
result (reduce step-fn 0 char-codes)]
result))
(dotest
(spy "hello")
(spyx (str->hashcode "hello"))
(spyx (.hashCode "hello"))
)
结果
-------------------------------
Clojure 1.10.0 Java 12
-------------------------------
Testing tst.demo.core
:spy => "hello"
(str->hashcode "hello") => 99162322
(.hashCode "hello") => 99162322
永远记住Clojure/ClojureSciprt备忘单
您的 hashCode.js
是一个闭包库,因此您可以使用 :libs
compiler option to access it. This is described in more detail on the Dependencies 页面。
(请注意,您的来源中有错字;p1
应替换为 stringToHash
。)
这是一个使用 :libs
访问您的实现的示例:
$ clj -m cljs.main -co '{:libs ["hashCode.js"]}' -r
ClojureScript 1.10.520
cljs.user=> (require '[hashCode :as hs])
nil
cljs.user=> (hs/hashCode "hello")
99162322
cljs.user=> (hs/hashCode "abcdef")
-1424385949
(请注意,如果您将 :advanced
:optimizations
, since your code makes use of let
, you would also need to specify :language-in
用作 :es6
。)
该实现到 ClojureScript 的相当直接的转换是:
(defn string-hash [s]
(loop [i 0 h 0]
(if (< i (.-length s))
(let [c (.charCodeAt s i)
h (+ (- (bit-shift-left h 5) h) c)]
(recur (inc i) (bit-and h h)))
h)))
虽然 Closure Library 附带了一个字符串 hashCode 实现,它 documented 与 Java 的 相似 ,但它可能不适合您的使用,因为它不会生成带符号的哈希值:
cljs.user=> (goog.string/hashCode "hello")
99162322
cljs.user=> (goog.string/hashCode "abcdef")
2870581347
我有一个项目应该同时作为 clj 和 cljs 项目工作,它目前使用 Java String 的 hashCode 进行哈希处理,我无法更改它。我需要找到一种方法来为 cljs 场景实现相同的解决方案。
我有实现相同哈希过程的 javascript 所需的代码,我认为理想情况下我想将此函数用于 clj 和 cljs 场景,因为它是最快的哈希方法我知道的具体方式。
hashCode = function(stringToHash){
let hash = 0;
if (stringToHash.length === 0) return hash;
let char;
for (i = 0; i < p1.length; i++) {
char = stringToHash.charCodeAt(i);
hash = ((hash << 5) - hash) + char;
hash = hash & hash; // Convert to 32bit integer
}
return hash;
};
另一种选择是在纯 clojure 中重新创建哈希算法,但我认为这会导致性能下降。所以我的问题是如何在我的 cljc 项目中正确地要求这个 js 方法,或者如何在 clojure 中重新创建相同的算法。
这是我的`hashCode.js
goog.provide('hashCode');
/**
* @param {string} stringToHash
* @return {number}
*/
hashCode.hashCode = function(stringToHash){
let hash = 0;
if (stringToHash.length === 0) return hash;
let char;
for (i = 0; i < p1.length; i++) {
char = stringToHash.charCodeAt(i);
hash = ((hash << 5) - hash) + char;
hash = hash & hash; // Convert to 32bit integer
}
return hash;
};
我试过在我的 core.cljc
文件中这样要求 [hashCode :as hs]
但无济于事。
这是一个解决方案:
(ns tst.demo.core
(:use demo.core tupelo.core tupelo.test)
(:require [tupelo.core :as t]) )
(defn str->hashcode
"Work-alike impl of Java String.hashCode() fn"
[str-val]
(let [char-codes (mapv int str-val)
step-fn (fn step-fn [hash-in char-code]
(let [hash-out (+ char-code
(-
(bit-shift-left hash-in 5)
hash-in))
hash-out (bit-and hash-out 0xFFFFFFFF)]
hash-out))
result (reduce step-fn 0 char-codes)]
result))
(dotest
(spy "hello")
(spyx (str->hashcode "hello"))
(spyx (.hashCode "hello"))
)
结果
-------------------------------
Clojure 1.10.0 Java 12
-------------------------------
Testing tst.demo.core
:spy => "hello"
(str->hashcode "hello") => 99162322
(.hashCode "hello") => 99162322
永远记住Clojure/ClojureSciprt备忘单
您的 hashCode.js
是一个闭包库,因此您可以使用 :libs
compiler option to access it. This is described in more detail on the Dependencies 页面。
(请注意,您的来源中有错字;p1
应替换为 stringToHash
。)
这是一个使用 :libs
访问您的实现的示例:
$ clj -m cljs.main -co '{:libs ["hashCode.js"]}' -r
ClojureScript 1.10.520
cljs.user=> (require '[hashCode :as hs])
nil
cljs.user=> (hs/hashCode "hello")
99162322
cljs.user=> (hs/hashCode "abcdef")
-1424385949
(请注意,如果您将 :advanced
:optimizations
, since your code makes use of let
, you would also need to specify :language-in
用作 :es6
。)
该实现到 ClojureScript 的相当直接的转换是:
(defn string-hash [s]
(loop [i 0 h 0]
(if (< i (.-length s))
(let [c (.charCodeAt s i)
h (+ (- (bit-shift-left h 5) h) c)]
(recur (inc i) (bit-and h h)))
h)))
虽然 Closure Library 附带了一个字符串 hashCode 实现,它 documented 与 Java 的 相似 ,但它可能不适合您的使用,因为它不会生成带符号的哈希值:
cljs.user=> (goog.string/hashCode "hello")
99162322
cljs.user=> (goog.string/hashCode "abcdef")
2870581347