用于快速过滤的.net集合(已排序集合)

时间:2013-10-04 18:31:47

标签: c# sorting collections c5

在分析一个非常慢的方法时,我发现滞后是搜索和过滤集合。

该方法执行以下操作(按顺序)。根据剖析器,80%的时间花在步骤1-3上。

  1. 从文件中读取已排序的集合,并使用Protobuf-net(v2)
  2. 进行反序列化
  3. 从已排序的集合中,根据开始和结束整数(名称.RangeFromTo()
  4. 进行过滤
  5. 从相同的排序集合中,获取集合的下一个元素(名称。Right()
  6. 执行一些任务......
  7. 对于给定范围的

    .RangeFromTo()过滤器,例如:

    [3,7,9,12].RangeFromTo(2,9) -> [3,7,9]
    [3,7,9,12].RangeFromTo(2,8) -> [3,7]
    [3,7,9,12].RangeFromTo(7,13) -> [7,9,12]
    [3,7,9,12].RangeFromTo(13,14) -> [ ]
    

    .Right()在集合中找到一个元素,并在列表中为您提供下一个元素。如果元素不存在,它会为您提供最接近右边的元素。例如:

    [3,7,9,12].Right(0) -> 3
    [3,7,9,12].Right(3) -> 7
    [3,7,9,12].Right(4) -> 7
    [3,7,9,12].Right(12) -> null
    

    目前,该集合正在使用C5中的SortedArrayhttps://github.com/sestoft/C5/)。我可以使用更合适的系列吗?

    注意: 步骤1.占用总时间的约30%。如果我改用List,那么protobuf实际上减少了40%的反序列化时间!我想当插入到SortedArray时,集合不知道数据已经排序并且正在进行大量的工作。理想的集合(如果存在)也应该能够绕过它。

    修改 为了澄清,列表大约1000-5000,有90k不同的集合!有问题的方法需要在内存中加载所有集合以执行某些业务任务。

    编辑2: 我在这里添加了一些示例基准:

    https://github.com/cchanpromys/so_19188345

    它将来自C5的SortedArray与来自.Net的SortedSet进行比较。到目前为止,结果如下:

    C5 sorted array deserialize took 904
    Sorted set deserialize took 1040
    C5 sorted array .Right() took 5
    Sorted set .Right() took 798    <--- Not sure what happened here...
    C5 sorted array .RangeFromTo() took 217
    Sorted set .RangeFromTo() took 140
    

    编辑3 这超出了我的预期,但我最终得到了一个列表的自定义实现。

    我遇到的问题是SortedArray的Find操作(通常)需要O(Log(N)),而我希望它是O(1)操作。

    此外,列表按性质排序,您永远不会添加到列表的中间。

    所以我最终实现了一个具有内部索引器数组的列表,例如:

    例如:

    indexer: [0,0,0,0,1,1,1,1,2,2]
    list: [3,7,9]
    

    因此.Right(3)list[indexer[3]++]

    可以找到代码here

    很难相信这种类型的列表尚未在互联网上的某个地方实现。如果可能的话,我想使用一个库,所以我不必管理我自己的列表。

    互联网上是否存在此类实施?

1 个答案:

答案 0 :(得分:0)

如果您的阵列足够小(可能低于10-20个元素),那么简单的线性搜索很可能足够好(List在测量中表现得更快),你可以使用Where / TakeWhile剪切范围:

  (new[]{3,7,9,12}).Where(i => i>= 2).TakeWhile(i => i <= 9)