JavaScript에 사전 구현이 있습니까?
JavaScript에서 인덱서로 배열을 구현하려면 어떻게해야합니까? .Net에 사전과 같은 것이 있습니까?
기술적으로는 아니지만 사전과 같은 일반 JavaScript 객체를 사용할 수 있습니다.
var a = {"a":"wohoo", 2:"hello2", "d":"hello"};
alert(a["a"]);
alert(a[2]);
alert(a["d"]);
John Resig (jQuery의 저자) 는 최근 자바 스크립트의 사전 조회에 대해 게시했습니다 .
그의 해결책은 사전 값을 객체의 속성으로 할당하는 것입니다. 위 기사에서 그대로 붙여 넣은 코드 :
// The dictionary lookup object
var dict = {};
// Do a jQuery Ajax request for the text dictionary
$.get( "dict/dict.txt", function( txt ) {
// Get an array of all the words
var words = txt.split( "\n" );
// And add them as properties to the dictionary lookup
// This will allow for fast lookups later
for ( var i = 0; i < words.length; i++ ) {
dict[ words[i] ] = true;
}
// The game would start after the dictionary was loaded
// startGame();
});
// Takes in an array of letters and finds the longest
// possible word at the front of the letters
function findWord( letters ) {
// Clone the array for manipulation
var curLetters = letters.slice( 0 ), word = "";
// Make sure the word is at least 3 letters long
while ( curLetters.length > 2 ) {
// Get a word out of the existing letters
word = curLetters.join("");
// And see if it's in the dictionary
if ( dict[ word ] ) {
// If it is, return that word
return word;
}
// Otherwise remove another letter from the end
curLetters.pop();
}
}
javascript 데이터 구조 라이브러리 인 buckets 을 사용해 볼 수 있으며 사전에있는 모든 유형의 객체를 사용할 수 있습니다.
지난 프로젝트에서 저는 수만 행의 데이터를 읽은 다음 그리드 및 차트에 표시하기 위해 데이터를 그룹화하고 집계하는 브라우저 클라이언트 애플리케이션을 만드는 작업을 맡았습니다. 대상 기술은 HTML 5, CSS 3 및 EMCS 5 (2013 년 6 월 최신 브라우저)였습니다. 이전 브라우저 호환성이 문제가되지 않았기 때문에 외부 라이브러리는 D3 (JQuery 없음)으로 제한되었습니다.
데이터 모델을 구축해야했습니다. 이전에 C #으로 빌드했고 사용자 지정 사전 개체에 의존하여 데이터, 그룹 및 집계에 빠르게 액세스했습니다. 몇 년 동안 JavaScript로 일하지 않았기 때문에 사전을 찾기 시작했습니다. JavaScript에는 여전히 진정한 기본 사전이 없습니다. 몇 가지 샘플 구현을 찾았지만 실제로 내 기대에 부합하는 것은 없습니다. 그래서 하나를 만들었습니다.
제가 언급했듯이 저는 몇 년 동안 JavaScript로 일하지 않았습니다. 발전 (또는 정보의 웹 가용성)은 매우 인상적이었습니다. 이전의 모든 작업은 클래스 기반 언어로 이루어 졌으므로 프로토 타입 기본 언어에 익숙해지는 데 시간이 좀 걸렸습니다 (아직 갈 길이 멀었습니다).
대부분과 마찬가지로이 프로젝트는 시작하기 전에 마감되었으므로 클래스 기반에서 프로토 타입 기반 언어로 전환 할 때 예상되는 많은 새로운 실수를 저지르면서 배웠습니다. 생성 된 사전은 기능적이지만 시간이지나면서 덜 새로운 것으로 만들어서 개선 할 수있는 몇 가지 개선 사항을 깨달았습니다. 사전을 재 작업하기 전에 프로젝트 자금이 부족했습니다. 아, 그리고 내 위치는 동시에 자금을 잃었습니다 (어떻게 일어날 수 있는지 놀랍습니다). 그래서 배운 것을 사용하여 사전을 다시 만들고 사전이 실제로 배열보다 성능이 향상되었는지 확인하기로 결정했습니다.
/*
* Dictionary Factory Object
* Holds common object functions. similar to V-Table
* this.New() used to create new dictionary objects
* Uses Object.defineProperties so won't work on older browsers.
* Browser Compatibility (https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/defineProperties)
* Firefox (Gecko) 4.0 (2), Chrome 5, IE 9, Opera 11.60, Safari 5
*/
function Dict() {
/*
* Create a new Dictionary
*/
this.New = function () {
return new dict();
};
/*
* Return argument f if it is a function otherwise return undefined
*/
function ensureF(f) {
if (isFunct(f)) {
return f;
}
}
function isFunct(f) {
return (typeof f == "function");
}
/*
* Add a "_" as first character just to be sure valid property name
*/
function makeKey(k) {
return "_" + k;
};
/*
* Key Value Pair object - held in array
*/
function newkvp(key, value) {
return {
key: key,
value: value,
toString: function () { return this.key; },
valueOf: function () { return this.key; }
};
};
/*
* Return the current set of keys.
*/
function keys(a) {
// remove the leading "-" character from the keys
return a.map(function (e) { return e.key.substr(1); });
// Alternative: Requires Opera 12 vs. 11.60
// -- Must pass the internal object instead of the array
// -- Still need to remove the leading "-" to return user key values
// Object.keys(o).map(function (e) { return e.key.substr(1); });
};
/*
* Return the current set of values.
*/
function values(a) {
return a.map(function(e) { return e.value; } );
};
/*
* Return the current set of key value pairs.
*/
function kvPs(a) {
// remove the leading "-" character from the keys
return a.map(function (e) { return newkvp(e.key.substr(1), e.value); });
}
/*
* Returns true if key exists in the dictionary.
* k - Key to check (with the leading "_" character)
*/
function exists(k, o) {
return o.hasOwnProperty(k);
}
/*
* Array Map implementation
*/
function map(a, f) {
if (!isFunct(f)) { return; }
return a.map(function (e, i) { return f(e.value, i); });
}
/*
* Array Every implementation
*/
function every(a, f) {
if (!isFunct(f)) { return; }
return a.every(function (e, i) { return f(e.value, i) });
}
/*
* Returns subset of "values" where function "f" returns true for the "value"
*/
function filter(a, f) {
if (!isFunct(f)) {return; }
var ret = a.filter(function (e, i) { return f(e.value, i); });
// if anything returned by array.filter, then get the "values" from the key value pairs
if (ret && ret.length > 0) {
ret = values(ret);
}
return ret;
}
/*
* Array Reverse implementation
*/
function reverse(a, o) {
a.reverse();
reindex(a, o, 0);
}
/**
* Randomize array element order in-place.
* Using Fisher-Yates shuffle algorithm.
* (Added just because:-)
*/
function shuffle(a, o) {
var j, t;
for (var i = a.length - 1; i > 0; i--) {
j = Math.floor(Math.random() * (i + 1));
t = a[i];
a[i] = a[j];
a[j] = t;
}
reindex(a, o, 0);
return a;
}
/*
* Array Some implementation
*/
function some(a, f) {
if (!isFunct(f)) { return; }
return a.some(function (e, i) { return f(e.value, i) });
}
/*
* Sort the dictionary. Sorts the array and reindexes the object.
* a - dictionary array
* o - dictionary object
* sf - dictionary default sort function (can be undefined)
* f - sort method sort function argument (can be undefined)
*/
function sort(a, o, sf, f) {
var sf1 = f || sf; // sort function method used if not undefined
// if there is a customer sort function, use it
if (isFunct(sf1)) {
a.sort(function (e1, e2) { return sf1(e1.value, e2.value); });
}
else {
// sort by key values
a.sort();
}
// reindex - adds O(n) to perf
reindex(a, o, 0);
// return sorted values (not entire array)
// adds O(n) to perf
return values(a);
};
/*
* forEach iteration of "values"
* uses "for" loop to allow exiting iteration when function returns true
*/
function forEach(a, f) {
if (!isFunct(f)) { return; }
// use for loop to allow exiting early and not iterating all items
for(var i = 0; i < a.length; i++) {
if (f(a[i].value, i)) { break; }
}
};
/*
* forEachR iteration of "values" in reverse order
* uses "for" loop to allow exiting iteration when function returns true
*/
function forEachR(a, f) {
if (!isFunct(f)) { return; }
// use for loop to allow exiting early and not iterating all items
for (var i = a.length - 1; i > -1; i--) {
if (f(a[i].value, i)) { break; }
}
}
/*
* Add a new Key Value Pair, or update the value of an existing key value pair
*/
function add(key, value, a, o, resort, sf) {
var k = makeKey(key);
// Update value if key exists
if (exists(k, o)) {
a[o[k]].value = value;
}
else {
// Add a new Key value Pair
var kvp = newkvp(k, value);
o[kvp.key] = a.length;
a.push(kvp);
}
// resort if requested
if (resort) { sort(a, o, sf); }
};
/*
* Removes an existing key value pair and returns the "value" If the key does not exists, returns undefined
*/
function remove(key, a, o) {
var k = makeKey(key);
// return undefined if the key does not exist
if (!exists(k, o)) { return; }
// get the array index
var i = o[k];
// get the key value pair
var ret = a[i];
// remove the array element
a.splice(i, 1);
// remove the object property
delete o[k];
// reindex the object properties from the remove element to end of the array
reindex(a, o, i);
// return the removed value
return ret.value;
};
/*
* Returns true if key exists in the dictionary.
* k - Key to check (without the leading "_" character)
*/
function keyExists(k, o) {
return exists(makeKey(k), o);
};
/*
* Returns value assocated with "key". Returns undefined if key not found
*/
function item(key, a, o) {
var k = makeKey(key);
if (exists(k, o)) {
return a[o[k]].value;
}
}
/*
* changes index values held by object properties to match the array index location
* Called after sorting or removing
*/
function reindex(a, o, i){
for (var j = i; j < a.length; j++) {
o[a[j].key] = j;
}
}
/*
* The "real dictionary"
*/
function dict() {
var _a = [];
var _o = {};
var _sortF;
Object.defineProperties(this, {
"length": { get: function () { return _a.length; }, enumerable: true },
"keys": { get: function() { return keys(_a); }, enumerable: true },
"values": { get: function() { return values(_a); }, enumerable: true },
"keyValuePairs": { get: function() { return kvPs(_a); }, enumerable: true},
"sortFunction": { get: function() { return _sortF; }, set: function(funct) { _sortF = ensureF(funct); }, enumerable: true }
});
// Array Methods - Only modification to not pass the actual array to the callback function
this.map = function(funct) { return map(_a, funct); };
this.every = function(funct) { return every(_a, funct); };
this.filter = function(funct) { return filter(_a, funct); };
this.reverse = function() { reverse(_a, _o); };
this.shuffle = function () { return shuffle(_a, _o); };
this.some = function(funct) { return some(_a, funct); };
this.sort = function(funct) { return sort(_a, _o, _sortF, funct); };
// Array Methods - Modified aborts when funct returns true.
this.forEach = function (funct) { forEach(_a, funct) };
// forEach in reverse order
this.forEachRev = function (funct) { forEachR(_a, funct) };
// Dictionary Methods
this.addOrUpdate = function(key, value, resort) { return add(key, value, _a, _o, resort, _sortF); };
this.remove = function(key) { return remove(key, _a, _o); };
this.exists = function(key) { return keyExists(key, _o); };
this.item = function(key) { return item(key, _a, _o); };
this.get = function (index) { if (index > -1 && index < _a.length) { return _a[index].value; } } ,
this.clear = function() { _a = []; _o = {}; };
return this;
}
return this;
}
클래스와 프로토 타입 객체를 정신적으로 조화 시키려고 시도하면서 얻은 깨달음 중 하나는 프로토 타입이 기본적으로 생성 된 객체에 대한 v- 테이블이라는 것입니다. 또한 인클로저의 기능은 V- 테이블 항목처럼 작동 할 수도 있습니다. 프로젝트가 진행됨에 따라 최상위 개체에 개체 유형에 대한 공통 함수가 포함되어 있고 솔루션에 사용되는 실제 개체를 만드는 데 사용되는 "this.New (args)"메서드가 포함 된 개체 팩토리를 사용하기 시작했습니다. 이것이 제가 사전에 사용한 스타일입니다.
사전의 핵심은 Array, Object 및 KeyValuePair 객체입니다. "addOrUpdate"메소드는 키와 값을 취하며 다음을 수행합니다.
- KeyValuePair를 생성합니다.
- 키를 속성 이름으로 사용하고 배열 길이를 속성 값으로 사용하여 객체에 새 속성을 추가합니다.
- 배열에 KeyValuePair를 추가하여 객체의 새 속성 값을 배열의 인덱스로 만듭니다.
참고 : 개체 속성 이름은 "거의 모든"유니 코드 문자로 시작할 수 있음을 읽었습니다. 이 프로젝트는 "모든"유니 코드 문자로 시작할 수있는 고객 데이터를 처리합니다. 유효하지 않은 속성 이름으로 인해 사전이 파열되지 않도록하기 위해 키 앞에 밑줄 (_)을 붙이고 사전 외부에 키를 반환 할 때 해당 밑줄을 제거합니다.
사전이 작동하려면 내부 배열과 객체가 동기화 상태로 유지되어야합니다. 이를 보장하기 위해 배열이나 객체가 외부에 노출되지 않습니다. "If"테스트에 등호가 하나만 있고 왼쪽에 실수로 값이있을 때 발생할 수있는 변경과 같은 우발적 인 변경을 피하고 싶었습니다.
If(dict.KeyObj[“SomeKey”] = “oops”) { alert(“good luck tracing this down:-)”); }
딕셔너리의 이러한 일반적인 오류는 버그 (증상)가 계산, 표시 등에서 나타나기 시작할 때 추적하기 매우 어려울 수 있습니다. 따라서 "this"속성은 어느 쪽에도 액세스 할 수 없습니다. 이 보호주의는 내가 프로토 타입을 더 많이 파지 않은 이유 중 하나입니다. Array 및 Object가 노출 된 내부 개체를 사용하고 "call"또는 "apply"메서드를 사용할 때 해당 내부 개체를 전달하는 것이 마음에 들었습니다. 아직 확실하지 않기 때문에 나중에 볼 수 있습니다. 핵심 배열 및 개체를 보호하려는 목적을 무력화하는 내부 개체를 노출해야합니다.
내가 만든 첫 번째 사전 객체로 만든 newb 실수 중 일부를 수정했습니다.
- "Dict ()"함수는 각 사전 객체에 대한 대부분의 작업 코드를 포함합니다. 포함 된 함수를 사용해야하는지 여부와 실제 사전 개체의 기능을 결정하는 데 사용한 기준 :
- 한 줄 이상의 코드
- 다른 포함 된 함수에서 사용
- 버그 / 문제를 발견함에 따라 성장으로 인해 변경 될 수 있습니다.
- 의미가있는 곳에 사용 된 Array 메서드 및 속성 이름. C #에서 나는 "forEach"대신 "length"대신 "Count"를 사용하거나 "ForEach"대신에 "ForEach"를 사용하여 사전을 덜 사용하도록 만드는 작업을 수행했습니다. 배열 이름을 사용하면 이제 대부분의 경우 사전을 배열로 사용할 수 있습니다. 불행히도 대괄호 접근자를 만드는 방법을 찾지 못했습니다 (예 : val = dict [key]). 어쨌든 좋은 방법 일 수 있습니다. 그것에 대해 생각할 때 나는 val = dict [12]와 같은 것이 제대로 작동하는지 확신하기가 어려웠습니다. 숫자 12는 키로 쉽게 사용할 수 있었기 때문에 그러한 호출의 "의도"를 알 수있는 좋은 방법을 생각할 수 없었습니다.
- 밑줄 접두사 처리를 완전히 묶었습니다. 작업중인 프로젝트에서 다양한 데이터 모델 개체에서이를 확산하고 반복했습니다. 못 생겼어!
JS에서 { "index": anyValue}는 단지 사전입니다. JSON (http://www.json.org/)의 정의를 참조 할 수도 있습니다.
Javascript에서 .Net 사전에 사용한 가장 가까운 구현은 해시 객체입니다 (링크 : http://www.mojavelinux.com/articles/javascript_hashes.html 참조 ). 내부적으로 배열을 구현하고 .Net 사전과 유사한 이름의 메서드를 가지고 있습니다.
ECMAScript 6 (일명 2015 JavaScript 사양) 은 Map이라는 사전 인터페이스를 지정합니다 . 모든 유형의 임의의 키를 지원하고, 읽기 전용 size
속성을 가지며, 객체와 같은 프로토 타입 관련 항목으로 복잡하지 않으며, 새 for...of...
구성 또는을 사용하여 반복 할 수 있습니다 Map.forEach
. MDN에 대한 문서는 여기 에서 확인하고 브라우저 호환성 표는 여기에서 확인하십시오 .
다른 사람들이 쓰는대로 개체를 사용합니다. 문자열 이외의 것을 키로 저장하는 경우 jsonize하십시오. 자바 스크립트에서 다양한 사전 구현의 성능 고려 사항은 이 블로그 게시물 을 참조하세요 .
var nDictionary = Object.create(null);
function setDictionary(index, value) {
nDictionary[index] = value;
}
function getDictionary(index) {
return nDictionary[index];
}
setDictionary(81403, "test 1");
setDictionary(81404, "test 2");
setDictionary(81405, "test 3");
setDictionary(81406, "test 4");
setDictionary(81407, "test 5");
alert(getDictionary(81403));
이 구현이 실행 중입니다. 키 값 쌍을 처음 추가하면 일종의 키 유형이 안전합니다. 잘 작동하며 Map과 독립적입니다.
function Dictionary() {
this.dictionary = [];
this.validateKey = function(key){
if(typeof key == 'undefined' || key == null){
return false;
}
if(this.dictionary.length){
if (!this.hasOwnProperty(this.dictionary[0], "key")) {
return false;
}
if(typeof this.dictionary[0].key != typeof key){
return false;
}
}
return true;
};
this.hasOwnProperty = function (obj, prop) {
var proto = obj.__proto__ || obj.constructor.prototype;
return (prop in obj) &&
(!(prop in proto) || proto[prop] !== obj[prop]);
};
}
Dictionary.prototype = {
Add: function(key, value) {
if(!this.validateKey(key)){
return false;
}
if(!this.ContainsKey(key)){
this.dictionary.push({ key: key, value: value });
return true;
}
return false;
},
Any: function() {
return this.dictionary.length > 0;
},
ContainsKey: function(key) {
if(!this.validateKey(key)){
return false;
}
for (var i = 0; i < this.dictionary.length; i++) {
var keyValuePair = this.dictionary[i];
if (typeof keyValuePair != "undefined" && keyValuePair != null) {
if (this.hasOwnProperty(keyValuePair, "key")) {
if (keyValuePair.key == key) {
return true;
}
}
}
}
return false;
},
ContainsValue: function(value) {
for (var i = 0; i < this.dictionary.length; i++) {
var keyValuePair = this.dictionary[i];
if(typeof keyValuePair != "undefined" && keyValuePair != null){
if (this.hasOwnProperty(keyValuePair, "value")) {
if(value == null && keyValuePair.value == null){
return true;
}
if ((value != null && keyValuePair.value == null) ||
(value == null && keyValuePair.value != null)) {
continue;
}
// compare objects content over json.
if(JSON.stringify(value) === JSON.stringify(keyValuePair.value)){
return true;
}
}
}
}
return false;
},
Count: function() {
return this.dictionary.length;
},
GetValue: function(key){
if(!this.validateKey(key)){
return null;
}
for (var i = 0; i < this.dictionary.length; i++) {
var keyValuePair = this.dictionary[i];
if (typeof keyValuePair != "undefined" && keyValuePair != null) {
if (this.hasOwnProperty(keyValuePair, "key")) {
if (keyValuePair.key == key) {
return keyValuePair.value;
}
}
}
}
return null;
},
Keys: function(){
var keys = [];
for (var i = 0; i < this.dictionary.length; i++) {
var keyValuePair = this.dictionary[i];
if (typeof keyValuePair != "undefined" && keyValuePair != null) {
if (this.hasOwnProperty(keyValuePair, "key")) {
keys.push(keyValuePair.key);
}
}
}
return keys;
},
Remove: function(key){
if(!this.validateKey(key)){
return;
}
for (var i = 0; i < this.dictionary.length; i++) {
var keyValuePair = this.dictionary[i];
if (typeof keyValuePair != "undefined" && keyValuePair != null) {
if (this.hasOwnProperty(keyValuePair, "key")) {
if (keyValuePair.key == key) {
this.dictionary.splice(i, 1);
return;
}
}
}
}
},
Values: function(){
var values = [];
for (var i = 0; i < this.dictionary.length; i++) {
var keyValuePair = this.dictionary[i];
if (typeof keyValuePair != "undefined" && keyValuePair != null) {
if (this.hasOwnProperty(keyValuePair, "value")) {
values.push(keyValuePair.value);
}
}
}
return values;
},
};
사용 방법은 다음과 같습니다.
var dic = new Dictionary();
var success = dic.Add("test", 5);
success = dic.Add("test1", 4);
success = dic.Add("test2", 8);
success = dic.Add(3, 8);
var containsKey = dic.ContainsKey("test2");
containsKey = dic.ContainsKey(3);
var containsValue = dic.ContainsValue(8);
var value = dic.GetValue("test1");
var keys = dic.Keys();
var values = dic.Values();
dic.Remove("test1");
var keys = dic.Keys();
var values = dic.Values();
참조 URL : https://stackoverflow.com/questions/5594850/is-there-a-dictionary-implementation-in-javascript
'Development Tip' 카테고리의 다른 글
git에서 삭제 된 파일에 대한 diff 억제 (0) | 2021.01.10 |
---|---|
heroku 데이터베이스 크기를 찾는 가장 빠른 방법 (0) | 2021.01.10 |
정수의 자릿수 찾기 (0) | 2021.01.10 |
PHP 객체 배열 (0) | 2021.01.10 |
Python의 matplotlib를 사용하여 x 축에 날짜 그리기 (0) | 2021.01.10 |