代码之家  ›  专栏  ›  技术社区  ›  Shalom Craimer

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

  •  3
  • Shalom Craimer  · 技术社区  · 17 年前

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

    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} .

    Dictionary<FavoriteNumber,Profession[]> Dictionary<Profession, FavoriteNumber[]>

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

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

    5 回复  |  直到 17 年前
        1
  •  9
  •   Nick Berardi    17 年前

    但是,实际上并不是使用字典,但是如果您创建一个这样的类集合

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

    或者如果您更喜欢正常的LINQ语法

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

    每一个 selectedPeople 变量的类型将为 IEnumerable<Person> 您可以使用循环来搜索它们。

        2
  •  6
  •   Community Mohan Dere    9 年前

    对于20行,只需使用 linear scanning

    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]; }
    }
    
        3
  •  5
  •   plinth    17 年前

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

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

    其中record是一个保存元素的类。

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

        4
  •  4
  •   Ryan Emerle    17 年前

    没有现成的东西(可能除了数据表)。然而,它可以通过一种更简单的方式完成,即:

    创建一个类来保存数据:

    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> ...;
    

    我建议将所有这些封装到一个facade类中,以隐藏实现细节。

        5
  •  1
  •   chills42    17 年前

    你能用一个电话吗 sqlite 数据库作为后盾?使用sqlite,您甚至可以选择构建内存中的数据库。