3

次のようなメモリ内の「テーブル」があります。

Favorite#  Name        Profession
---------  ----------  ------------------
3          Names.Adam  Profession.Baker
9          Names.Bob   Profession.Teacher
7          Names.Carl  Profession.Coder
7          Names.Dave  Profession.Miner
5          Names.Fred  Profession.Teacher

そして、私がやりたいことは、3 つのフィールドのいずれかを使用して、迅速かつ効率的なルックアップを行うことです。言い換えれば、私は欲しい:

  • myTable[3]そしてmyTable[Names.Adam]、そしてmyTable[Professions.Baker]すべてに戻る{3,Names.Adam,Profession.Baker}
  • myTable[Profession.Teacher]{9,Names.Bob,Profession.Teacher}と の両方を返し{5,Names.Fred,Profession.Teacher}ます。

テーブルは、ユーザーのアクションに従って実行時に作成され、データベース接続が保証されないセクションで使用されるため、データベースに格納できません。

現在、私は「単純に」(ハァッ!)これを3つのuber-Dictionariesを使用して保存し、それぞれが列(FavoriteNumber、Name、Profession)の1つを使用してキーを設定し、2つのDictionariesを保持するuber-Dictionariesの各値をキーにしています残りの列のそれぞれ (したがって、"Name" uber-dictionary の値は型Dictionary<FavoriteNumber,Profession[]>Dictionary<Profession, FavoriteNumber[]>

これには、2 つの辞書での 2 つの検索と、配列の別のトラバース (通常は 1 つまたは 2 つの要素を保持します) が必要です。

誰でもこれを行うためのより良い方法を提案できますか? テーブルが小さい (20 エントリ以下) 可能性が高いため、余分なメモリを消費することは気にしませんが、コードをより簡単に保守できるようにするために、CPU を少し犠牲にしても構わないと思っています...

4

5 に答える 5

6

20 行の場合は、リニア スキャンを使用するだけです。あらゆる点で最も効率的です。

より大きなセットの場合。hzere は、LINQToLookupと遅延インデックス作成を使用したアプローチです。

public enum Profession {
    Baker, Teacher, Coder, Miner
}
public class Record {
    public int FavoriteNumber {get;set;}
    public string Name {get;set;}
    public Profession Profession {get;set;}
}
class Table : Collection<Record>
{
    protected void Rebuild()
    {
        indexName = null;
        indexNumber = null;
        indexProfession = null;
    }
    protected override void ClearItems()
    {
        base.ClearItems();
        Rebuild();
    }
    protected override void InsertItem(int index, Record item)
    {
        base.InsertItem(index, item);
        Rebuild();
    }
    protected override void RemoveItem(int index)
    {
        base.RemoveItem(index);
        Rebuild();
    }
    protected override void SetItem(int index, Record item)
    {
        base.SetItem(index, item);
        Rebuild();
    }
    ILookup<int, Record> indexNumber;
    ILookup<string, Record> indexName;
    ILookup<Profession, Record> indexProfession;
    protected ILookup<int, Record> IndexNumber {
        get {
            if (indexNumber == null) indexNumber = this.ToLookup(x=>x.FavoriteNumber);
            return indexNumber;
        }
    }
    protected ILookup<string, Record> IndexName {
        get {
            if (indexName == null) indexName = this.ToLookup(x=>x.Name);
            return indexName;
        }
    }
    protected ILookup<Profession, Record> IndexProfession {
        get {
            if (indexProfession == null) indexProfession = this.ToLookup(x=>x.Profession);
            return indexProfession;
        }
    }
    public IEnumerable<Record> Find(int favoriteNumber) { return IndexNumber[favoriteNumber]; }
    public IEnumerable<Record> Find(string name) { return IndexName[name]; }
    public IEnumerable<Record> Find(Profession profession) { return IndexProfession[profession]; }
}
于 2009-02-05T13:46:58.487 に答える
5

これを行う方法は、独自のオブジェクトを作成することだと思います

public ICollection<Record> this[int] { get; }
public ICollection<Record> this[Profession] { get; }
public ICollection<Record> this[Names] { get; }

record は要素を保持するクラスです。

内部的には、リストを保持し、各インデクサーが必要なものを取得するために List.FindAll() を実行します。

于 2009-02-05T13:40:36.193 に答える
4

すぐに使用できるものはありません (おそらく DataTable を除く)。それにもかかわらず、それはあなたが持っているより簡単な方法で達成することができます:

データを保持するクラスを作成します。

class PersonData {
   public int FavoriteNumber;
   public string Name;
   public string Profession;
}

次に、同じ参照を指す 3 つの辞書を保持します。

PersonData personData = new PersonData();
Dictionary<int, PersonData> ...;
Dictionary<string, PersonData> ...;
Dictionary<string, PersonData> ...;

これらすべてを、実装の詳細を隠すファサード クラスにカプセル化することをお勧めします。

于 2009-02-05T13:44:04.000 に答える
1

バッキングとしてsqliteデータベースを使用できますか? sqlite を使用すると、メモリ内データベースを構築するオプションさえあります。

于 2009-02-05T13:40:49.873 に答える