HashSetにComparerを使用する方法
-
06-07-2019 - |
質問
ここで尋ねた別の質問の結果、オブジェクトに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']
}
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
}
}
別の(独立した)クラスではなく、同義語クラスのPARTである関数(または、必要に応じてネストされたクラス[シングルトンですか?])が望ましいです。これは可能ですか?
使用方法について: クラス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);
}
}
上記のコードでは、「Find」メソッドの実装方法がわかりません。どうすればいいですか?
ご協力いただければ幸いです (PS実装方法についての私の考えが完全に間違っている場合、私に知らせて実装方法を教えてください)
解決
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
を確認する必要があります(また、キーが found);マッピングされた値は<!> quot; returned <!> quot; outパラメーター。
他のヒント
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)
{
...
}
常にLINQを使用して検索を実行できます。
public Synonym Find(string NameSynomym)
{
return ListOfSynonyms.SingleOrDefault(x => x.Name == NameSynomym);
}
しかし、代わりに辞書を使用することを検討しました。単一のメンバーを抽出するのに適していると思います。選択したキーに基づいて重複がないことを保証できます。
検索時間がSingleOrDefaultであるかどうかはわかりませんが、線形(O(n))であると確信しているので、検索時間が重要な場合、辞書はO(1)検索時間を提供します。