Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/338.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
具有唯一键和值的C#字典类型_C#_Collections_Dictionary - Fatal编程技术网

具有唯一键和值的C#字典类型

具有唯一键和值的C#字典类型,c#,collections,dictionary,C#,Collections,Dictionary,我想知道C语言中是否有一个类似于“Dictionary”的内置类型,但TKey和TValue必须是唯一的 例如: d.Add(1, "1"); d.Add(2, "1"); // This would not be OK because "1" has already been used as a value. 我知道这有点异国情调,但似乎因为BCL中有大约十亿种收集类型,它可能存在。有什么想法吗?使用字典和HashSet/二级反向字典怎么样?它将解决这个问题,并且比单一字典的检查性能更好 类

我想知道C语言中是否有一个类似于“Dictionary”的内置类型,但TKey和TValue必须是唯一的

例如:

d.Add(1, "1");
d.Add(2, "1"); // This would not be OK because "1" has already been used as a value.

我知道这有点异国情调,但似乎因为BCL中有大约十亿种收集类型,它可能存在。有什么想法吗?

使用字典和HashSet/二级反向字典怎么样?它将解决这个问题,并且比单一字典的检查性能更好

类似这样的东西,包装为类:

HashSet<string> secondary = new HashSet<string>(/*StringComparer.InvariantCultureIgnoreCase*/);
Dictionary<int, string>dictionary = new Dictionary<int, string>();
object syncer = new object();

