code

객체 유형을 허용하는 해시 코드 함수가 있습니까?

starcafe 2023. 10. 20. 13:53
반응형

객체 유형을 허용하는 해시 코드 함수가 있습니까?

기본적으로, 저는 독특한 물건들로 이루어진 물건, 집합을 만들려고 노력하고 있습니다.속성 이름에 객체가 있는 자바스크립트 객체를 사용하는 아이디어를 생각해 냈습니다.예를 들어,

set[obj] = true;

어느 정도까지는 효과가 있습니다.문자열과 숫자에는 적합하지만 다른 개체에서는 모두 동일한 값으로 "해시"되고 동일한 속성에 액세스하는 것처럼 보입니다.개체에 대한 고유한 해시 값을 생성할 수 있는 방법이 있습니까?문자열과 숫자는 어떻게 사용하나요, 같은 동작을 무시해도 되나요?

자바스크립트의 자바와 같은 hashCode() 함수를 원한다면, 이것은 당신의 것입니다.

function hashCode(string){
    var hash = 0;
    for (var i = 0; i < string.length; i++) {
        var code = string.charCodeAt(i);
        hash = ((hash<<5)-hash)+code;
        hash = hash & hash; // Convert to 32bit integer
    }
    return hash;
}

그것이 자바(비트와이즈 연산자)에서의 구현 방식입니다.

hashCode는 양수일 수도 있고 음수일 수도 있으며, 일반적인 경우에는 음수 값을 제공하는 hashCode는 음수일 수도 있습니다.그래서, 당신은 당신이 사용하는 것을 고려할 수 있습니다.Math.abs()이 기능과 함께

자바스크립트 개체는 문자열만 키로 사용할 수 있습니다(다른 모든 것은 문자열로 변환됩니다).

또는 해당 개체를 색인화하는 배열을 유지 관리하고 해당 색인 문자열을 개체에 대한 참조로 사용할 수도 있습니다.이와 같은 것:

var ObjectReference = [];
ObjectReference.push(obj);

set['ObjectReference.' + ObjectReference.indexOf(obj)] = true;

분명히 약간 장황하지만, 당신은 그것을 처리하는 몇 가지 방법을 써서 모든 사람들을 멋대로 만들고 설정할 수 있습니다.

편집:

이는 자바스크립트에서 정의된 동작입니다. 즉, 속성 이름으로 사용할 객체에 자신의 toString 함수를 정의할 수 있음을 의미하는 toString 변환이 발생합니다. - ollij

해시할 개체에 대한 toString 메서드를 정의하고 해시 식별자를 구성할 수 있는 또 다른 흥미로운 점이 나타납니다.

이를 위한 가장 쉬운 방법은 각 개체에 고유한 고유한 기능을 부여하는 것입니다.toString방법:

(function() {
    var id = 0;

    /*global MyObject */
    MyObject = function() {
        this.objectId = '<#MyObject:' + (id++) + '>';
        this.toString= function() {
            return this.objectId;
        };
    };
})();

저도 같은 문제를 겪었고, 이것은 최소한의 소란으로 완벽하게 해결해 주었고, 좀 더 쉽게 살찐 자바 스타일을 다시 구현할 수 있었습니다.Hashtable 추가하기equals()그리고.hashCode()오브젝트 클래스에 적용할 수 있습니다.해시에 '<#MyObject:12> 문자열을 붙이지 않도록 해야 합니다. 그렇지 않으면 해당 ID로 나가는 개체에 대한 항목이 삭제됩니다.

이제 내 모든 해시는 완전히 식었습니다.저도 며칠 전에 이 정확한 주제에 대해 블로그에 글을 올렸습니다.

설명한 내용은 ECMAscript 6 사양(JavaScript의 다음 버전)의 일부인 Harmony WickMaps에서 다룹니다.즉, 키가 정의되지 않은 것을 포함하여 모든 것이 될 수 있고 셀 수 없는 집합입니다.

즉, 값에 연결된 키(모든 개체!)에 대한 직접적인 참조가 없는 한 값에 대한 참조를 가져오는 것이 불가능합니다.효율성 및 가비지 수집과 관련된 여러 엔진 구현 이유에서 중요하지만 데이터 전송자를 노출하지 않고 취소 가능한 액세스 권한 및 데이터 전달과 같은 새로운 의미를 허용한다는 점에서 매우 멋집니다.

MDN에서:

