C #에서 다차원 키가있는 해시 테이블
기본적으로 C #의 2 차원 형식 키를 사용하여 해시 테이블 값에 액세스하는 방법을 찾고 있습니다.
결국 나는 이와 같은 것을 할 수있을 것이다.
HashTable[1][false] = 5;
int a = HashTable[1][false];
//a = 5
이것은 내가 시도한 것입니다 ... 작동하지 않았습니다
Hashtable test = new Hashtable();
test.Add(new Dictionary<int, bool>() { { 1, true } }, 555);
Dictionary<int, bool> temp = new Dictionary<int, bool>() {{1, true}};
string testz = test[temp].ToString();
더 나은 접근 방식은 다차원 키의 많은 필드를 클래스 / 구조체로 캡슐화하는 것입니다. 예를 들면
struct Key {
public readonly int Dimension1;
public readonly bool Dimension2;
public Key(int p1, bool p2) {
Dimension1 = p1;
Dimension2 = p2;
}
// Equals and GetHashCode ommitted
}
이제 일반 HashTable을 만들고 사용하고이 래퍼를 키로 사용할 수 있습니다.
어떤 종류의 튜플 구조가있는 일반 사전을 키로 사용하는 것은 어떻습니까?
public class TwoKeyDictionary<K1,K2,V>
{
private readonly Dictionary<Pair<K1,K2>, V> _dict;
public V this[K1 k1, K2 k2]
{
get { return _dict[new Pair(k1,k2)]; }
}
private struct Pair
{
public K1 First;
public K2 Second;
public override Int32 GetHashCode()
{
return First.GetHashCode() ^ Second.GetHashCode();
}
// ... Equals, ctor, etc...
}
}
이제 새 튜플을 사용하여 C # 7.0에서이 작업을 수행 할 수 있습니다.
// Declare
var test = new Dictionary<(int, bool), int>();
// Add
test.Add((1, false), 5);
// Get
int a = test[(1, false)];
누군가가 최근에 여기에있는 경우를 대비하여 댓글 작성자 중 한 명이 설명했듯이 .Net 4.0에서이 작업을 빠르고 더러운 방식으로 수행하는 방법의 예입니다.
class Program
{
static void Main(string[] args)
{
var twoDic = new Dictionary<Tuple<int, bool>, String>();
twoDic.Add(new Tuple<int, bool>(3, true), "3 and true." );
twoDic.Add(new Tuple<int, bool>(4, true), "4 and true." );
twoDic.Add(new Tuple<int, bool>(3, false), "3 and false.");
// Will throw exception. Item with the same key already exists.
// twoDic.Add(new Tuple<int, bool>(3, true), "3 and true." );
Console.WriteLine(twoDic[new Tuple<int, bool>(3,false)]);
Console.WriteLine(twoDic[new Tuple<int, bool>(4,true)]);
// Outputs "3 and false." and "4 and true."
}
}
나는 이것이 당신이 찾고있는 것에 더 가깝다고 생각합니다 ...
var data = new Dictionary<int, Dictionary<bool, int>>();
jachymko의 솔루션에 약간의 변형을 제안하여 키 쌍에 대한 클래스 생성을 피할 수 있습니다. 대신 사전의 개인 사전을 다음과 같이 래핑하십시오.
public class MultiDictionary<K1, K2, V>
{
private Dictionary<K1, Dictionary<K2, V>> dict =
new Dictionary<K1, Dictionary<K2, V>>();
public V this[K1 key1, K2 key2]
{
get
{
return dict[key1][key2];
}
set
{
if (!dict.ContainsKey(key1))
{
dict[key1] = new Dictionary<K2, V>();
}
dict[key1][key2] = value;
}
}
}
gethashcode를 올바르게 구현하는 사전에 대한 키 클래스가 필요합니다. 그리고 dictonary를 확장하여 친숙한 방법으로 액세스 할 수 있습니다.
키 페어 클래스
public class KeyPair<Tkey1, Tkey2>
{
public KeyPair(Tkey1 key1, Tkey2 key2)
{
Key1 = key1;
Key2 = key2;
}
public Tkey1 Key1 { get; set; }
public Tkey2 Key2 { get; set; }
public override int GetHashCode()
{
return Key1.GetHashCode() ^ Key2.GetHashCode();
}
public override bool Equals(object obj)
{
KeyPair<Tkey1, Tkey2> o = obj as KeyPair<Tkey1, Tkey2>;
if (o == null)
return false;
else
return Key1.Equals(o.Key1) && Key2.Equals(o.Key2);
}
}
확장 Dictonary <>
public class KeyPairDictonary<Tkey1, Tkey2, Tvalue>
: Dictionary<KeyPair<Tkey1, Tkey2>, Tvalue>
{
public Tvalue this[Tkey1 key1, Tkey2 key2]
{
get
{
return this[new KeyPair<Tkey1, Tkey2>(key1, key2)];
}
set
{
this[new KeyPair<Tkey1, Tkey2>(key1, key2)] = value;
}
}
}
그리고 당신은 이것을 이렇게 사용합니다
KeyPairDictonary<int, bool, string> dict =
new KeyPairDictonary<int, bool, string>();
dict[1, false] = "test";
string test = dict[1, false];
bool 및 int 속성을 노출하는 작은 사용자 지정 클래스를 만들고 GetHashCode 및 Equals 메서드를 재정의 한 다음이를 키로 사용하는 것이 좋습니다.
기본적으로 포함 된 해시 테이블을 사용해야합니다. 질문에 대해 생각해 보면 두 개의 키가있는 해시 테이블은 두 개의 독립 변수가있는 함수이며 f(x,y)
정의상 2 차원입니다.
그러나 임베디드 해시가 아닌 하나의 해시 테이블처럼 사용하고 싶습니다. 따라서 필요한 것은 포함 된 해시 테이블 아이디어를 감싸고 단일 해시처럼 작동하는 객체를 만드는 것입니다.
몇 가지 걸림돌 :
- 반복하고 싶으므로
GetEnumerator()
메서드 를 덮어 써야합니다 . 그리고 2 차원에서 올바르게 반복되는 자체 반복자가 필요합니다. - 중복이 없는지 확인하려면 추가 검사를 수행해야합니다.
내 코드를 포함했습니다.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Collections;
using System.Windows.Forms;
namespace YourProjectNameHere
{
public class Hashtable2D
{
/// <summary>
/// This is a hashtable of hashtables
/// The X dim is the root key, and the y is the internal hashes key
/// </summary>
///
private Hashtable root = new Hashtable();
public bool overwriteDuplicates = false;
public bool alertOnDuplicates = true;
public void Add(object key_x, object key_y, object toStore)
{
if(root[key_x]!=null)//If key_x has already been entered
{
Hashtable tempHT = (Hashtable)root[key_x];//IF the hash table does not exist then focus will skip to the catch statement
if (tempHT[key_y] == null) tempHT.Add(key_y, toStore);
else handleDuplicate(tempHT, key_y, toStore);
}else{//Making a new hashtable
Hashtable tempHT = new Hashtable();
tempHT.Add(key_y, toStore);
root.Add(key_x, tempHT);
}
}
public void Remove(object key_x, object key_y)
{
try{
((Hashtable)root[key_x]).Remove(key_y);
}catch(Exception e){
MessageBox.Show("That item does not exist");
}
}
public void handleDuplicate (Hashtable tempHT, object key_y, object toStore)
{
if (alertOnDuplicates) MessageBox.Show("This Item already Exists in the collection");
if (overwriteDuplicates)
{
tempHT.Remove(key_y);
tempHT.Add(key_y,toStore);
}
}
public object getItem(object key_x, object key_y)
{
Hashtable tempHT = (Hashtable)root[key_x];
return tempHT[key_y];
}
public ClassEnumerator GetEnumerator()
{
return new ClassEnumerator(root);
}
public class ClassEnumerator : IEnumerator
{
private Hashtable ht;
private IEnumerator iEnumRoot;
private Hashtable innerHt;
private IEnumerator iEnumInner;
public ClassEnumerator(Hashtable _ht)
{
ht = _ht;
iEnumRoot = ht.GetEnumerator();
iEnumRoot.MoveNext();//THIS ASSUMES THAT THERE IS AT LEAST ONE ITEM
innerHt = (Hashtable)((DictionaryEntry)iEnumRoot.Current).Value;
iEnumInner = innerHt.GetEnumerator();
}
#region IEnumerator Members
public void Reset()
{
iEnumRoot = ht.GetEnumerator();
}
public object Current
{
get
{
return iEnumInner.Current;
}
}
public bool MoveNext()
{
if(!iEnumInner.MoveNext())
{
if (!iEnumRoot.MoveNext()) return false;
innerHt = (Hashtable)((DictionaryEntry)iEnumRoot.Current).Value;
iEnumInner = innerHt.GetEnumerator();
iEnumInner.MoveNext();
}
return true;
}
#endregion
}
}
}
해시 테이블을 "이중 중첩"할 수 있습니다. 즉, 기본 사전은 유형 Dictionary<int, Dictionary<bool, my_return_type>>
입니다.
이는 첫 번째 코드 스 니펫에서 이중 대괄호 표기법을 사용할 수 있다는 목표를 달성합니다.
물론 관리 측면은 조금 더 까다 롭습니다. 항목을 추가 할 때마다 기본 사전에 기본 키에 대한 사전이 포함되어 있는지 테스트하고 그렇지 않은 경우 새 사전을 추가 한 다음 내부 사전에 보조 키와 값을 추가해야합니다.
사용할 수 Dictionary<KeyValuePair<int,bool>,int>
있습니까?
2 차원 키를 개별적으로 감싸고 type
해당 유형을 키로 사용합니다. 재정의 GetHashCode()
및 Equals()
메서드 도 고려하십시오 . 가급적 이면 Dictionary<>
대신 사용할 HashTable
수 있습니다.
빠르고 더러운 방법은 두 가지 정보에서 복합 키를 만드는 것입니다.
IDictionary<string, int> values = new Dictionary<string, int>();
int i = ...;
bool b = ...;
string key = string.Concat(i, '\0', b);
values[key] = 555;
이것을 좀 더 잘 캡슐화하려면 사전을 래핑 할 수 있습니다.
public class MyDict
{
private readonly IDictionary<string, int> values = new Dictionary<string, int>();
public int this[int i, bool b]
{
get
{
string key = BuildKey(i, b);
return values[key];
}
set
{
string key = BuildKey(i, b);
values[key] = value;
}
}
private static string BuildKey(int i, bool b)
{
return string.Concat(i, '\0', b);
}
}
To make this more robust, encapsulate the composite key as a type, e.g. a class that contains the two fields, ensuring you override the Equals() and GetHashCode() methods correctly.
Look, this code works just fine:
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
this.Services = new Dictionary<object, Hashtable>();
this.Services.Add("array1", new Hashtable());
this.Services["array1"]["qwe"] = "123";
this.Services["array1"][22] = 223;
object zz = null;
zz = this.Services["array1"]["qwe"];
MessageBox.Show(zz.ToString()); // shows qwe
zz = this.Services["array1"][22];
MessageBox.Show(zz.ToString()); // shows 22
}
Now we just need a wrapper to avoid manually doing this.Services.Add("array1", new Hashtable());
I think the easiest way to do it now is to use Tupple.Create and ValueTuple.Create:
> var k1 = Tuple.Create("test", int.MinValue, DateTime.MinValue, double.MinValue);
> var k2 = Tuple.Create("test", int.MinValue, DateTime.MinValue, double.MinValue);
> var dict = new Dictionary<object, object>();
> dict.Add(k1, "item");
> dict.Add(k2, "item");
An item with the same key has already been added....
> dict[k1] == dict[k2]
true
or use new c#7 tuple syntax to create tuple-keys:
var k = (item1: "value1", item2: 123);
This is my nested Dictionary implementation:
public class TwoKeysDictionary<K1, K2, T>:
Dictionary<K1, Dictionary<K2, T>>
{
public T this[K1 key1, K2 key2]
{
get => base.ContainsKey(key1) && base[key1].ContainsKey(key2) ? base[key1][key2] : default;
set
{
if (ContainsKey(key1) && base[key1].ContainsKey(key2))
base[key1][key2] = value;
else
Add(key1, key2, value);
}
}
public void Add(K1 key1, K2 key2, T value)
{
if (ContainsKey(key1))
{
if (base[key1].ContainsKey(key2))
throw new Exception("Couple " + key1 + "/" + key2 + " already exists!");
base[key1].Add(key2, value);
}
else
Add(key1, new Dictionary<K2, T>() { { key2, value } });
}
public bool ContainsKey(K1 key1, K2 key2) => ContainsKey(key1) && base[key1].ContainsKey(key2);
}
참고URL : https://stackoverflow.com/questions/689940/hashtable-with-multidimensional-key-in-c-sharp
'Nice programing' 카테고리의 다른 글
Jenkins 파이프 라인의 조건부 단계 / 단계 (0) | 2020.11.26 |
---|---|
Python 확장-swig 또는 Cython이 아닌 swig로 (0) | 2020.11.26 |
포함 된 이미지가 포함 된 Multipart HTML 이메일 보내기 (0) | 2020.11.26 |
파일의 각 줄에서 선행 공백을 제거하는 방법 (0) | 2020.11.26 |
MacOS에서 Android 애플리케이션을 개발할 수 있습니까? (0) | 2020.11.26 |