C# 如何将比较器用于 HashSet

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/1023424/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-06 05:44:40  来源:igfitidea点击:

How to use Comparer for a HashSet

c#templatesdictionaryhashset

提问by SoftwareTester

As a result of another question I asked here I want to use a HashSet for my objects

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

I will create objects containing a string and a reference to its owner.

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

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

I understand I need a comparer , but never used it before. Should I create a separate class? like:

我知道我需要一个 comparer ,但以前从未使用过它。我应该创建一个单独的类吗?喜欢:

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
   }

}

}

I prefer to have a function (or nested class [maybe a singleton?] if required) being PART of class Synonym instead of another (independent) class. Is this possible?

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

About usage: As i never used this kind of thing before I suppose I must write a Find(string NameSynonym) function inside class Synonym, but how should I do that?

关于用法:因为在我想我必须在类 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);
    }
 }

In the code above I don't know how to implement the 'Find' method. How should i do that?

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

Any help will be appreciated (PS If my ideas about how it should be implemented are completely wrong let me know and tell me how to implement)

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

采纳答案by Jon Skeet

A HashSet doesn't need a IComparer<T>- it needs an IEqualityComparer<T>, such as

HashSet 不需要 a 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);

   }
}

However, your current code only compiles because you're creating a set of comparersrather than a set of synonyms.

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

Furthermore, I don't think you really want a set at all. It seems to me that you want a dictionary or a lookup so that you can find the synonyms for a given 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];
    }
}

Note that there are some questions in the code above, about how you want it to behave in various cases. You need to work out exactlywhat you want it to do.

请注意,上面的代码中有一些关于您希望它在各种情况下如何表现的问题。你需要找出究竟你想要它做的事情。

EDIT: If you want to be able to store multiple stocks for a single synonym, you effectivelywant a Lookup<string, Stock>- but that's immutable. You're probably best storing a Dictionary<string, List<Stock>>; a list of stocks for each string.

编辑:如果您希望能够为一个同义词存储多个股票,您实际上需要一个Lookup<string, Stock>- 但这是不可变的。你可能最好存储一个Dictionary<string, List<Stock>>; 每个字符串的股票列表。

In terms of not throwing an error from Find, you should look at Dictionary.TryGetValuewhich doesn't throw an exception if the key isn't found (and also returns whether or not the key wasfound); the mapped value is "returned" in an out parameter.

在不引发错误的方面Find,你应该看看Dictionary.TryGetValue不抛出一个异常关键是没有找到(和返回键是否找到); 映射值在输出参数中“返回”。

回答by ilya n.

Wouldn't it be more reasonable to scrap the Synonymclass entirely and have list of synonyms to be a Dictonary(or, if there is such a thing, HashDictionary) of strings?

完全取消Synonym该类并将同义词列表作为一个Dictonary(或者,如果有这样的事情,HashDictionary)字符串不是更合理吗?

(I'm not very familiar with C# types, but I hope this conveys general idea)

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

The answer I recommend (edited, now respects the case):

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

    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) 
    {
        ...
    }

回答by Egil Hansen

You can always use LINQ to do the lookup:

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

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

But, have you considered using a Dictionary instead, I believe it is better suited for extracting single members, and you can still guarantee that there are no duplicates based on the key you choose.

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

I am not sure that lookup time is of SingleOrDefault, but I am pretty sure it is linear (O(n)), so if lookup time is important to you, a Dictionary will provide you with O(1) lookup time.

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