【问题标题】:How to use Comparer for a HashSet如何将比较器用于 HashSet
【发布时间】:2010-11-04 15:17:50
【问题描述】:

由于我在这里提出的另一个问题,我想为我的对象使用 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
   }

}

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

关于使用: 因为我之前从未使用过这种东西,所以我想我必须在 Synonym 类中编写一个 Find(string 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);
    }
 }

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

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

【问题讨论】:

  • 我能不能再改进一下我的回答?

标签: c# templates dictionary hashset


【解决方案1】:

HashSet 不需要IComparer&lt;T&gt; - 它需要IEqualityComparer&lt;T&gt;,例如

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&lt;string, Stock&gt; - 但这是不可变的。您可能最好存储Dictionary&lt;string, List&lt;Stock&gt;&gt;;每个字符串的股票列表。

关于不从Find 引发错误,您应该查看Dictionary.TryGetValue,如果找不到密钥,它不会引发异常(并且还会返回密钥是否存在 找到);映射的值在 out 参数中“返回”。

【讨论】:

  • 假设他只需要一本字典,(我的回答也是如此),我想知道字典是如何实现的。有没有像 HashDictionary 这样的东西(它在内部使用 HashSet 来保存键,然后使用标准字典进行查找)?
  • 一开始我定义了一个有名字的股票(这将是那个特定股票的第一个同义词)。然后,用户可能会为特定股票提供自己的同义词(将添加到字典中),但也可能是在读取文件时会找到一个(或多个)同义词(即安全性定义为它的 ISIN 但 [几乎] 每个显示股票价值的网站都会使用不同的名称,因此所有这些不同的名称都必须链接到相同的证券 (=ISIN)。我不想在 Find 中抛出异常,但是需要知道同义词是否存在及其库存
  • @ilya: Dictionary 一直使用哈希表方法——但它内部不使用 HashSet。基本上这两种类型都使用相同的概念(散列),但它们提供不同的接口 - 集合仅具有项目是否在集合中的概念,而字典将键映射到值。您可以通过忽略值轻松实现给定字典的 HashSet - 从 HashSet 构建字典更难。
  • @Jon Skeet:这可能很愚蠢,但我不知道 C# 中设置了什么(如果你回答,请在stackoverflow.com/questions/1023697/… 做)。
【解决方案2】:

完全废弃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) 
    {
        ...
    }

【讨论】:

  • 我需要能够找出与每个特定同义词相关联的 Stock(当然在这个例子中没有显示,但实际上它确实显示了)
  • 当然,这就是为什么我在两个示例中都保留字典 ListOfSynonims 的原因。要从同义词中查找库存,请编写“ListOfSynonims[synonim]”。
  • 如你所见,这正是你想要的,但你写的不是 .?????(同义词) :)
  • 好的,我看到使用字典将避免创建另一个类(和对象),因为字典本身将存储 'syn' 和 'this' (= stock object) 之间的关系。显然会有/可能有几个字符串(同义词)指代同一只股票。但我想知道字典是否会处理区分大小写(当然我可以用 'syn.ToUpper()' 替换 'syn' 。我想 getSynonyms 方法是为了以防万一我想检索所有同义词
  • 我对 C++ 中的 Dictionary 类不是很熟悉。但是,总是将单词添加到字典中是最简单的。好吧,无论如何你都知道。是的,getSynonims 可能是您根本不需要的东西,这意味着您以您需要的简单结构结束。
【解决方案3】:

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

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

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

我不确定查找时间是 SingleOrDefault,但我很确定它是线性的 (O(n)),所以如果查找时间对您很重要,字典将为您提供 O(1) 查找时间.

【讨论】:

  • 第一:这不需要比较器???第二:这个 Find 是 Synonym 的成员函数。是必需的吗?那个“x”呢?
  • SingleOrDefault 是 HashSet 实现的 IEnumerable 上的扩展方法。这允许您使用 SingleOrDefault(或仅 Single)来查找与名称匹配的单个元素。您可以考虑将“x => x.Name == NameSynomym”作为您的比较器。它只是统计它需要一个 x (在您的情况下,这是 ListOfSynonyms 的同义词),如果 x.Name == NameSynomym 为真,它会将 x 返回给您。如果没有找到任何匹配项,它将返回 null。
  • 但是如果多个元素具有指定条件,则会抛出异常!
猜你喜欢
  • 1970-01-01
  • 2012-02-15
  • 1970-01-01
  • 1970-01-01
  • 2010-11-14
  • 1970-01-01
  • 1970-01-01
  • 2022-11-10
  • 1970-01-01
相关资源
最近更新 更多