14

私は、背骨の高さ全体に対して正規化された、各人間の椎骨の相対的な高さを表す一定のデータ構造を持っています。これは、人体計測研究などから導き出されたものです。

次のように、各タプルに (string)Name と (double)Value が含まれる、タプルのタプルとして Python で実装しました。

vertebral_heights = (
("C7",  0.0000000),
("T1",  0.0391914),
("T2",  0.0785479),
("T3",  0.1183993),
("T4",  0.1590759),
("T5",  0.2009076),
("T6",  0.2442244),
("T7",  0.2893564),
("T8",  0.3366337),
("T9",  0.3863861),
("T10", 0.4389439),
("T11", 0.4946370),
("T12", 0.5537954),
("L1",  0.6167492),
("L2",  0.6838284),
("L3",  0.7553630),
("L4",  0.8316832),
("L5",  0.9131188),
("S1",  1.0000000))

私が最初に考えたのは Dictionary を作成することでしたが、それにはクラスをコンテナーとして使用する必要があります。次に、列挙型のアイデアが頭に浮かびましたが、「列挙型は int 用です」を読み、double を持っています。それから Class と Struct がありますが、この時点まで私は完全に混乱しており、C# でこのようなことを行うベスト プラクティスについての現在の理解はまだ十分ではないと思います。

私の使用目的は、アプリケーション モデル (要素の数値部分) とユーザー モデル (要素の名前付きドメイン関連部分) の間に「マップ」を作成することです。

なにか提案を?

4

7 に答える 7

12

それは、値にどのようにアクセスしたいかによって異なります。

定数

たとえば、常に変数名を使用する場合:

double x = C7;

次に、次のように定数でいっぱいのクラスを使用できます。

public class VertebralHeights
{
    public const double C7 = 0.0000000d;
}

辞書

ただし、動的にアクセスする場合は、次のようになります。

string id = "C7";
double x = VertebralHeights[id];

Dictionary次に、次のように定義できるa を使用したほうがよいでしょう。

Dictionary<string, double> VertebralHeights = new Dictionary<string, double>()
{
    { "C7", 0.0000000d },
    { "T1", 0.0391914d}
}

両方の方法を一緒に持っています

値への厳密に型指定されたアクセスと動的アクセスの両方が必要な場合は、上記のメソッドのいずれかを拡張できます...

定数の場合(方法 1)、文字列を取る関数を追加します。

public double GetValue(string s)
{
    switch(s)
    {
        case "C7": return C7;
        case "T7": return T7;
        //...and so on...
        default: return 0;//or an alternate default
    }
}

(注:代わりにリフレクションを使用してこれを行うこともできます。これは、大量のリストを使用すると簡単になりますが、ここで追加のパフォーマンスを犠牲にする価値はありません)

Dictionaryアプローチ (方法 2) の場合、getter のコレクションを追加できます。

public double C7 { get { return VertebralHeights["C7"]; } }
于 2013-04-04T13:37:10.310 に答える
7

これが私の見解です-ディクショナリであるシングルトンクラスで作業してください:

public class Vertebrae : Dictionary<string, double>
{
    private Vertebrae() : base() { }


    private static Vertebrae _heights = new Vertebrae() {
        { "C7", 0.0 },
        { "T1", 0.0391914 },
        { "T2", 0.0785479 },
    };

    public static Vertebrae Heights { get { return _heights; } }

    public static double C7 { get { return Heights["C7"]; } }
    public static double T1 { get { return Heights["T1"]; } }
    public static double T2 { get { return Heights["T2"]; } }

    public static IEnumerable<double> All
    {
        get
        {
            return new List<double>() { C7, T1, T2 };
        }
    }
}

文字列名で Vertebrae にアクセスするには、次のようにします。

double c7 = Vertebrae.Heights["C7"];

シンボリック名で Vertebrae にアクセスするには、次のようにします。

double c7 = Vertebrae.C7;

椎骨を列挙するには、次のようにします。

foreach (double v in Vertebrae.All) { /* ... */ }

列挙子の場合、列挙子のように単一の静的リストを初期化できますが、静的リストと静的辞書のどちらが最初に初期化されるかわかりませんでした...

于 2013-04-04T13:52:34.693 に答える
6

列挙型として実行し、ブラックボックスの配管コードを前もって記述します。後悔しない!これが私がすることです:

double 値を各列挙型に関連付けることができるように、カスタム属性を記述します。

[AttributeUsage(AttributeTargets.Field, Inherited = false, AllowMultiple = false)]
internal sealed class VertebralHeightAsDoubleAttribute : Attribute
{
  public double HeightValue { get; private set; }

  public VertebralHeightAsDoubleAttribute(double heightValue_)
  {
    HeightValue = heightValue_;
  }
}   

生活を楽にするいくつかの拡張メソッド:

public static class VHAttribExtensions
{
  public static string ToNameString(this VertebralHeight target)
  {
    return Enum.GetName(typeof(VertebralHeight), target);
  }

