2015-09-18 49 views
0

,你骂我之前,我知道有一个非常类似的问题:数据结构现在

Best data structure for two way mapping?

其实,我找了一个数据结构,将完成相同事情。具体来说,我有一个字符串应该被映射到另一个字符串,而另一个字符串也应该映射到原始字符串。

例如:

".jpg" -> "image/jpeg" 
"image/jpeg" -> ".jpg" 

链接的问题建议使用某种HashMap的或Dictionary<string,string>的做到这一点。

人们必须将持有两个字典,每个字典是映射的一种方式自定义数据类型。这将提供O(1),但我发现它根本不可扩缩

考虑到我有一个字典从200种MIME类型相关的文件扩展名的映射,我需要建立一个类似的,具有相同的内容,但反转。这很容易出现拼写错误或丢失键,并且是很多重复的代码。我想在C#寻找一个解决方案。

是否有支持这些类型的物体之间的双向映射.NET数据结构?

如果没有,我怎么能做到这一点,而不复制代码(如两个库解决方案)?

+0

从理论上讲,你需要'dictionary.Add(“.jpg”,“image/jpg”)'',并且可以将它用作var mime = dictionary [“。jpg”]''var var ext = dictionary [ “图像/ JPG”]'? –

+0

@DaveZych正是! –

+0

似乎有点毫无意义,因为你仍然可以明确映射这些关系已经.. –

回答

2

为什么使用两个字典的自定义类型不起作用?虽然它会使用两倍的内存,但它允许O(1)查找,并且应该按照您的要求工作。

然而,当涉及到通用参数,它可以变得有点毛。如果指定了相同的类型,这不是问题,但是如果指定了不同的类型,则索引器会中断,因为只能以单向方式获取值。如果你重载索引,有两个,即:

public K this[T value] 
public T this[K value] 

这将打破,如果你有相同的参数,因为它不能够解决。在这种情况下,我建议有两个不同的类别:

public class TwoWayDictionary<T> 
{ 
    private Dictionary<T, T> _first; 
    private Dictionary<T, T> _second; 

    public TwoWayDictionary() 
    { 
     _first = new Dictionary<T, T>(); 
     _second = new Dictionary<T, T>(); 
    } 

    public void Add(T first, T second) 
    { 
     _first.Add(first, second); 
     _second.Add(second, first); 
    } 

    public T this[T value] 
    { 
     get 
     { 
      if(_first.ContainsKey(value)) 
      { 
       return _first[value]; 
      } 
      if(_second.ContainsKey(value)) 
      { 
       return _second[value]; 
      } 

      throw new ArgumentException(nameof(value)); 
     } 
    } 
} 

public class TwoWayDictionary<T, K> 
{ 
    private readonly Dictionary<T, K> _first; 
    private readonly Dictionary<K, T> _second; 

    public TwoWayDictionary() 
    { 
     _first = new Dictionary<T, K>(); 
     _second = new Dictionary<K, T>(); 
    } 

    public void Add(T first, K second) 
    { 
     _first.Add(first, second); 
     _second.Add(second, first); 
    } 

    public K this[T value] 
    { 
     get 
     { 
      if (_first.ContainsKey(value)) 
      { 
       return _first[value]; 
      } 

      throw new ArgumentException(nameof(value)); 
     } 
    } 

    public T this[K value] 
    { 
     get 
     { 
      if (_second.ContainsKey(value)) 
      { 
       return _second[value]; 
      } 

      throw new ArgumentException(nameof(value)); 
     } 
    } 
}  

这将允许你使用它就像在评论中提到:

var dict = new TwoWayDictionary<string>(); 
dict.Add(".jpg", "image/jpg"); 
var mime = dict[".jpg"]; 
var ext = dict["image/jpg"]; 

,并指定2如果你想不同的类型:

var dict = new TwoWayDictionary<string, int>(); 
dict.Add(".jpg", 100); 
var number = dict[".jpg"]; 
var ext = dict[100]; 
+0

我是为了它。唯一我不喜欢的是索引器的二元性。我宁愿公开两个单独的方法,例如'string GetFirst(string second)'和'string GetSecond(string first)' –

+0

@IvanStoev揭露两个单独的索引器几乎完全打败了类的目的。如果这样做,你将不得不在课堂外进行包含/空的检查。在那种情况下,为什么即使有班级 - 为什么不只是有2个字典,并检查他们每个人的存在。 –

+0

我不这么认为。我看到的这个类的主要好处是**封装**。还可以想象你引入了像TwoWayDictionary 这样的通用参数。那么索引器的签名是什么?顺便说一句,我upvoted你的答案,所以我们在同一方:-) –