How to use Comparer for HashSet

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

I will create objects containing a string and a link 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 comparator, but he never used it before. Should I create a separate class? as:

 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 a nested class [maybe a singleton?] If required) that is PART of the class Synonym instead of another (independent) class. Is it possible?

About usage: Since I have never used this kind of thing before, I suppose, I should write the Find (string NameSynonym) function inside the Synonym class, but how do I do this?

 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 above code, I don’t know how to implement the Find method. How can I do it?

Any help would be appreciated (PS If my ideas on how this should be implemented are completely wrong, let me know and tell me how to implement this)

+5
source share
3 answers

HashSet does not require IComparer<T> - it needs IEqualityComparer<T> , for example

 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 are creating a set of comparators, not a set of synonyms.

Also, I don't think you really need a kit. It seems to me that you need a dictionary or search so that you can find synonyms for this 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]; } } 

Please note that in the above code there are some questions about how you want it to behave in different cases. You need to pinpoint what you want.

EDIT: if you want to store multiple stocks for one synonym, you really want Lookup<string, Stock> , but that is immutable. You should probably store Dictionary<string, List<Stock>> ; stock list for each row.

In terms of not throwing an error from Find you should look at Dictionary.TryGetValue , which does not throw an exception if the key is not found (and also returns if the key was found); the displayed value is "returned" in the output parameter.

+13
source

Wouldn't it be wiser to completely abandon the Synonym class and have a list of synonyms like Dictonary (or, if there is such a thing, HashDictionary ) lines?

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

The answer I recommend (edited, now relevant):

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

You can always use LINQ to search:

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

But you thought you were using a dictionary instead, I believe that it is better for extracting individual members, and you can still guarantee that there are no duplicates based on the selected key.

I'm not sure if the search time is SingleOrDefault, but I'm sure it is linear (O (n)), so if the search time is important to you, the dictionary will give you O (1) search time.

0
source

All Articles