[kdb+/q]:将邻接矩阵转换为邻接表

[kdb+/q]: Convert adjacency matrix to adjacency list

给定(矩形)邻接矩阵m,如何用q语言构造邻接表?

QIdioms wiki 中,我找到了 k 语言的解决方案,当 运行 通过 q 控制台和 k) 命令时,我得到 'vs错误:

m:(1 0 1;1 0 1)
k) (^m)_vs &,/m
'vs

结果应该是:

0 0 1 1
0 2 0 2

这是我在 q 中能够复制的内容:

k) &,/m
0 2 3 5
q) where raze m
0 2 3 5

k^a.k.a。 shape q 中缺少动词,所以我就这样做了:

k) (^m)
000b
000b
q) 2 3#0b
000b
000b

现在,因为:

q) parse "vs"
k) {x\:y}

我试了两个都不成功:

q) (2 3#0b) _vs where raze m
'
q) (2 3#0b) _\: where raze m
'type

请注意 QIdioms wiki has q solution 用于反问题:从 adj.list 到 adj.matrix。

你有错误,因为原始的 Q 习语是用 k2 写的 - 一个旧版本的 k,现代 kdb+ 版本不支持。 k 的当前版本是 k4,它不向后兼容 k2。

例如,X _vs Y 其中 X 和 Y 是整数原子或旧 k2 中的列表表现得像 X vs Y will 从 3.4t 开始在 kdb+ 中表现2015.12.13: http://code.kx.com/q/ref/lists/#vs:

Since 3.4t 2015.12.13: For integer types, computes the base representation of Y in the radices X.

再举个例子。事实上,k2 中的 ^ 是一个形状运算符,但现在不再是了。在 k2 ^m 中,您的示例中的矩阵 m 会 returned 2 3,而目前的实现行为与 qnot null 一样据我了解。

现在,回到您最初的问题,"how to construct adjacency list in q language"。一种方法是这样的:

q)lm:{flip raze(til count x),''where each x}

k)lm:{+,/(!#x),''&:'x}

更新:这是它的工作原理。如果我们要使用任何 "verbose" 语言构建邻接表,我们会做这样的事情:

for i = 0 to <number of rows> - 1            <---- (1)
    for j = 0 to <number of columns> - 1     <---- (2)
        if M[i;j] <> 0                       <---- (3)
            print i, j

在像 q 这样的数组语言中,(1) 可以 "translated" 变成 til count M 因为 count 将 return 顶层元素的数量,即行数。 (2)(3)组合起来可以表示为where each M。实际上,对于每一行,我们 return 非零元素的位置。给定一个原始矩阵 m 我们将得到:

til count m -> 0 1
where each m -> (0 2; 0 2)

我们需要做的就是连接行和列索引。我们不能只使用 ,',因为它会将 0 与第一个 0 2 连接起来,将 1 与第二个 0 2 连接起来,从而得到 (0 0 2; 1 0 2)。我们需要更深入一层,将左侧的每个元素与右侧嵌套列表 (0 2; 0 2) 的每个元素的每个元素连接起来,因此 ,''.

中的双撇号

我希望它现在有意义。


就我个人而言,我不会使用 flip(或 + in k),我无法读取这种形式的邻接矩阵:

0 0 1 1
0 2 0 2

我认为这更具可读性:

0 0
0 2
1 0
1 2

但这当然取决于你。