var wm1 = new WeakMap(),
    wm2 = new WeakMap();
var o1 = {},
    o2 = function(){},
    o3 = window;

wm1.set(o1, 37);
wm1.set(o2, "azerty");
wm2.set(o1, o2); // A value can be anything, including an object or a function.
wm2.set(o3, undefined);
wm2.set(wm1, wm2); // Keys and values can be any objects. Even WeakMaps!

wm1.get(o2); // "azerty"
wm2.get(o2); // Undefined, because there is no value for o2 on wm2.
wm2.get(o3); // Undefined, because that is the set value.

wm1.has(o2); // True
wm2.has(o2); // False
wm2.has(o3); // True (even if the value itself is 'undefined').

wm1.has(o1);   // True
wm1.delete(o1);
wm1.has(o1);   // False

WickMaps는 현재 Firefox, Chrome 및 Edge에서 사용할 수 있습니다. 및 v7과 됩니다를 --harmony-weak-maps깃발을 올리다

제가 선택한 솔루션은 Daniel의 솔루션과 비슷하지만 객체 팩토리를 사용하고 toString을 재정의하기보다는 getHashCode 함수를 통해 처음 요청할 때 명시적으로 객체에 해시를 추가합니다.조금 지저분하긴 하지만 제 필요에는 더 낫습니다 :)

Function.prototype.getHashCode = (function(id) {
    return function() {
        if (!this.hashCode) {
            this.hashCode = '<hash|#' + (id++) + '>';
        }
        return this.hashCode;
    }
}(0));

나의 구체적인 상황에서 나는 키와 원시적인 가치에 관한 한 객체의 동일성에만 관심을 갖습니다.제게 도움이 된 솔루션은 객체를 JSON 표현으로 변환하여 해시로 사용하는 것이었습니다.키 정의 순서가 일관성이 없을 가능성이 있는 등의 한계가 있지만, 이 객체들이 모두 한 곳에서 생성되기 때문에 제게 효과가 있다고 말씀드린 것처럼 말입니다.

var hashtable = {};

var myObject = {a:0,b:1,c:2};

var hash = JSON.stringify(myObject);
// '{"a":0,"b":1,"c":2}'

hashtable[hash] = myObject;
// {
//   '{"a":0,"b":1,"c":2}': myObject
// }

얼마전에 작은 자바스크립트 모듈을 조립하여 문자열, 객체, 배열 등에 대한 해시코드를 제작하였습니다. (저는 방금 GitHub에 커밋하였습니다 :)

용도:

Hashcode.value("stackoverflow")
// -2559914341
Hashcode.value({ 'site' : "stackoverflow" })
// -3579752159

ECMA ECMA 6이 Set원하는 방식으로 작동합니다. https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Set

이미 최신 크롬, FF, IE11에서 사용 가능합니다.

자바스크립트 사양에서는 인덱스된 속성 액세스를 인덱스 이름에 대해 문자열로 변환하는 것으로 정의하고 있습니다.예를들면,

myObject[myProperty] = ...;

와 같음

myObject[myProperty.toString()] = ...;

이것은 자바스크립트에서처럼 필요합니다.

myObject["someProperty"]

와 같음

myObject.someProperty

