.NET 사전에 중복 키가 있습니까?
.NET 기본 클래스 라이브러리에 중복 키를 사용할 수있는 사전 클래스가 있습니까? 내가 찾은 유일한 해결책은 예를 들어 다음과 같은 클래스를 만드는 것입니다.
Dictionary<string, List<object>>
그러나 이것은 실제로 사용하는 데 매우 자극적입니다. Java에서는 MultiMap 이이 작업을 수행하지만 .NET에서 아날로그를 찾을 수 없다고 생각합니다.
.NET 3.5를 사용하는 경우 Lookup
클래스를 사용하십시오 .
편집 : 당신은 일반적으로 Lookup
using을 만듭니다 Enumerable.ToLookup
. 이것은 나중에 변경하지 않아도된다고 가정하지만 일반적으로 충분합니다.
그 경우 하지 않는 당신을 위해 일을, 내가 도움이 될 것입니다 프레임 워크에서 아무것도 생각하지 않습니다 - 그리고 사전을 사용하는 것이 좋은가수록 같다가 :(
List 클래스는 실제로 컬렉션을 반복하려는 중복이 포함 된 키 / 값 컬렉션에 매우 효과적입니다. 예:
List<KeyValuePair<string, string>> list = new List<KeyValuePair<string, string>>();
// add some values to the collection here
for (int i = 0; i < list.Count; i++)
{
Print(list[i].Key, list[i].Value);
}
List <KeyValuePair <string, string>>로이를 수행하는 한 가지 방법이 있습니다.
public class ListWithDuplicates : List<KeyValuePair<string, string>>
{
public void Add(string key, string value)
{
var element = new KeyValuePair<string, string>(key, value);
this.Add(element);
}
}
var list = new ListWithDuplicates();
list.Add("k1", "v1");
list.Add("k1", "v2");
list.Add("k1", "v3");
foreach(var item in list)
{
string x = string.format("{0}={1}, ", item.Key, item.Value);
}
출력 k1 = v1, k1 = v2, k1 = v3
문자열을 키와 값으로 모두 사용하는 경우 System.Collections.Specialized.NameValueCollection 을 사용 하면 GetValues (string key) 메서드를 통해 문자열 값의 배열을 반환합니다.
나는 방금 MultiDictionary라는 클래스를 포함 하는 PowerCollections 라이브러리를 발견했습니다. 이것은 이러한 유형의 기능을 깔끔하게 마무리합니다.
조회 사용에 관한 매우 중요한 참고 사항 :
구현하는 객체를 Lookup(TKey, TElement)
호출 하여의 인스턴스를 만들 수 있습니다ToLookup
IEnumerable(T)
의 새 인스턴스를 만들 수있는 공개 생성자가 없습니다 Lookup(TKey, TElement)
. 또한 Lookup(TKey, TElement)
개체는 변경할 수 없습니다. 즉 , 개체 나 키를 Lookup(TKey, TElement)
만든 후에 는 개체 나 키를 추가하거나 제거 할 수 없습니다 .
나는 이것이 대부분의 사용을위한 쇼 스토퍼라고 생각합니다.
나는 List<KeyValuePair<object, object>>
욥 과 같은 일이 생각된다 .
> = .NET 4를 사용하는 경우 Tuple
클래스 를 사용할 수 있습니다 .
// declaration
var list = new List<Tuple<string, List<object>>>();
// to add an item to the list
var item = Tuple<string, List<object>>("key", new List<object>);
list.Add(item);
// to iterate
foreach(var i in list)
{
Console.WriteLine(i.Item1.ToString());
}
"중복 키"항목을 허용하는 사전의 "자신의"버전을 쉽게 롤백 할 수 있습니다. 다음은 대략적인 간단한 구현입니다. 기본적으로 (모두는 아니지만)에 대한 대부분의 지원을 추가하는 것이 IDictionary<T>
좋습니다.
public class MultiMap<TKey,TValue>
{
private readonly Dictionary<TKey,IList<TValue>> storage;
public MultiMap()
{
storage = new Dictionary<TKey,IList<TValue>>();
}
public void Add(TKey key, TValue value)
{
if (!storage.ContainsKey(key)) storage.Add(key, new List<TValue>());
storage[key].Add(value);
}
public IEnumerable<TKey> Keys
{
get { return storage.Keys; }
}
public bool ContainsKey(TKey key)
{
return storage.ContainsKey(key);
}
public IList<TValue> this[TKey key]
{
get
{
if (!storage.ContainsKey(key))
throw new KeyNotFoundException(
string.Format(
"The given key {0} was not found in the collection.", key));
return storage[key];
}
}
}
사용 방법에 대한 간단한 예 :
const string key = "supported_encodings";
var map = new MultiMap<string,Encoding>();
map.Add(key, Encoding.ASCII);
map.Add(key, Encoding.UTF8);
map.Add(key, Encoding.Unicode);
foreach (var existingKey in map.Keys)
{
var values = map[existingKey];
Console.WriteLine(string.Join(",", values));
}
원래 질문에 대한 답변. 와 같은 Dictionary<string, List<object>>
클래스에서 호출 MultiMap
됩니다 Code Project
.
아래 링크에 대한 자세한 정보를 찾을 수 있습니다 : http://www.codeproject.com/KB/cs/MultiKeyDictionary.aspx
NameValueCollection은 하나의 키 (문자열이기도 함)에서 여러 문자열 값을 지원하지만 내가 아는 유일한 예입니다.
나는 그런 종류의 기능이 필요한 상황에 처할 때 귀하의 예와 비슷한 구조를 만드는 경향이 있습니다.
사용하는 경우 List<KeyValuePair<string, object>>
옵션을, 당신은 검색을 수행 LINQ를 사용할 수 있습니다 :
List<KeyValuePair<string, object>> myList = new List<KeyValuePair<string, object>>();
//fill it here
var q = from a in myList Where a.Key.Equals("somevalue") Select a.Value
if(q.Count() > 0){ //you've got your value }
내가 사용하는 방식은
Dictionary<string, List<string>>
이렇게하면 문자열 목록을 보유하는 단일 키가 있습니다.
예:
List<string> value = new List<string>();
if (dictionary.Contains(key)) {
value = dictionary[key];
}
value.Add(newValue);
실제 복제본이 아니라 합동을 의미합니까? 그렇지 않으면 해시 테이블이 작동하지 않습니다.
합동은 두 개의 개별 키가 동등한 값으로 해시 할 수 있지만 키가 동일하지 않음을 의미합니다.
예를 들어, 해시 테이블의 해시 함수는 hashval = key mod 3이라고 가정하십시오. 1과 4는 모두 1에 매핑되지만 다른 값입니다. 이것은 목록에 대한 아이디어가 작용하는 곳입니다.
1을 조회해야하는 경우 해당 값은 1로 해시되며 Key = 1을 찾을 때까지 목록이 순회됩니다.
중복 키를 삽입 할 수 있으면 어떤 키가 어떤 값에 매핑되는지 구별 할 수 없습니다.
나는 같은 대답을 찾기 위해이 게시물을 우연히 발견했지만 아무것도 찾지 못했기 때문에 사전 목록을 사용하여 기본 예제 솔루션을 리깅하여 [] 연산자를 재정 의하여 다른 모든 사람들이 목록에 새 사전을 추가하도록했습니다. 주어진 키 (set), 값 목록 (get)을 반환합니다.
추악하고 비효율적이며 키로 만 가져오고 설정하며 항상 목록을 반환하지만 작동합니다.
class DKD {
List<Dictionary<string, string>> dictionaries;
public DKD(){
dictionaries = new List<Dictionary<string, string>>();}
public object this[string key]{
get{
string temp;
List<string> valueList = new List<string>();
for (int i = 0; i < dictionaries.Count; i++){
dictionaries[i].TryGetValue(key, out temp);
if (temp == key){
valueList.Add(temp);}}
return valueList;}
set{
for (int i = 0; i < dictionaries.Count; i++){
if (dictionaries[i].ContainsKey(key)){
continue;}
else{
dictionaries[i].Add(key,(string) value);
return;}}
dictionaries.Add(new Dictionary<string, string>());
dictionaries.Last()[key] =(string)value;
}
}
}
@Hector Correa의 답변을 일반 유형의 확장으로 변경하고 사용자 지정 TryGetValue를 추가했습니다.
public static class ListWithDuplicateExtensions
{
public static void Add<TKey, TValue>(this List<KeyValuePair<TKey, TValue>> collection, TKey key, TValue value)
{
var element = new KeyValuePair<TKey, TValue>(key, value);
collection.Add(element);
}
public static int TryGetValue<TKey, TValue>(this List<KeyValuePair<TKey, TValue>> collection, TKey key, out IEnumerable<TValue> values)
{
values = collection.Where(pair => pair.Key.Equals(key)).Select(pair => pair.Value);
return values.Count();
}
}
이것은 동시대 사전입니다. 이것이 도움이 될 것이라고 생각합니다.
public class HashMapDictionary<T1, T2> : System.Collections.IEnumerable
{
private System.Collections.Concurrent.ConcurrentDictionary<T1, List<T2>> _keyValue = new System.Collections.Concurrent.ConcurrentDictionary<T1, List<T2>>();
private System.Collections.Concurrent.ConcurrentDictionary<T2, List<T1>> _valueKey = new System.Collections.Concurrent.ConcurrentDictionary<T2, List<T1>>();
public ICollection<T1> Keys
{
get
{
return _keyValue.Keys;
}
}
public ICollection<T2> Values
{
get
{
return _valueKey.Keys;
}
}
public int Count
{
get
{
return _keyValue.Count;
}
}
public bool IsReadOnly
{
get
{
return false;
}
}
public List<T2> this[T1 index]
{
get { return _keyValue[index]; }
set { _keyValue[index] = value; }
}
public List<T1> this[T2 index]
{
get { return _valueKey[index]; }
set { _valueKey[index] = value; }
}
public void Add(T1 key, T2 value)
{
lock (this)
{
if (!_keyValue.TryGetValue(key, out List<T2> result))
_keyValue.TryAdd(key, new List<T2>() { value });
else if (!result.Contains(value))
result.Add(value);
if (!_valueKey.TryGetValue(value, out List<T1> result2))
_valueKey.TryAdd(value, new List<T1>() { key });
else if (!result2.Contains(key))
result2.Add(key);
}
}
public bool TryGetValues(T1 key, out List<T2> value)
{
return _keyValue.TryGetValue(key, out value);
}
public bool TryGetKeys(T2 value, out List<T1> key)
{
return _valueKey.TryGetValue(value, out key);
}
public bool ContainsKey(T1 key)
{
return _keyValue.ContainsKey(key);
}
public bool ContainsValue(T2 value)
{
return _valueKey.ContainsKey(value);
}
public void Remove(T1 key)
{
lock (this)
{
if (_keyValue.TryRemove(key, out List<T2> values))
{
foreach (var item in values)
{
var remove2 = _valueKey.TryRemove(item, out List<T1> keys);
}
}
}
}
public void Remove(T2 value)
{
lock (this)
{
if (_valueKey.TryRemove(value, out List<T1> keys))
{
foreach (var item in keys)
{
var remove2 = _keyValue.TryRemove(item, out List<T2> values);
}
}
}
}
public void Clear()
{
_keyValue.Clear();
_valueKey.Clear();
}
IEnumerator IEnumerable.GetEnumerator()
{
return _keyValue.GetEnumerator();
}
}
예 :
public class TestA
{
public int MyProperty { get; set; }
}
public class TestB
{
public int MyProperty { get; set; }
}
HashMapDictionary<TestA, TestB> hashMapDictionary = new HashMapDictionary<TestA, TestB>();
var a = new TestA() { MyProperty = 9999 };
var b = new TestB() { MyProperty = 60 };
var b2 = new TestB() { MyProperty = 5 };
hashMapDictionary.Add(a, b);
hashMapDictionary.Add(a, b2);
hashMapDictionary.TryGetValues(a, out List<TestB> result);
foreach (var item in result)
{
//do something
}
이 간단한 클래스를 사용합니다.
public class ListMap<T,V> : List<KeyValuePair<T, V>>
{
public void Add(T key, V value) {
Add(new KeyValuePair<T, V>(key, value));
}
public List<V> Get(T key) {
return FindAll(p => p.Key.Equals(key)).ConvertAll(p=> p.Value);
}
}
용법:
var fruits = new ListMap<int, string>();
fruits.Add(1, "apple");
fruits.Add(1, "orange");
var c = fruits.Get(1).Count; //c = 2;
U는 사전을 사용하려는 모든 위치에서 복합 문자열 키를 작성하는 방법을 정의 할 수 있습니다.
private string keyBuilder(int key1, int key2)
{
return string.Format("{0}/{1}", key1, key2);
}
사용하기 위해 :
myDict.ContainsKey(keyBuilder(key1, key2))
중복 키는 사전의 전체 계약을 위반합니다. 사전에서 각 키는 고유하며 단일 값으로 매핑됩니다. 객체를 임의의 수의 추가 객체에 연결하려는 경우 가장 좋은 방법은 DataSet과 유사합니다 (일반적으로 테이블). 한 열에는 키를, 다른 열에는 키를 넣으십시오. 이것은 사전보다 상당히 느리지 만 주요 객체를 해시하는 기능을 잃어 버린 것은 절충입니다.
또한 가능합니다 :
Dictionary<string, string[]> previousAnswers = null;
이런 식으로 고유 키를 가질 수 있습니다. 이것이 효과가 있기를 바랍니다.
다음과 같이 다른 경우에 동일한 키를 추가 할 수 있습니다.
키 1
키 1
KEY1
키 1
키 1
키 1
나는 답이 더미라는 것을 알고 있지만 나를 위해 일했다.
참고 URL : https://stackoverflow.com/questions/146204/duplicate-keys-in-net-dictionaries
'IT story' 카테고리의 다른 글
Eclipse는 일치하는 변수를 강조 표시하지 않습니다 (0) | 2020.04.09 |
---|---|
CSS의 HTML colspan (0) | 2020.04.09 |
tensorflow가 GPU 메모리의 전체를 할당하지 못하게하는 방법은 무엇입니까? (0) | 2020.04.09 |
bash는 함수의 정의를 보여줄 수 있습니까? (0) | 2020.04.09 |
handler.postdelayed 프로세스 취소 (0) | 2020.04.09 |