在C#中,是否有现成的方法来构建三向查找表?

在C#中,是否有现成的方法来构建三向查找表?,c#,lookup,C#,Lookup,我有一个内存中的“表”,可能看起来像这样: Favorite# Name Profession --------- ---------- ------------------ 3 Names.Adam Profession.Baker 9 Names.Bob Profession.Teacher 7 Names.Carl Profession.Coder 7 Names.Dave Profess

我有一个内存中的“表”,可能看起来像这样:

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,professione.Baker}
  • myTable[Profession.Teacher]
    返回
    {9,Names.Bob,Profession.Teacher}
    {5,Names.Fred,Profession.Teacher}
该表是在运行时根据用户的操作生成的,不能存储在数据库中,因为它用于无法保证数据库连接的部分

现在,我使用3个uber字典“简单”(哈!)存储它,每个字典使用一个列(FavoriteNumber、Name、Profession)键入,uber字典中的每个值包含2个字典,它们自己用其余的列键入(因此“Name”中的值)uber字典属于
字典
字典

这需要在2个字典中进行2次查找,并对数组进行另一次遍历(通常包含1或2个元素)


有人能提出更好的方法吗?我不介意花费额外的内存,因为表可能很小(不超过20个条目),但我愿意牺牲一点CPU,使其更易于维护代码…

实际上不需要使用字典,但如果您创建这样的类集合

class Person {
    public int FavoriteNumber;
    public string Name;
    public string Profession;
}
您可以使用LINQ搜索集合

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");

每个
selectedPeople
变量都将被输入为
IEnumerable
,您可以使用循环来搜索它们。

我认为这样做的方法是编写您自己的

public ICollection<Record> this[int] { get; }
public ICollection<Record> this[Profession] { get; }
public ICollection<Record> this[Names] { get; }
public ICollection this[int]{get;}
公共ICollection此[职业]{get;}
公共ICollection此[Names]{get;}
其中record是一个保存元素的类

在内部,您保留一个列表,每个索引器都执行List.FindAll()来获取您需要的内容。

您可以使用数据库作为支持吗?使用sqlite,您甚至可以选择构建内存中的数据库。

没有现成的东西(可能除了一个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> ...;
PersonData PersonData=新PersonData();
字典。。。;
字典。。。;
字典。。。;
我建议将所有这些封装到一个facade类中,该类隐藏了实现细节。

对于20行,只需使用-它将在各个方面都是最有效的

对于较大的集合,hzere的方法使用LINQ的
ToLookup
和延迟索引:

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]; }
}
公共枚举职业{
面包师、教师、编码员、矿工
}
公开课记录{
public int-FavoriteNumber{get;set;}
公共字符串名称{get;set;}
公共职业职业{get;set;}
}
类表:集合
{
受保护的无效重新生成()
{
indexName=null;
indexNumber=null;
indexProfession=null;
}
受保护的覆盖无效ClearItems()
{
base.ClearItems();
重建();
}
受保护的覆盖无效插入项(整数索引,记录项)
{
基本插入项(索引,项目);
重建();
}
受保护的覆盖void removietem(int索引)
{
基本删除项(索引);
重建();
}
受保护的覆盖无效集合项(整数索引,记录项)
{
base.SetItem(索引,项);
重建();
}
ILookup索引编号;
ILookup索引名;
我想从事非专业工作;
受保护的ILookup索引编号{
得到{
如果(indexNumber==null)indexNumber=this.ToLookup(x=>x.FavoriteNumber);
返回索引编号;
}
}
受保护的ILookup索引名{
得到{
如果(indexName==null)indexName=this.ToLookup(x=>x.Name);
返回indexName;
}
}
受保护的ILookup非专业{
得到{
如果(indexProfession==null)indexProfession=this.ToLookup(x=>x.Profession);
回归非专业化;
}
}
public IEnumerable Find(int-favoriteNumber){return IndexNumber[favoriteNumber];}
public IEnumerable Find(字符串名){return IndexName[name];}
公共IEnumerable Find(Profession){return IndexProfession[Profession];}
}

你的第一个例子不应该是myTable[3]?对于20行,只需使用线性搜索-它会比字典更快。这样做的缺点是,你暴露了你的表示,如果IList不够好,重构起来会很痛苦。因为它是IList,它还可以根据OP的请求按索引进行查找。例如,people[0]={3,“Adam”,“贝克”}etc@plinthIList只是一个集合的持有者,实际上,在处理LINQ时,您需要IList的哪一部分是IEnumerable。其他所有内容都由LINQ处理,它提供了更大的查询可能性。@Luke您还可以通过调用.ToArray(),.ToList()将其更改为任何类型这是最好的答案,不幸的是,我被禁止在这个项目上使用C#3.0结构。(不,我不知道为什么。)因为OP状态为20行,这是最有效的选择,从各个方面来说,你可能是对的,线性扫描是这样一个小集合的最佳方式,因为我的最佳度量也包括“维护代码所花费的时间”。
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]; }
}