네, 저도 슬퍼요 :-(

제목을 기반으로 강력한 SHA 해시를 생성할 수 있습니다. 브라우저 컨텍스트에서 객체, 파라미터 배열, 문자열 등에서 고유한 해시를 생성하는 데 사용할 수 있습니다.

async function H(m) {
  const msgUint8 = new TextEncoder().encode(m)                       
  const hashBuffer = await crypto.subtle.digest('SHA-256', msgUint8)          
  const hashArray = Array.from(new Uint8Array(hashBuffer))                    
  const hashHex = hashArray.map(b => b.toString(16).padStart(2, '0')).join('')
  console.log(hashHex)
}

/* Examples ----------------------- */
H("An obscure ....")
H(JSON.stringify( {"hello" : "world"} ))
H(JSON.stringify( [54,51,54,47] ))

내 브라우저의 위 출력은 당신에게도 동일해야 합니다.

bf1cf3fe6975fe382ab392ec1dd42009380614be03d489f23601c11413cfca2b
93a23971a914e5eacbf0a8d25154cda309c3c1c72fbb9914d47c60f3cb681588
d2f209e194045604a3b15bdfd7502898a0e848e4603c5a818bd01da69c00ad19

지원되는 알고리즘:

SHA-1 (but don't use this in cryptographic applications)
SHA-256
SHA-384
SHA-512

https://developer.mozilla.org/en-US/docs/Web/API/SubtleCrypto/digest#Converting_a_digest_to_a_hex_string


그러나 충돌 방지용으로만 만들어진 단순 FAST 체크섬 해시 함수는 CRC32(Content Redundancy Check)를 참조하십시오.

자바스크립트 CRC32


웹 암호화 api를 통해 HMAC 코드를 생성하는 이와 유사한 방법도 관심을 가질 수 있습니다.

참조 : https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Symbol

Es6 심볼을 사용하여 고유한 키와 액세스 개체를 만들 수 있습니다.Symbol()에서 반환되는 모든 Symbol 값은 고유합니다.심볼 값은 객체 속성의 식별자로 사용될 수 있으며, 이것이 데이터 유형의 유일한 목적입니다.

var obj = {};

obj[Symbol('a')] = 'a';
obj[Symbol.for('b')] = 'b';
obj['c'] = 'c';
obj.d = 'd';

여기 고유한 정수를 반환하는 간단한 솔루션이 있습니다.

function hashcode(obj) {
    var hc = 0;
    var chars = JSON.stringify(obj).replace(/\{|\"|\}|\:|,/g, '');
    var len = chars.length;
    for (var i = 0; i < len; i++) {
        // Bump 7 to larger prime number to increase uniqueness
        hc += (chars.charCodeAt(i) * 7);
    }
    return hc;
}

나의 솔루션은 글로벌에 정적 기능을 도입했습니다.Object물건.

(function() {
    var lastStorageId = 0;

    this.Object.hash = function(object) {
        var hash = object.__id;

        if (!hash)
             hash = object.__id = lastStorageId++;

        return '#' + hash;
    };
}());

자바스크립트에서 다른 객체 조작 기능을 사용하면 더 편리하다고 생각합니다.

다른 대답보다 조금 더 깊이 들어가도록 하겠습니다.

JS가 해싱 지원을 더 잘하더라도 마법처럼 모든 것을 완벽하게 해내지는 못할 것이기 때문에 많은 경우 자신의 해싱 함수를 정의해야 합니다.예를 들어 자바는 해싱 지원이 좋지만, 그래도 생각하고 몇 가지 일을 해야 합니다.

한 가지 문제는 해시/해시코드...라는 용어에 있습니다.암호 해싱과 비 crypt 해싱이 있습니다.또 다른 문제는 왜 해싱이 유용하고 어떻게 작동하는지 이해해야 한다는 것입니다.

대부분의 경우 자바스크립트나 자바의 해싱에 대해 이야기할 때 해시맵/해시테이블에 대한 해싱에 대해 이야기합니다(NodeJS를 사용하여 서버 측에서 할 수 있는 인증이나 암호에 대해 작업하지 않는 한).

어떤 데이터를 보유하고 무엇을 달성하고자 하는지에 따라 달라집니다.

데이터에는 자연스러운 "단순한" 독특함이 있습니다.

  • 정수의 해시는...정수는, 그것이 독특하기 때문에, 운이 좋습니다!
  • 문자열의 해시...문자열에 따라 다르므로 문자열이 고유 식별자를 나타내는 경우 해시로 간주할 수 있습니다(따라서 해시는 필요 없음).
  • 간접적으로 거의 유일한 정수인 것은 가장 간단한 경우입니다.
  • 이것은 존중합니다: 개체가 같으면 해시 코드가 같습니다.

데이터에는 자연스러운 "복합" 고유성이 있습니다.

  • 예를 들어, person 개체를 사용하여 이름, 성, 생년월일, ...Java가 어떻게 하는지 볼 수 있습니다: 문자열에 대한 좋은 해시 함수 또는 사용 사례에 충분히 값싸고 고유한 다른 ID 정보를 사용합니다.

데이터가 무엇인지 전혀 알 수 없습니다.

  • 행운을...문자열로 직렬화하여 Java 스타일로 해시할 수 있지만 문자열이 커서 충돌을 방지하지 않고 정수(자체)의 해시를 말하는 경우에는 비용이 많이 들 수 있습니다.

알 수 없는 데이터에 대해 마법처럼 효율적인 해싱 기술은 없으며, 어떤 경우에는 매우 쉽고, 어떤 경우에는 다시 생각해 보아야 할 수도 있습니다.따라서 자바스크립트/ECM스크립트가 지원을 더 추가하더라도 이 문제에 대한 마법 언어 솔루션은 없습니다.

실제로 당신은 두 가지가 필요합니다: 충분한 고유성, 충분한 속도.

또한 "객체가 같다면 해시코드도 같다"는 것도 좋습니다.

저는 눈꺼풀이 없는 것과 김하의 대답을 종합했습니다.

다음은 angularjs 서비스로 숫자, 문자열, 객체를 지원합니다.

exports.Hash = () => {
  let hashFunc;
  function stringHash(string, noType) {
    let hashString = string;
    if (!noType) {
      hashString = `string${string}`;
    }
    var hash = 0;
    for (var i = 0; i < hashString.length; i++) {
        var character = hashString.charCodeAt(i);
        hash = ((hash<<5)-hash)+character;
        hash = hash & hash; // Convert to 32bit integer
    }
    return hash;
  }

  function objectHash(obj, exclude) {
    if (exclude.indexOf(obj) > -1) {
      return undefined;
    }
    let hash = '';
    const keys = Object.keys(obj).sort();
    for (let index = 0; index < keys.length; index += 1) {
      const key = keys[index];
      const keyHash = hashFunc(key);
      const attrHash = hashFunc(obj[key], exclude);
      exclude.push(obj[key]);
      hash += stringHash(`object${keyHash}${attrHash}`, true);
    }
    return stringHash(hash, true);
  }

  function Hash(unkType, exclude) {
    let ex = exclude;
    if (ex === undefined) {
      ex = [];
    }
    if (!isNaN(unkType) && typeof unkType !== 'string') {
      return unkType;
    }
    switch (typeof unkType) {
      case 'object':
        return objectHash(unkType, ex);
      default:
        return stringHash(String(unkType));
    }
  }

  hashFunc = Hash;

  return Hash;
};

사용 예시:

Hash('hello world'), Hash('hello world') == Hash('hello world')
Hash({hello: 'hello world'}), Hash({hello: 'hello world'}) == Hash({hello: 'hello world'})
Hash({hello: 'hello world', goodbye: 'adios amigos'}), Hash({hello: 'hello world', goodbye: 'adios amigos'}) == Hash({goodbye: 'adios amigos', hello: 'hello world'})
Hash(['hello world']), Hash(['hello world']) == Hash(['hello world'])
Hash(1), Hash(1) == Hash(1)
Hash('1'), Hash('1') == Hash('1')

산출량

432700947 true
-411117486 true
1725787021 true
-1585332251 true
1 true
-1881759168 true

설명.

서비스의 핵심이 김카가 만든 해시 함수라는 것을 보시면 알 수 있습니다.객체의 구조가 최종 해시 값에도 영향을 미치도록 문자열에 유형을 추가했습니다.배열 개체 충돌을 방지하기 위해 키가 해시됩니다.

눈꺼풀 없는 개체 비교는 개체를 자체 참조하여 무한 재귀를 방지하는 데 사용됩니다.

사용.

저는 오브젝트로 접속하는 오류 서비스를 받을 수 있도록 이 서비스를 만들었습니다.한 서비스는 지정된 개체에 오류를 등록하고 다른 서비스는 오류가 발견되었는지 여부를 확인할 수 있습니다.

JsonValidation.js

ErrorSvc({id: 1, json: '{attr: "not-valid"}'}, 'Invalid Json Syntax - key not double quoted');

UserOfData.js

ErrorSvc({id: 1, json: '{attr: "not-valid"}'});

이 경우 다음을 반환합니다.

['Invalid Json Syntax - key not double quoted']

하는 동안에

ErrorSvc({id: 1, json: '{"attr": "not-valid"}'});

이것은 돌아올 것입니다.

[]

만약 여러분이 진정으로 설정된 행동을 원한다면 (나는 자바 지식에 따라 행동할 것입니다), 여러분은 자바스크립트에서 해결책을 찾기가 어려울 것입니다.대부분의 개발자는 각 개체를 나타내는 고유한 키를 권장하지만, 이는 고유한 키로 두 개의 동일한 개체를 각각 얻을 수 있다는 점에서 집합과는 다릅니다.자바 API는 키가 아닌 해시 코드 값을 비교하여 중복된 값을 확인하는 작업을 하는데, 자바스크립트에는 객체의 해시 코드 값 표현이 없기 때문에 거의 불가능하게 됩니다.프로토타입 JS 라이브러리에서도 다음과 같은 단점을 인정하고 있습니다.

"해시는 연관 배열로 간주될 수 있으며, 고유한 키를 반드시 고유하지는 않습니다.."

http://www.prototypejs.org/api/hash

눈꺼풀이 없는 답변 외에, 모든 개체에 대해 재현 가능한 고유 ID를 반환하는 기능이 있습니다.

var uniqueIdList = [];
function getConstantUniqueIdFor(element) {
    // HACK, using a list results in O(n), but how do we hash e.g. a DOM node?
    if (uniqueIdList.indexOf(element) < 0) {
        uniqueIdList.push(element);
    }
    return uniqueIdList.indexOf(element);
}

보시는 것처럼 검색에 매우 비효율적인 목록을 사용합니다. 하지만 지금으로서는 그것이 최선입니다.

개체를 키로 사용하려면 일부에서 이미 언급한 대로 String Method로 덮어씁니다.사용된 해시 함수는 모두 정상이지만 동일한 개체에 대해서만 작동하지만 동일한 개체에 대해서는 작동하지 않습니다.

이런 용도로 쉽게 사용할 수 있는 객체로 해시를 만드는 작은 도서관을 만들었습니다.개체의 순서가 다를 수도 있고 해시도 동일합니다.내부적으로 해시에 다른 유형(djb2, md5, sha1, sha256, sha512, ripemd160)을 사용할 수 있습니다.

다음은 설명서의 작은 예입니다.

var hash = require('es-hash');

// Save data in an object with an object as a key
Object.prototype.toString = function () {
    return '[object Object #'+hash(this)+']';
}

var foo = {};

foo[{bar: 'foo'}] = 'foo';

/*
 * Output:
 *  foo
 *  undefined
 */
console.log(foo[{bar: 'foo'}]);
console.log(foo[{}]);

패키지는 브라우저 및 Node-Js에서 사용할 수 있습니다.

리포지토리: https://bitbucket.org/tehrengruber/es-js-hash

조회 개체에 고유한 값을 가지려면 다음과 같은 작업을 수행할 수 있습니다.

조회 개체 생성

var lookup = {};

해시 코드 함수 설정

function getHashCode(obj) {
    var hashCode = '';
    if (typeof obj !== 'object')
        return hashCode + obj;
    for (var prop in obj) // No hasOwnProperty needed
        hashCode += prop + getHashCode(obj[prop]); // Add key + value to the result string
    return hashCode;
}

물건

var key = getHashCode({ 1: 3, 3: 7 });
// key = '1337'
lookup[key] = true;

배열

var key = getHashCode([1, 3, 3, 7]);
// key = '01132337'
lookup[key] = true;

기타종류

var key = getHashCode('StackOverflow');
// key = 'StackOverflow'
lookup[key] = true;

최종결과

{ 1337: true, 01132337: true, StackOverflow: true }

참고하세요.getHashCode개체 또는 배열이 비어 있으면 값을 반환하지 않습니다.

getHashCode([{},{},{}]);
// '012'
getHashCode([[],[],[]]);
// '012'

@ijmacd 솔루션과 유사합니다.getHashCode가지고 있지 않습니다JSON의존.

그냥 숨겨진 비밀 재산을 사용하면 됩니다.defineProperty enumerable: false

작동 속도가 매우 빠릅니다.

  • 첫 번째 읽기 uniqueId: 1,257,500 ops/s
  • 기타: 309,226,485 ops/s
var nextObjectId = 1
function getNextObjectId() {
    return nextObjectId++
}

var UNIQUE_ID_PROPERTY_NAME = '458d576952bc489ab45e98ac7f296fd9'
function getObjectUniqueId(object) {
    if (object == null) {
        return null
    }

    var id = object[UNIQUE_ID_PROPERTY_NAME]

    if (id != null) {
        return id
    }

    if (Object.isFrozen(object)) {
        return null
    }

    var uniqueId = getNextObjectId()
    Object.defineProperty(object, UNIQUE_ID_PROPERTY_NAME, {
        enumerable: false,
        configurable: false,
        writable: false,
        value: uniqueId,
    })

    return uniqueId
}

언급URL : https://stackoverflow.com/questions/194846/is-there-hash-code-function-accepting-any-object-type

반응형