In C # ist es out-of-the-box-Weg, um eine 3-Wege-Lookup-Tabelle zu bauen?
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]
undmyTable[Names.Adam]
undmyTable[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 ...
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.