C# で値のペア (トリプルなど) を 1 つの値として使用する最良の方法は何ですか?
-
01-07-2019 - |
質問
つまり、値のタプルが必要です。
私の頭の中にある使用例:
Dictionary<Pair<string, int>, object>
または
Dictionary<Triple<string, int, int>, object>
ペアやトリプルなどの組み込みタイプはありますか?またはそれを実装する最良の方法は何ですか?
アップデート 回答にはいくつかの汎用タプルの実装が説明されていますが、辞書のキーとして使用されるタプルについては、ハッシュ コードの正しい計算をさらに検証する必要があります。詳細については別の記事で説明します 質問.
アップデート 2 辞書のキーとして値を使用する場合、その値は不変である必要があることも覚えておく価値があると思います。
解決
C#でタプルライブラリを実装しました。訪問 http://www.adventuresinsoftware.com/generics/ 「タプル」リンクをクリックします。
他のヒント
組み込みクラス
特定のケースでは、.net フレームワークは、利用できるタプルのようなクラスをすでに提供しています。
ペアとトリプル
ジェネリックSystem.Collections.Generic.KeyValuePairクラスはアドホック ペアの実装として使用できます。これは、一般的な辞書が内部で使用するクラスです。
あるいは、System.Collections.DictionaryEntry初歩的なペアとして機能し、Mscorlibで利用できるという利点がある構造。ただし、この構造は強く型付けされていないことです。
ペアとトリプルは、System.Web.UI.ペア そしてSystem.Web.UI.Triplet クラス。たとえこれらのクラスが システム.ウェブ アセンブリは、Winforms開発に完全に適している可能性があります。ただし、これらのクラスは強く入力されておらず、一般的なフレームワークやライブラリなど、一部のシナリオでは適切ではない場合があります。
高次タプル
高次のタプルの場合、自分のクラスを転がしていない場合、単純な解決策はないかもしれません。
をインストールしている場合は、F# 言語, を参照できます。 FSharp.Core.dll 一般的な不変のセットが含まれていますMicrosoft.Fsharp.Core.Tuple ジェネリックセクストゥルまでのクラス。ただし、無修正にもかかわらず、 FSharp.Code.dll再配布することができます。F#は研究言語であり、進行中の作業であるため、このソリューションは学術界でのみ興味深いものになる可能性があります。
独自のクラスを作成したくなく、F#ライブラリを参照する不快な場合、Valueメンバー自体がネストされたKeyValuePairであるように、一般的なKeyValuePairクラスを拡張することで、気の利いたトリックが1つ構成できます。
たとえば、次のコードは、トリプルを作成するためにKeyValuePairを活用する方法を示しています。
int id = 33;
string description = "This is a custom solution";
DateTime created = DateTime.Now;
KeyValuePair<int, KeyValuePair<string, DateTime>> triple =
new KeyValuePair<int, KeyValuePair<string, DateTime>>();
triple.Key = id;
triple.Value.Key = description;
triple.Value.Value = created;
これにより、必要に応じてクラスを任意のレベルに拡張できます。
KeyValuePair<KeyValuePair<KeyValuePair<string, string>, string>, string> quadruple =
new KeyValuePair<KeyValuePair<KeyValuePair<string, string>, string>, string>();
KeyValuePair<KeyValuePair<KeyValuePair<KeyValuePair<string, string>, string>, string>, string> quintuple =
new KeyValuePair<KeyValuePair<KeyValuePair<KeyValuePair<string, string>, string>, string>, string>();
自分でロールしてみよう
それ以外の場合は、自分のタプルクラスを転がすことに頼る必要があるかもしれませんが、これは難しくありません。
次のような単純な構造を作成できます。
struct Pair<T, R>
{
private T first_;
private R second_;
public T First
{
get { return first_; }
set { first_ = value; }
}
public R Second
{
get { return second_; }
set { second_ = value; }
}
}
フレームワークとライブラリ
この問題は以前に取り組んでおり、汎用フレームワークが存在しています。以下はそのようなフレームワークへのリンクです。
- タプルライブラリ によるマイケル・L・ペリー.
public struct Pair<T1, T2>
{
public T1 First;
public T2 Second;
}
public struct Triple<T1, T2, T3>
{
public T1 First;
public T2 Second;
public T3 Third;
}
2010 年に早送りすると、.NET 4.0 はサポートされるようになりました。 任意の n の n タプル. 。これらのタプルは、期待どおりに構造的等価性と比較を実装します。
通常は、値を含む独自の構造体を作成するだけです。多くの場合、もう少し読みやすくなります ;)
キー値ペア 独自のクラスを作成したくない場合に拡張するのに最適なクラスです。
int id = 33;
string description = "This is a custom solution";
DateTime created = DateTime.Now;
KeyValuePair<int, KeyValuePair<string, DateTime>> triple =
new KeyValuePair<int, KeyValuePair<string, DateTime>>();
triple.Key = id;
triple.Value.Key = description;
triple.Value.Value = created;
必要なだけレベルを拡張できます。
KeyValuePair<KeyValuePair<KeyValuePair<string, string>, string, string> quadruple =
new KeyValuePair<KeyValuePair<KeyValuePair<string, string>, string, string>();
注記:クラス トリプレット そして ペア の中に存在します システム.ウェブ-dll なので、ASP.NET 以外のソリューションにはあまり適していません。
独自のタプル クラスは比較的簡単に作成できます。厄介になる可能性があるのは、等価性とハッシュコードのオーバーライド (辞書で使用する場合に必須) だけです。
.Net 独自の KeyValuePair<TKey,TValue>
構造体には 比較的遅い等価メソッドとハッシュコードメソッド.
それが気にならないとしても、コードを理解するのが難しくなるという問題がまだあります。
public Tuple<int, string, int> GetSomething()
{
//do stuff to get your multi-value return
}
//then call it:
var retVal = GetSomething();
//problem is what does this mean?
retVal.Item1 / retVal.Item3;
//what are item 1 and 3?
これらのケースのほとんどでは、特定のレコード クラスを作成する方が簡単だと思います (少なくとも C#4 がこのコンパイラの魔法を実現するまでは)
class CustomRetVal {
int CurrentIndex { get; set; }
string Message { get; set; }
int CurrentTotal { get; set; }
}
var retVal = GetSomething();
//get % progress
retVal.CurrentIndex / retVal.CurrentTotal;
1 つの簡単な解決策はまだ言及されていません。単に使用することもできます List<T>
. 。内蔵されており、効率的で使いやすいです。確かに、最初は少し奇妙に見えますが、特に要素数が多い場合には、その機能は完璧に機能します。
NGenerics - 人気のある .Net アルゴリズムおよびデータ構造ライブラリが最近導入されました 不変 データ構造をセットに追加します。
最初に実装した不変のものは次のとおりです。 ペア そして タプル クラス。コードはテストで十分にカバーされており、非常にエレガントです。確認できます ここ. 。彼らは現在、他の不変の代替案に取り組んでおり、間もなく準備が整うはずです。
組み込みはありませんが、Pair<T,R> クラスを作成するのは簡単です。
そうです、System.Web.UI.Pair と System.Web.UI.Triplet があります (これには、Pair タイプの動作のためのオーバーロードされたクリエーターがあります!)
最初のケースでは、私は通常、
Dictionary<KeyValuePair<string, int>, object>
そのための組み込みクラスはありません。使用できます キー値ペア または独自の実装を展開します。
System.Collections.Generic.KeyValuePair をペアの実装として使用できます。
または、独自のものを実装することもできます。それらは難しくありません。
public class Triple<T, U, V>
{
public T First {get;set;}
public U Second {get;set;}
public V Third {get;set;}
}
もちろん、いつか Triple(string, int, int) が Triple(int, int, string) と互換性がないという問題に遭遇するかもしれません。代わりに System.Xml.Linq.XElement を使用するかもしれません。
F# には Tuple<> 型もあります。FSharp.Core.dll を参照する必要があるだけです。