public override void Add(int key, string value)
{
  lock(syncer)
  {
    if(dictionary.ContainsKey(key))
    {
      throw new Exception("Key already exists");
    }

    if(secondary.Add(value)
    {
      throw new Exception("Value already exists");
    }
    dictionary.Add(key, value);
  }
}
HashSet secondary=新的HashSet(/*StringComparer.InvariantCultureIgnoreCase*/);
Dictionarydictionary=新字典();
对象同步器=新对象();
公共覆盖无效添加(整型键,字符串值)
{
锁定(同步器)
{
if(字典容器(键))
{
抛出新异常(“密钥已存在”);
}
如果(次要)添加(值)
{
抛出新异常(“值已存在”);
}
添加(键、值);
}
}

有一个项目的类型是这样的。它被称为PairDictionary,它工作得很好。这不是最好的答案,但适合任何需要自定义类的人。

我通过将数据存储为
字典解决了这个问题。
如果需要具有2个主键的值,可以用另一个字典替换哈希集

Dictionary<int, HashSet<int>> _myUniquePairOfIntegerKeys;
// OR
Dictionary<string, Dictionary<string, bool>> _myUniquePairOfStringKeysWithABooleanValue;
Dictionary\u myUniquePairOfIntegerKeys;
//或
字典_myuniquepairofstringkeys,带有一个布尔值;

对于内部密码,我编写了一个
双字典
。它不是防弹的,因为我没有将它暴露给用户,所以对我来说效果很好。它允许我根据需要获取任意一个密钥

KeyPair
是实现
IEnumerable
Add
方法所必需的,这样我们就可以使用对象初始值设定项

internal class KeyPair<TKey1, TKey2>
{
    public TKey1 Key1 { get; set; }
    public TKey2 Key2 { get; set; }
}
内部类密钥对
{
public TKey1 Key1{get;set;}
public TKey2 Key2{get;set;}
}
这是作为动态对象的主类,因此我们可以在检索值时在其上使用键名:

internal class BiDictionary<TKey1, TKey2> : DynamicObject, IEnumerable<KeyPair<TKey1, TKey2>>
{
    private readonly Dictionary<TKey1, TKey2> _K1K2 = new Dictionary<TKey1, TKey2>();
    private readonly Dictionary<TKey2, TKey1> _K2K1 = new Dictionary<TKey2, TKey1>();

    private readonly string _key1Name;
    private readonly string _key2Name;

    public BiDictionary(string key1Name, string key2Name)
    {
        _key1Name = key1Name;
        _key2Name = key2Name;
    }

    public override bool TryGetMember(GetMemberBinder binder, out object result)
    {
        if (binder.Name == _key1Name)
        {
            result = _K1K2;
            return true;
        }

        if (binder.Name == _key2Name)
        {
            result = _K2K1;
            return true;
        }

        result = null;
        return false;
    }

    public void Add(TKey1 key1, TKey2 key2)
    { 
        _K1K2.Add(key1, key2);
        _K2K1.Add(key2, key1);
    }

    public IEnumerator<KeyPair<TKey1, TKey2>> GetEnumerator()
    {
        return _K1K2.Zip(_K2K1, (d1, d2) => new KeyPair<TKey1, TKey2>
        {
            Key1 = d1.Key,
            Key2 = d2.Key
        }).GetEnumerator();
    }

    IEnumerator IEnumerable.GetEnumerator()
    {
        return GetEnumerator();
    }
}
内部类BiDictionary:DynamicObject,IEnumerable
{
专用只读词典_K1K2=新词典();
专用只读词典_K2K1=新词典();
私有只读字符串_key1Name;
私有只读字符串_key2Name;
公开投标书(字符串key1名称,字符串key2名称)
{
_key1Name=key1Name;
_key2Name=key2Name;
}
公共重写bool TryGetMember(GetMemberBinder绑定器,输出对象结果)
{
如果(binder.Name==\u key1Name)
{
结果=_K1K2;
返回true;
}
if(binder.Name==\u key2Name)
{
结果=_K2K1;
返回true;
}
结果=空;
返回false;
}
公共无效添加(TKey1键1、TKey1键2)
{ 
_K1K2.添加(键1、键2);
_K2K1.添加(键2,键1);
}
公共IEnumerator GetEnumerator()
{
return K1K2.Zip(K2K1,(d1,d2)=>新密钥对
{
键1=d1。键,
键2=d2。键
}).GetEnumerator();
}
IEnumerator IEnumerable.GetEnumerator()
{
返回GetEnumerator();
}
}
例如:

dynamic bidic = new BiDictionary<string, string>("Key1", "Key2") 
{ 
    { "foo", "bar" }, 
    { "baz", "qux" } 
};
var bar = bidic.Key1["foo"];
var foo = bidic.Key2["bar"];
dynamic bidic=new BiDictionary(“键1”、“键2”)
{ 
{“foo”,“bar”},
{“baz”,“qux”}
};
var bar=bidic.Key1[“foo”];
var foo=bidic.Key2[“bar”];


如果您在外部修改任何词典,它们可能会不同步。为此,我使用了
observedictionary
,以便在一个词典发生更改时可以更新另一个词典,但为了简单起见,我删除了这部分代码,只是演示了主逻辑。

您可以实现一个扩展方法,该方法跳过添加到如果给定值已存在,则使用字典

static class Extensions
{
    public static void AddSafe(this Dictionary<int, string> dictionary, int key, string value)
    {
        if (!dictionary.ContainsValue(value))
            dictionary.Add(key, value);
    }
}

使值成为键的一部分。在.NET Framework中没有这样的类。但是你可以很容易地用一个字典和一个哈希集或两个字典构造一个。@Robert Harvey:如果他这样做了,他就不能做
d[1]
不再使用,这违背了字典的目的。不妨使用HashSet@RobertHarvey:如果您只有键的一半,您将如何检索另一半?请参阅-您必须存储额外的
char
,但是
元组可能适合您。尽管这与另一个com中提到的问题相同然后将其包装在自定义类中。@Jason如果您需要它超过一次-绝对是!@OlegDok如果您必须阅读代码超过一次-绝对是!(您应该希望有一天必须再次阅读此代码。)
PairDictionary
是一个糟糕的解决方案。它在内部处理列表,并且每个操作都是一个O(n)操作,不同于O(1)真正的字典---@t3chb0t您关注的是实现,而不是API。是的,它不是最好的,但它的使用才是重要的。因为这是一些开放源代码的一部分,所以您应该提交一个改进功能的补丁:)
d.AddSafe(1, "1");
d.AddSafe(2, "1"); // This would not add anything