Как использовать Comparer для HashSet - PullRequest
6 голосов
/ 21 июня 2009

В результате другого вопроса, который я задал здесь, я хочу использовать 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 вместо другого (независимого) класса. Это возможно?

Об использовании: Поскольку я никогда не использовал подобные вещи раньше, я предполагал, что должен написать функцию Find (string NameSynonym) внутри класса Synonym, но как мне это сделать?

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 Если мои идеи о том, как это должно быть реализовано, совершенно неверны, дайте мне знать и расскажите, как это осуществить)

Ответы [ 3 ]

15 голосов
/ 21 июня 2009

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, который не выдает исключение, если ключ не найден (и также возвращает, был ли ключ был найдено); сопоставленное значение «возвращается» в выходном параметре.

1 голос
/ 21 июня 2009

Разве не разумнее полностью исключить класс 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) 
    {
        ...
    }
0 голосов
/ 21 июня 2009

Вы всегда можете использовать LINQ для поиска:

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

Но если вы решили использовать словарь вместо этого, я считаю, что он лучше подходит для извлечения отдельных членов, и вы все равно можете гарантировать, что не будет дубликатов, основанных на выбранном вами ключе.

Я не уверен, что время поиска относится к SingleOrDefault, но я уверен, что оно линейное (O (n)), поэтому, если время поиска важно для вас, словарь предоставит вам время поиска O (1) .

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...