我有一个包含项目的列表,其中每个项目都有多个属性(A,B,C,D),我想使用包含相同属性(A,B,C,D)的模板进行过滤。当我使用模板时,我想过滤所有与此模板匹配的项目。如果item等于模板或者是较小的子序列(0匹配任何项目),则假定匹配。
示例数据
A B C D
1 0 1 0
2 0 0 0
0 0 2 3
2 0 2 1
2 0 2 0
0 0 0 0
示例模板
[2 0 0 0] will filter {[0 0 0 0], [2 0 0 0]}
[2 0 2 0] will filter {[0 0 0 0], [2 0 0 0], [2 0 2 0]}
[2 0 2 1] will filter {[0 0 0 0], [2 0 2 1]}
[3 4 5 6] will filter {[0 0 0 0]}
[0 0 2 0] will filter {[0 0 0 0], [0 0 2 3], [2 0 2 1], [2 0 2 0]}
问题是,比较次数很容易达到300k,有时可能会变慢。我可以用什么技巧或结构来加快速度?有什么想法吗?
答案 0 :(得分:2)
假设有4个属性,我们将所有项目放入16个桶中。
第一个存储桶是属性没有零值的地方。从这里选择 - 基于密钥ABCD的简单查找。
第二个桶是属性A == 0的地方。从这里选择是在模板上查找值为BCD。
第三个桶是B == 0。从这里选择是在模板上查找值为ACD。
第四个是A == 0和B == 0.从这里选择是在模板上查找值为CD。
...
第十五是A,B,C == 0.查找在D上。
第十六是A,B,C,D == 0.这可以是布尔变量; - )
由于所有16个桶都是“完全匹配” - 您可以使用哈希表等方法进行搜索。
(此提案基于示例中的假设,它在prop值中为0,计为'匹配任意',而不是在模板中。) - 因为2000在您的示例中仅选择了一个值。如果语义在两个地方都是“任何”,那么显然是不正确的。
-
更新:推论:你可以有不超过2 ^ Nproperties匹配。
示例:
假设我们有3个属性A,B,C和以下四个项目:
itemX[A=1, B=0, C=1] ---> B is a wildcard, so bucketAC[11] = itemX
itemY[A=2, B=0, C=0] ---> B and C are wildcards, so bucketA[2] = itemY
itemZ[A=2, B=1, C=0] ---> C is a wildcard, so bucketAB[21] = itemZ
现在,键'abc'的查找如下(我也包括在右边的 桶的内容以便于阅读,'<<<意味着“积累”在这种情况下)
1.results << bucketA[a] | '2' => itemY[A=2, B=0, C=0]
2.results << bucketB[b]
3.results << bucketAB[ab] | '21' => itemZ[A=2, B=1, C=0]
4.results << bucketC[c]
5.results << bucketAC[ac] | '11' => itemX[A=1, B=0, C=1]
6.results << bucketBC[bc]
7.results << bucketABC[abc]
8.results << bucket_item_all_wildcards
因此,如果我们使用模板[2 0 0],我们只能从桶A中的密钥A = 2得到结果。 如果我们使用模板[2 1 0],那么我们从bucketA中得到密钥为A = 2的结果, 从桶AB中的AB = 21键 - 两个结果。
注意:当然,上面的密钥符号是相当无聊的,它只是假设“类似哈希表的访问,并且所述属性的串联是关键”。
如果允许您多次使用具有相同属性的项目,那么您需要在某些插槽中包含多个元素 - 然后,显然,您可以拥有更多元素 但是,除了2 ^ Nproperties搜索结果之外,您还可以跟踪最大重复次数,从而始终预测最坏情况下的最大项目数。
值得注意的是,如果物业数量增加,桶的总数可能很快就会爆炸(例如32个物业意味着最多超过40亿桶), 所以这个想法将不再适用于直接,并且还需要进一步 存储桶遍历/分配周围的优化。
答案 1 :(得分:1)
嵌套哈希映射怎么样?例如,项目“it”将存储为:
map(it.A)(it.B)(it.C).(it.D) = it
所以[2 0 2 0]可以搜索为:
map(2).keys.(2).keys