如何将Comparer用于HashSet

时间:2009-06-21 08:14:25

标签: c# templates dictionary hashset

由于我在这里问的另一个问题,我想为我的对象使用HashSet

我将创建包含字符串的对象和对其所有者的引用。

public class Synonym
{
   private string name;
   private Stock owner;
   public Stock(string NameSynonym, Stock stock)
   {
       name=NameSynonym;
       owner=stock
   }
   // [+ 'get' for 'name' and 'owner']
}

我知道我需要一个比较器,但之前从未使用它。我应该创建一个单独的类吗?像:

public class SynonymComparer : IComparer<Synonym>
{
   public int Compare(Synonym One, Synonym Two)
   { // Should I test if 'One == null'  or  'Two == null'  ???? 
       return String.Compare(One.Name, Two.Name, true); // Caseinsesitive
   }

}

我更喜欢有一个函数(或嵌套类[可能是单例?],如果需要)作为类同义词的PART而不是另一个(独立)类。这可能吗?

关于用法: 因为我之前从未使用过这种东西,我想我必须在类同义词中写一个Find(字符串NameSynonym)函数,但是我应该怎么做呢?

public class SynonymManager
{ 
    private HashSet<SynonymComparer<Synonym>> ListOfSynonyms;

    public SynonymManager()
    {
        ListOfSymnonyms = new HashSet<SynonymComparer<Synonym>>();
    }

    public void SomeFunction()
    { // Just a function to add 2 sysnonyms to 1 stock
        Stock stock = GetStock("General Motors");
        Synonym otherName = new Synonym("GM", stock);
        ListOfSynonyms.Add(otherName);
        Synonym otherName = new Synonym("Gen. Motors", stock);
        ListOfSynonyms.Add(otherName);
    }

    public Synonym Find(string NameSynomym)
    {
       return ListOfSynonyms.??????(NameSynonym);
    }
 }

在上面的代码中,我不知道如何实现'Find'方法。我该怎么做?

任何帮助将不胜感激 (PS如果我对如何实施它的想法完全错误,请告诉我如何实施)

3 个答案:

答案 0 :(得分:15)

HashSet不需要IComparer<T> - 它需要IEqualityComparer<T>,例如

public class SynonymComparer : IEqualityComparer<Synonym>      
{
   public bool Equals(Synonym one, Synonym two)
   {
        // Adjust according to requirements.
        return StringComparer.InvariantCultureIgnoreCase
                             .Equals(one.Name, two.Name);

   }

   public int GetHashCode(Synonym item)
   {
        return StringComparer.InvariantCultureIgnoreCase
                             .GetHashCode(item.Name);

   }
}

但是,您当前的代码只会编译,因为您创建了一组比较器而不是一组同义词

此外,我认为你根本不想要一套。在我看来,你想要一个字典或查找,以便你可以找到给定名称的同义词:

public class SynonymManager
{ 
    private readonly IDictionary<string, Synonym> synonyms = new
        Dictionary<string, Synonym>();

    private void Add(Synonym synonym)
    {
        // This will overwrite any existing synonym with the same name.
        synonyms[synonym.Name] = synonym;
    }

    public void SomeFunction()
    { 
        // Just a function to add 2 synonyms to 1 stock.
        Stock stock = GetStock("General Motors");
        Synonym otherName = new Synonym("GM", stock);
        Add(otherName);
        ListOfSynonyms.Add(otherName);
        otherName = new Synonym("Gen. Motors", stock);
        Add(otherName);
    }

    public Synonym Find(string nameSynonym)
    {
       // This will throw an exception if you don't have
       // a synonym of the right name.  Do you want that?
       return synonyms[nameSynonym];
    }
}

请注意,上面的代码中有一些问题,关于您希望它在各种情况下的行为方式。你需要完全 你想要它做什么。

编辑:如果您希望能够为单个同义词存储多个股票,那么有效地想要Lookup<string, Stock> - 但这是不可变的。你可能最好存储一个Dictionary<string, List<Stock>>;每个字符串的股票清单。

就不从Find抛出错误而言,您应该查看Dictionary.TryGetValue如果找不到密钥则不会抛出异常(并且还会返回密钥< em> 找到了);映射的值在out参数中“返回”。

答案 1 :(得分:1)

完全废弃Synonym类并将同义词列表设为Dictonary(或者,如果有这样的事情,HashDictionary),是不是更合理字符串?

(我对C#类型不太熟悉,但我希望这能传达一般的想法)

我推荐的答案(编辑,现在尊重案例):

    IDictionary<string, Stock>>  ListOfSynonyms = new Dictionary<string,Stock>>(); 
    IDictionary<string, string>> ListOfSynForms = new Dictionary<string,string>>(); 
    class Stock 
    {   
        ...
        Stock addSynonym(String syn) 
        {
            ListOfSynForms[syn.ToUpper()] = syn;
            return ListOfSynonyms[syn.ToUpper()] = this;
        }
        Array findSynonyms()
        {
            return ListOfSynonyms.findKeysFromValue(this).map(x => ListOfSynForms[x]);
        }
    }

    ...
    GetStock("General Motors").addSynonym('GM').addSynonym('Gen. Motors');
    ...
    try  
    {
        ... ListOfSynonyms[synonym].name ...
    }  
    catch (OutOfBounds e) 
    {
        ...
    } 
    ...
    // output everything that is synonymous to GM. This is mix of C# and Python
    ... GetStock('General Motors').findSynonyms()
    // test if there is a synonym
    if (input in ListOfSynonyms) 
    {
        ...
    }

答案 2 :(得分:0)

您始终可以使用LINQ进行查找:

public Synonym Find(string NameSynomym)
{
   return ListOfSynonyms.SingleOrDefault(x => x.Name == NameSynomym);
}

但是,您是否考虑使用词典,我相信它更适合提取单个成员,并且您仍然可以保证根据您选择的键没有重复项。

我不确定查找时间是否为SingleOrDefault,但我很确定它是线性的(O(n)),因此如果查找时间对您很重要,则Dictionary会为您提供O(1)查找时间