In C # ist es out-of-the-box-Weg, um eine 3-Wege-Lookup-Tabelle zu bauen?

StackOverflow https://stackoverflow.com/questions/515887

  •  21-08-2019
  •  | 
  •  

Frage

Ich habe eine in-memory "Tabelle" Das könnte etwa wie folgt aussieht:

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

Und was ich tun möchte, ist schnell und effizient Lookups, einer der drei Felder verwendet wird. Mit anderen Worten, ich will:

  • myTable[3] und myTable[Names.Adam] und myTable[Professions.Baker] auf alle Rückkehr {3,Names.Adam,Profession.Baker}
  • myTable[Profession.Teacher] sowohl {9,Names.Bob,Profession.Teacher} und {5,Names.Fred,Profession.Teacher} zurückzukehren.

Die Tabelle während der Laufzeit erstellt wird, nach den Aktionen des Benutzers und kann nicht in einer Datenbank gespeichert werden, da sie in den Abschnitten verwendet wird, in dem die Datenbankkonnektivität kann nicht garantiert werden.

Im Moment ist „einfach“ (hah!) Speichere diesen mit 3 uber-Wörterbücher, die jeweils verkeilte eine der Spalten mit (FavoriteNumber, Namen, Beruf), und jeden Wert in dem uber-Wörterbücher Halt 2 Wörterbücher, die selbst verkeilte mit jedem der verbleibenden Spalten (so die Werte in dem „Namen“ über-Wörterbuch sind von der Art Dictionary<FavoriteNumber,Profession[]> und Dictionary<Profession, FavoriteNumber[]>

Dies erfordert 2-Lookups in 2 Wörterbücher, und einen anderen Verfahrweg eines Arrays (die in der Regel 1 oder 2 Elemente enthält.)

Kann jemand empfehlen, einen besseren Weg, dies zu tun? Ich kümmere mich nicht zusätzliche Speicher zu verbringen, da die Tabelle wahrscheinlich ist, klein sein (nicht mehr als 20 Einträge), aber ich bin bereit, ein wenig CPU zu opfern es leichter wartbaren Code zu machen ...

War es hilfreich?

Lösung

Nicht wirklich aber mit einem Wörterbuch, aber wenn Sie eine Sammlung von Klassen wie folgt erstellen

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

Sie können LINQ verwenden, um die Sammlungen zu suchen.

IList<Person> people = /* my collection */;
var selectedPeople = people.Where(p => p.FavoriteNumber = 3);
var selectedPeople2 = people.Where(p => p.Name == "Bob");
var selectedPeople3 = people.Where(p => p.Profession = "Teacher");

oder wenn Sie es vorziehen, die normale LINQ-Syntax

var selectedPeople4 = from p in people
                      where p.Name == "Bob"
                      select p;

wird Jeder dieser selectedPeople Variablen wie IEnumerable<Person> werden eingegeben und Sie können eine Schleife verwenden, um durch sie suchen.

Andere Tipps

Für 20 Zeilen, verwenden Sie einfach linear Scannen -. es wird die effizienteste in jeder Hinsicht sein

Für größere Mengen; hzere ist ein Ansatz LINQ ToLookup und verzögerte Indizierung:

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]; }
}

Ich denke, die Art und Weise, dies zu tun, ist Ihr eigenes Objekt zu schreiben, das hat

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

, wo Datensatz ist eine Klasse, die Ihre Elemente enthält.

Intern halten Sie eine Liste und jede Indexer tut List.FindAll () zu bekommen, was Sie brauchen.

Nothing out-of-the-box (außer vielleicht ein Datatable). Dennoch kann es in einer einfacheren Art und Weise erreicht werden, dass das, was du hast:

Erstellen Sie eine Klasse, die Daten zu halten:

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

Dann halten Sie 3 Wörterbücher, die mit dem gleichen Bezugspunkt:

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

Ich würde empfehlen, dies alles in eine Fassadenklasse Verkapselung, die die Details der Implementierung versteckt.

Könnten verwenden Sie eine SQLite Datenbank als Träger? Mit SQLite haben Sie auch die Möglichkeit, den Aufbau einer In-Memory-db.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top