没有字典的快速多键查找?

时间:2012-11-27 21:27:06

标签: c# linq search .net-4.0 lookup

我有一个Id映射缓存占用了太多内存。它用于存放一个对象的3种不同类型的Id的组合,并且从表中读取它们的映射,并缓存在6个不同的字典中,以便从任何1 Id类型快速查找/转换到另一个(性能是对我的申请很重要。)

我想将其重写为内存占用较少的内容,因此我确实实现了Id的整合列表,并使用linq / lambda表达式来提取我想要的值。它现在看起来像这样。

public struct IdMappings
{
     public int Id1;
     public int Id2;
     public int Id3;
}

//new cache    
private static List<IdMappings> AllIdMappings = null;

//current cache implementation
private static Dictionary<int, int> Id1ToId2 = null;
private static Dictionary<int, int> Id1ToId3 = null;
//etc.

public static void FillCache(DataSet data)
{
     foreach (DataRow r in data.Tables[0].Rows)
     {
          //fill list and/or dictionaries with id's
     }
}

示例查找将是:

public static int GetId2FromId1(int id1)
{
    return AllIdMappings.FirstOrDefault(m => m.Id1 == id1).Id2;
    //or
    return Id1ToId2[id1];
}

这就是我在减少内存使用方面所需要的,但是查找的性能因此受到影响,所以我看到了如何实现不同的东西。有没有办法做多索引键,或多键查找比迭代列表相对快?

4 个答案:

答案 0 :(得分:1)

是的,对列表进行排序并使用二进制搜索(List&lt;&gt;已在方法Find中为您实现此功能) 然后在O(logn)中完成维护排序列表和查找。

答案 1 :(得分:1)

一个潜在的性能改进可能是使用Hashset<IdMappings>而不是List<IdMappings>,但这主要有助于直接查找,而不是FirstOrDefault,或多或少,按顺序迭代列表。

如果您的查询全部来自ID1 - &gt; ID2和ID3方向,您可以使用Dictionary<int, Tuple<int, int>>作为键,这将消除当前词典中ID1的额外值。

无论如何,根据定义,缓存是查找速度的内存交易,所以我认为你不能大幅提高内存消耗。

答案 2 :(得分:1)

如果添加这三个词典:

private static Dictionary<int, IdMappings> Id1Lookup = null;
private static Dictionary<int, IdMappings> Id2Lookup = null;
private static Dictionary<int, IdMappings> Id3Lookup = null;

如果字典值是相同的引用,它应该使用最少的内存,但保留与原始实现相同的查找速度。

如果我正在考虑这个问题,那么这应该使用6个字典解决方案的一半内存,但是使用List<IdMappings>类型解决方案的两倍。

正如@SWeko指出的那样,IdMappings需要是class而不是struct才能确保使用引用指针而不是副本。

答案 3 :(得分:1)

可能你最好的办法是创建一个映射结构:

struct Mapping: IComparable<Mapping>
{
    private readonly int FromId;
    private readonly int ToId;
    public Mapping(int fid, int tid);
    // implement the IComparable.Compare method to compare FromId
}

然后,为每个索引创建一个List<Mapping>,并对列表进行排序。然后,您可以使用List.Find查找所需的项目。