  public static double ToHeightValue(this VertebralHeight target)
  {
    var fi = target.GetType().GetField(target.ToString());
    var attributes = (VertebralHeightAsDoubleAttribute[])fi.GetCustomAttributes(
      typeof(VertebralHeightAsDoubleAttribute), false);
    return attributes.Length > 0 ? attributes[0].HeightValue : double.NaN;
  }
}

カスタム属性を使用して列挙型を定義します。

public enum VertebralHeight
{
  [VertebralHeightAsDouble(0.0000000)]
  C7,
  [VertebralHeightAsDouble(0.0391914)]
  T1,
  [VertebralHeightAsDouble(0.0785479)]
  T2,
  [VertebralHeightAsDouble(0.1183993)]
  T3,
  [VertebralHeightAsDouble(0.1590759)]
  T4,
  [VertebralHeightAsDouble(0.2009076)]
  T5,
  [VertebralHeightAsDouble(0.2442244)]
  T6,
  [VertebralHeightAsDouble(0.2893564)]
  T7,
  [VertebralHeightAsDouble(0.3366337)]
  T8,
  [VertebralHeightAsDouble(0.3863861)]
  T9,
  [VertebralHeightAsDouble(0.4389439)]
  T10,
  [VertebralHeightAsDouble(0.4946370)]
  T11,
  [VertebralHeightAsDouble(0.5537954)]
  T12,
  [VertebralHeightAsDouble(0.6167492)]
  L1,
  [VertebralHeightAsDouble(0.6838284)]
  L2,
  [VertebralHeightAsDouble(0.7553630)]
  L3,
  [VertebralHeightAsDouble(0.8316832)]
  L4,
  [VertebralHeightAsDouble(0.9131188)]
  L5,
  [VertebralHeightAsDouble(1.0000000)]
  S1
}

試して:

static void Main(string[] args)
{
  var list = Enum.GetValues(typeof(VertebralHeight)).OfType<VertebralHeight>();
  foreach (var vh in list)
  {
    Console.WriteLine("{0} : {1}", vh.ToNameString(), vh.ToHeightValue());
  }
  Console.ReadLine();
}
于 2013-04-04T14:37:36.180 に答える
4

You could create a class:

public static class VertebralHeights
{
    public const double C7 = 0.0000000;
    public const double T1 = 0.0391914;
    //...
}

Access: double c7 = VertebralHeights.C7;

于 2013-04-04T13:34:43.560 に答える
2

これらのマッピングをどのように使用しているかによって異なります。名前によるルックアップ ( string) が関係している場合Dictionaryは、正しい選択です。しかし、それらの数値にわかりやすい名前を付けるだけでよい場合は、クラス内の定数 (おそらく静的) を使用します。

ディクショナリでキーと値の両方を列挙するのも簡単です。

var dict = new Dictionary<string, double>();

foreach (var key in dict.Keys)
{

}

foreach (var value in dict.Values)
{

}
于 2013-04-04T13:33:04.130 に答える
2

それらを列挙し、文字列で検索し、順序で並べ替えるには、3 つのデータを格納する必要があります。それらにアクセスする方法によって、それらを保管するのに最適な方法が変わります。

  1. List名前と値を含むタプルの。
    • これには、注文の主な利点があります。
    • 特定のアイテムを名前で取得するには、それを取得するための linq クエリが必要です。
  2. Dictionary名前のキー、および順序と値を含むタプルの値
    • これには、名前で項目をすばやく検索できるという主な利点があります
    • すべてのアイテムを特定の順序で取得するには、それらを並べ替えるための linq クエリが必要です。
    • 特定の順序を持​​たずにすべてのアイテムをループしたいだけであれば、Dictionaryそれが可能になります。
  3. 1 つのディクショナリと 1 つの値のリストを保持します。- ちょっと厄介です。最適化が過剰な可能性があります。
  4. 上記の実装のいずれかを継承し、実際の実装を隠して不足している機能を提供するカスタム コレクションを作成します。Linq は、短いリストで気になるほど遅くはありません。
于 2013-04-04T13:53:30.503 に答える
1

ジェネリック コレクションで単純なクラスを使用できます。次に、LINQ を使用すると、値を相互に簡単にマップできます。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace ConsoleApplication1
{

    class Vertebra {
        public string name { get; set; }
        public double height { get; set; }
    }

    class Program
    {
        static void Main(string[] args)
        {
            List<Vertebra> Vertebrae = new List<Vertebra>() {
                new Vertebra() {name = "C7", height = 0.0000000},
                new Vertebra() {name = "T1", height = 0.0391914}
                //etc
            };

            //find height by name:
            double H = Vertebrae.Single(v => v.name == "C7").height;

            //find name by height:
            string N = Vertebrae.Single(v => v.height == 0.0391914).name;

        }
    }

}
于 2013-04-04T13:54:44.667 に答える