Scala 查找范围内的缺失值
Scala find missing values in a range
对于给定的范围,例如
val range = (1 to 5).toArray
val ready = Array(2,4)
缺失值(未就绪)是
val missing = range.toSet diff ready.toSet
Set(5, 1, 3)
实际用例包括数以千计的范围实例,其中(可能)有数以千计的缺失或就绪值。 Scala 有没有更省时的方法?
diff
操作在 Scala 中实现为左 ope运行d 上的 foldLeft
,其中右 ope运行d 的每个元素都从左集合。假设左右 ope运行d 分别有 m
和 n
元素。
在 Array
或 Range
对象上调用 toSet
将 return 一个 HashTrieSet
,这是一个 HashSet
实现,因此,提供复杂度几乎 O(1)
的删除操作。因此,diff
操作的总体复杂度为 O(m)
.
现在考虑一种不同的方法,我们会发现这实际上非常好。还可以通过对两个 运行ges 进行排序然后以合并排序方式遍历它们一次以消除出现在两个 运行ges 中的所有元素来解决该问题。这会给你带来 O(max(m, n) * log(max(m, n)))
的复杂度,因为你必须对两个 运行ges.
进行排序
更新
我 运行 一些实验来研究是否可以通过使用可变哈希集而不是不可变哈希集来加快计算速度。如下表所示的结果取决于 range
和 ready
的大小比例。
如果 ready.size/range.size < 0.2
,使用不可变哈希集似乎更有效。高于此比率,可变哈希集优于不可变哈希集。
对于我的实验,我设置 range = (1 to n)
,其中 n
是 range
中的元素数。对于 ready
,我选择了 range
的 运行dom 子集,其中包含相应的元素数。我每个 运行 重复了 20 次并总结了用 System.currentTimeMillis()
.
计算的时间
range.size == 100000
+-----------+-----------+---------+
| Fraction | Immutable | Mutable |
+-----------+-----------+---------+
| 0.01 | 28 | 111 |
| 0.02 | 23 | 124 |
| 0.05 | 39 | 115 |
| 0.1 | 113 | 129 |
| 0.2 | 174 | 140 |
| 0.5 | 472 | 200 |
| 0.75 | 722 | 203 |
| 0.9 | 786 | 202 |
| 1.0 | 743 | 212 |
+-----------+-----------+---------+
range.size == 500000
+-----------+-----------+---------+
| Fraction | Immutable | Mutable |
+-----------+-----------+---------+
| 0.01 | 73 | 717 |
| 0.02 | 140 | 771 |
| 0.05 | 328 | 722 |
| 0.1 | 538 | 706 |
| 0.2 | 1053 | 836 |
| 0.5 | 2543 | 1149 |
| 0.75 | 3539 | 1260 |
| 0.9 | 4171 | 1305 |
| 1.0 | 4403 | 1522 |
+-----------+-----------+---------+
对于给定的范围,例如
val range = (1 to 5).toArray
val ready = Array(2,4)
缺失值(未就绪)是
val missing = range.toSet diff ready.toSet
Set(5, 1, 3)
实际用例包括数以千计的范围实例,其中(可能)有数以千计的缺失或就绪值。 Scala 有没有更省时的方法?
diff
操作在 Scala 中实现为左 ope运行d 上的 foldLeft
,其中右 ope运行d 的每个元素都从左集合。假设左右 ope运行d 分别有 m
和 n
元素。
在 Array
或 Range
对象上调用 toSet
将 return 一个 HashTrieSet
,这是一个 HashSet
实现,因此,提供复杂度几乎 O(1)
的删除操作。因此,diff
操作的总体复杂度为 O(m)
.
现在考虑一种不同的方法,我们会发现这实际上非常好。还可以通过对两个 运行ges 进行排序然后以合并排序方式遍历它们一次以消除出现在两个 运行ges 中的所有元素来解决该问题。这会给你带来 O(max(m, n) * log(max(m, n)))
的复杂度,因为你必须对两个 运行ges.
更新
我 运行 一些实验来研究是否可以通过使用可变哈希集而不是不可变哈希集来加快计算速度。如下表所示的结果取决于 range
和 ready
的大小比例。
如果 ready.size/range.size < 0.2
,使用不可变哈希集似乎更有效。高于此比率,可变哈希集优于不可变哈希集。
对于我的实验,我设置 range = (1 to n)
,其中 n
是 range
中的元素数。对于 ready
,我选择了 range
的 运行dom 子集,其中包含相应的元素数。我每个 运行 重复了 20 次并总结了用 System.currentTimeMillis()
.
range.size == 100000
+-----------+-----------+---------+
| Fraction | Immutable | Mutable |
+-----------+-----------+---------+
| 0.01 | 28 | 111 |
| 0.02 | 23 | 124 |
| 0.05 | 39 | 115 |
| 0.1 | 113 | 129 |
| 0.2 | 174 | 140 |
| 0.5 | 472 | 200 |
| 0.75 | 722 | 203 |
| 0.9 | 786 | 202 |
| 1.0 | 743 | 212 |
+-----------+-----------+---------+
range.size == 500000
+-----------+-----------+---------+
| Fraction | Immutable | Mutable |
+-----------+-----------+---------+
| 0.01 | 73 | 717 |
| 0.02 | 140 | 771 |
| 0.05 | 328 | 722 |
| 0.1 | 538 | 706 |
| 0.2 | 1053 | 836 |
| 0.5 | 2543 | 1149 |
| 0.75 | 3539 | 1260 |
| 0.9 | 4171 | 1305 |
| 1.0 | 4403 | 1522 |
+-----------+-----------+---------+