에 중복된 키가 있습니다.NET 사전?
에 사전 클래스가 있습니까?중복 키를 사용할 수 있는 NET 기본 클래스 라이브러리를 선택하십시오.내가 찾은 유일한 해결책은 예를 들어 다음과 같은 클래스를 만드는 것입니다.
Dictionary<string, List<object>>
하지만 이것은 실제로 사용하기에는 꽤 짜증나는 일입니다.Java에서 MultiMap은 이를 수행하지만 에서 아날로그를 찾을 수 없습니다.그물.
를 사용하는 경우.NET 3.5, 클래스를 사용합니다.
으로 집편: .Lookup
…을 사용하여이는 나중에 변경할 필요가 없다고 가정하지만 일반적으로 충분하다고 생각합니다.
만약 그것이 당신에게 효과가 없다면, 저는 프레임워크에 도움이 될 만한 것이 없다고 생각합니다 - 그리고 사전을 사용하는 것은 얻는 것만큼 좋습니다 :(
목록 클래스는 실제로 컬렉션 위에서 반복할 중복 항목이 포함된 키/값 컬렉션에 매우 적합합니다.예:
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
문자열을 키와 값으로 모두 사용하는 경우 시스템을 사용할 수 있습니다.컬렉션.전문화된.NameValueCollection - GetValues(문자열 키) 메서드를 통해 문자열 값 배열을 반환합니다.
저는 방금 PowerCollections 라이브러리를 발견했습니다. 여기에는 MultiDictionary라는 클래스가 포함되어 있습니다.이것은 이러한 유형의 기능을 깔끔하게 포장합니다.
Lookup 사용과 관련하여 매우 중요한 참고 사항:
의인스를생수있다니의 수 .Lookup(TKey, TElement)
화로로 ToLookup
을 에.IEnumerable(T)
새인스를만공없생다습니성의 새 를 만들 .Lookup(TKey, TElement)
.또한.Lookup(TKey, TElement)
즉, 할 수 .Lookup(TKey, TElement)
개체를 만든 후 개체를 클릭합니다.
저는 이것이 대부분의 용도의 쇼 스토퍼가 될 것이라고 생각합니다.
새로운 C#(7.0의 C#인 것으로 생각됨)을 사용하면 다음과 같은 작업을 수행할 수 있습니다.
var duplicatedDictionaryExample = new List<(string Key, string Value)> { ("", "") ... }
그리고 당신은 그것을 표준 목록으로 사용하고 있지만, 당신이 원하는 대로 이름을 붙인 두 개의 값을 가지고 있습니다.
foreach(var entry in duplicatedDictionaryExample)
{
// do something with the values
entry.Key;
entry.Value;
}
제 생각에는 그런 것 같아요.List<KeyValuePair<object, object>>
그 일을 할 것입니다.
> .> = 를 하는 경우.를 사용하면 NET 4를 사용자는 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 }
당신은 실제 복제품이 아니라 일치한다는 것을 의미합니까?그렇지 않으면 해시 테이블이 작동하지 않습니다.
일치는 두 개의 개별 키가 동등한 값으로 해시될 수 있지만 키가 같지 않다는 것을 의미합니다.
예를 들어, 해시 테이블의 해시 함수가 단지 hashval = key mod 3이었다고 가정합니다.1과 4는 모두 1에 매핑되지만 다른 값입니다.이것이 목록에 대한 당신의 생각이 작용하는 부분입니다.
1을 조회해야 하는 경우 해당 값이 1로 해시되면 키 = 1이 발견될 때까지 목록이 순회됩니다.
중복 키를 삽입하도록 허용한 경우 어떤 키가 어떤 값에 매핑되는지 구분할 수 없습니다.
제가 사용하는 방법은 그냥
Dictionary<string, List<string>>
이렇게 하면 문자열 목록이 들어 있는 단일 키를 가질 수 있습니다.
예:
List<string> value = new List<string>();
if (dictionary.Contains(key)) {
value = dictionary[key];
}
value.Add(newValue);
다음과 같은 사전 래퍼를 만들 수 있습니다. 보너스로 null 값을 키로 지원합니다.
/// <summary>
/// Dictionary which supports duplicates and null entries
/// </summary>
/// <typeparam name="TKey">Type of key</typeparam>
/// <typeparam name="TValue">Type of items</typeparam>
public class OpenDictionary<TKey, TValue>
{
private readonly Lazy<List<TValue>> _nullStorage = new Lazy<List<TValue>>(
() => new List<TValue>());
private readonly Dictionary<TKey, List<TValue>> _innerDictionary =
new Dictionary<TKey, List<TValue>>();
/// <summary>
/// Get all entries
/// </summary>
public IEnumerable<TValue> Values =>
_innerDictionary.Values
.SelectMany(x => x)
.Concat(_nullStorage.Value);
/// <summary>
/// Add an item
/// </summary>
public OpenDictionary<TKey, TValue> Add(TKey key, TValue item)
{
if (ReferenceEquals(key, null))
_nullStorage.Value.Add(item);
else
{
if (!_innerDictionary.ContainsKey(key))
_innerDictionary.Add(key, new List<TValue>());
_innerDictionary[key].Add(item);
}
return this;
}
/// <summary>
/// Remove an entry by key
/// </summary>
public OpenDictionary<TKey, TValue> RemoveEntryByKey(TKey key, TValue entry)
{
if (ReferenceEquals(key, null))
{
int targetIdx = _nullStorage.Value.FindIndex(x => x.Equals(entry));
if (targetIdx < 0)
return this;
_nullStorage.Value.RemoveAt(targetIdx);
}
else
{
if (!_innerDictionary.ContainsKey(key))
return this;
List<TValue> targetChain = _innerDictionary[key];
if (targetChain.Count == 0)
return this;
int targetIdx = targetChain.FindIndex(x => x.Equals(entry));
if (targetIdx < 0)
return this;
targetChain.RemoveAt(targetIdx);
}
return this;
}
/// <summary>
/// Remove all entries by key
/// </summary>
public OpenDictionary<TKey, TValue> RemoveAllEntriesByKey(TKey key)
{
if (ReferenceEquals(key, null))
{
if (_nullStorage.IsValueCreated)
_nullStorage.Value.Clear();
}
else
{
if (_innerDictionary.ContainsKey(key))
_innerDictionary[key].Clear();
}
return this;
}
/// <summary>
/// Try get entries by key
/// </summary>
public bool TryGetEntries(TKey key, out IReadOnlyList<TValue> entries)
{
entries = null;
if (ReferenceEquals(key, null))
{
if (_nullStorage.IsValueCreated)
{
entries = _nullStorage.Value;
return true;
}
else return false;
}
else
{
if (_innerDictionary.ContainsKey(key))
{
entries = _innerDictionary[key];
return true;
}
else return false;
}
}
}
사용 예:
var dictionary = new OpenDictionary<string, int>();
dictionary.Add("1", 1);
// The next line won't throw an exception;
dictionary.Add("1", 2);
dictionary.TryGetEntries("1", out List<int> result);
// result is { 1, 2 }
dictionary.Add(null, 42);
dictionary.Add(null, 24);
dictionary.TryGetEntries(null, out List<int> result);
// result is { 42, 24 }
같은 답을 찾다가 우연히 이 게시물을 발견하지 못했기 때문에 사전 목록을 사용하여 맨본 예제 솔루션을 구성하고, 다른 모든 사용자가 지정된 키(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;
사전을 사용하여 복합 문자열 키를 작성할 방법을 정의할 수 있습니다. 이 방법을 사용하여 키를 작성해야 합니다. 예를 들어 다음과 같습니다.
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
키1
KeY1
kEy1
키 Y1
바보 같은 대답인 건 알지만, 저를 위해 일했습니다.
언급URL : https://stackoverflow.com/questions/146204/duplicate-keys-in-net-dictionaries
'source' 카테고리의 다른 글
오류 발생: @출력이 초기화되지 않음 (0) | 2023.05.02 |
---|---|
이클립스, 현재 디버그 라인 배경을 변경할 위치는 어디입니까? (0) | 2023.05.02 |
ReSharper의 대안은 무엇입니까? (0) | 2023.05.02 |
Azure Key Vault의 키와 비밀의 차이점은 무엇입니까? (0) | 2023.05.02 |
자바스크립트에서 배열에서 특정 항목을 제거하려면 어떻게 해야 합니까? (0) | 2023.05.02 |