ConcurrentDictionary<TKey, TValue> - 如何高效地“从键 K 开始获取 N 个元素”?

Fil*_*dor 5 c# dictionary

情况如下:

  • 我有一个ConcurrentDictionary<TId, TItem>
  • 为了高效分页,我们希望实现“获取 N 个项目,从键 K 开始”

我想出的最好方法是:

public IEnumerable<TItem> Get( TId fromKey, int count )
{
    // parameter validation left out for brevity

    return items.Keys // KeyCollection of the Dictionary, please assume 'items' is a class field
             .SkipWhile(key => key != fromKey)
             .Take(count)
             .Select(x => items[x])
             .ToList();
}
Run Code Online (Sandbox Code Playgroud)

但这种感觉确实不对。特别是因为我们明确不想“SkipWhile”。如果我可以跳过,我可以只.Skip(n).Take(m)对值进行操作,但这显然是不想要的。我的要求是:从键 K 开始,返回 N 个元素。

也许我想得太多了,我应该反击。但我有一种感觉,我在这里错过了一些东西。

所以我的问题是:有没有办法做到这一点,而不必在字典的 KeyCollection 或 ValueCollection 中“跳过”?


编辑

  • ConcurrentDictionary<TKey, TVaue>是我接手任务的地方。它不是刻在石头上以保持该类型的。
  • 顺序没有优先级。老年人和 PO 认为它“足够好”,可以遵循 KeyCollection 的任何顺序结果。但请记住这一点,以寻找未来可能的功能请求。

Kit*_*Kit 3

嗯,根据评论,这听起来有点奇怪,但我确信有原因你不能深入了解背景故事或细节。

我会这么说。

SkipWhile(key => key != fromKey)实际上,您可以找到一把钥匙,以便在“之后”找到更多钥匙,因此从这个意义上说,您拥有的东西是正确的。如果你的密钥空间不是大得离谱,那似乎就足够了。

也就是说,不同的数据结构会更好。例如,您可以实现字典 + 数组或字典 + 链表的并发版本,它允许您访问 O(1) 中的键,然后访问 a 内的 O(m) 中的后续元素lock(您甚至可以使其成为A ReaderWriterLockSlim)。如果O(n)仅使用ConcurrentDictionary.

插入会有点奇怪,因为您必须对之前之后的含义保持某种任意的概念。例如,在字典 + 数组的情况下,您可以将键“foo”添加到字典和数组中的槽 0 中。键“bar”将像往常一样进入字典,并进入插槽 1,依此类推。

哦 - 你的字典条目必须指向数组或链表中的位置才能获得 O(m) 以及数据本身。而且,如果您想删除重复数据,数组/列表可以指向字典条目,而不仅仅是保存数据。

当项目被删除时,数组会给你留下漏洞!这就是链接列表会有所帮助的地方。为了维持“顺序”(宽松地使用这个术语),写入会慢一些,因为您正在访问两个底层数据结构。