如何在“HashTable中的键视图”和nim中的HashSet之间执行set-difference操作?
概念:
import tables, sets, sequtils
var a = initTable[int, string]()
var b: HashSet[int]
b.init(4)
a[0] = "a"
a[1] = "b"
b.incl(0)
b.incl(1)
b.incl(2)
b.incl(3)
var diff = b - toset(toseq(a.keys))
echo diff # {2, 3}
这是有效的(并且很难做到,编译器会给出误导性的消息。例如,尝试删除上面的toseq
,它说“未声明的字段:'键'”哇。 )
但是,当然,这是无用的,我将循环并在这种状态下自己做出改变
我们需要的是一个无分配方法,它直接与hashset / hashtable一起工作。例如:
var diff = b - a.keys
或者最坏的情况:
var diff = b - HashSetView(a.keys)
这将创建一个适配器对象,形成键迭代器以适应-
过程,该过程可能只接受集合。
可能?
编辑:
事实上,我只记得我头脑中浮现的东西,它是boost::transform_iterator
概念
Initialize a container with iterator range of container with different type
这就是为什么在C ++的设计中,每个算法/ stdlib函数都需要一个范围(2个iters),而不是尽可能多地引用容器本身。这是鸭子打字的一种形式
第二个想法我的问题似乎是设置差异过程不适用于迭代器。
答案 0 :(得分:3)
你正在寻找的东西似乎可以通过Nim的元编程和UFCS设施得到很好的解决:
proc `-`[K, V](a: HashSet[K], b: Table[K, V]): HashSet[K] =
result = a
for k in b.keys:
result.excl k
var diff = b - a
正如您所怀疑的那样,这比分配一个全新的序列只是为了丢弃一个集合更有效。似乎没有一种内置的方法来完成你想要完成的任务。
undeclared field: "keys"
错误在keys
为an inline iterator且不是字段的上下文中有意义,但是此错误消息肯定可以提供更多信息。如果你想使用任意迭代器,你似乎必须wrap it in a closure,尽管它可能会带来一些开销。
使用nim-iterutils包中的toClosure
:
template toClosure*(i): auto =
## Wrap an inline iterator in a first-class closure iterator.
iterator j: type(i) {.closure.} =
for x in i:
yield x
j
proc `-`[K](a: HashSet[K], b: iterator): HashSet[K] =
result = a
for k in b():
result.excl k
var diff = b - toClosure(a.keys)
如果你不需要完整的结果,那么产生差异可能会有更大的表现。
iterator without_keys[K, V](a: HashSet[K], b: Table[K, V]): K =
for k in a.items:
if not b.has_key(k):
yield k
for k in b.without_keys(a):
echo k