3

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

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}

该表是在运行时根据用户的操作构建的,并且不能存储在数据库中,因为它用于无法保证数据库连接性的部分。

现在,我“简单地”(哈哈!)使用 3 个 uber-Dictionaries 存储它,每个使用列(FavoriteNumber,Name,Profession)之一键控,并且 uber-Dictionaries 中的每个值都包含 2 个本身键控的字典剩余的每一列(因此“名称”超级词典中的值属于类型Dictionary<FavoriteNumber,Profession[]>Dictionary<Profession, FavoriteNumber[]>

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

谁能建议一个更好的方法来做到这一点?我不介意花费额外的内存,因为该表可能很小(不超过 20 个条目),但我愿意牺牲一点 CPU 以使其更易于维护代码......

4

5 回答 5

9

但是不是真的使用字典,但是如果您创建这样的类的集合

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>,您可以使用循环来搜索它们。

于 2009-02-05T13:38:46.290 回答
6

对于 20 行,只需使用线性扫描- 它在各个方面都是最有效的。

对于较大的套装;hzere 是一种使用 LINQToLookup和延迟索引的方法:

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]; }
}
于 2009-02-05T13:46:58.487 回答
5

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

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

其中记录是一个包含您的元素的类。

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

于 2009-02-05T13:40:36.193 回答
4

没有开箱即用的东西(可能是 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> ...;

我建议将所有这些封装到一个隐藏实现细节的外观类中。

于 2009-02-05T13:44:04.000 回答
1

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

于 2009-02-05T13:40:49.873 回答