在C#中,有没有开箱即用的方法来构建3向查找表?

Sha*_*mer 3 c# lookup

我有一个内存"表",可能看起来像这样:

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
Run Code Online (Sandbox Code Playgroud)

我想做的是使用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个超级字典存储它,每个字符使用其中一个列(FavoriteNumber,Name,Profession)键入,并且uber-Dictionaries中的每个值包含2个字典,这些字典本身都是键入的每个剩余的列(因此"名称"超级字典中的值属于类型Dictionary<FavoriteNumber,Profession[]>Dictionary<Profession, FavoriteNumber[]>

这需要2个字典中的2个查找,以及数组的另一个遍历(通常包含1或2个元素.)

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

Nic*_*rdi 9

然而,并不是真的使用字典,但是如果你创建这样的类的集合

class Person {
    public int FavoriteNumber;
    public string Name;
    public string Profession;
}
Run Code Online (Sandbox Code Playgroud)

您可以使用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");
Run Code Online (Sandbox Code Playgroud)

或者如果您更喜欢普通的LINQ语法

var selectedPeople4 = from p in people
                      where p.Name == "Bob"
                      select p;
Run Code Online (Sandbox Code Playgroud)

这些selectedPeople变量中的每一个都将被输入IEnumerable<Person>,您可以使用循环来搜索它们.


Mar*_*ell 6

对于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]; }
}
Run Code Online (Sandbox Code Playgroud)


pli*_*nth 5

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

public ICollection<Record> this[int] { get; }
public ICollection<Record> this[Profession] { get; }
public ICollection<Record> this[Names] { get; }
Run Code Online (Sandbox Code Playgroud)

其中record是一个包含元素的类.

在内部,你保留一个List,每个索引器都有List.FindAll()来获得你需要的东西.