KDB / Q:如何循环没有循环?

时间:2013-05-24 08:07:21

标签: kdb

我在kdb数据库上学习q。我担心q中没有循环这一事实。 我需要编写一个算法,我会在像C这样的详细程序中用几个嵌套的for循环编写。但是在q中我被我无法循环的事实所困扰。

只是给出一个具体的例子(许多中的一个),我有这个简单的向量(列表):

q)closures
price
-----
18.54
18.53
18.53
18.52
18.57
18.9 
18.9 
18.77
18.59
18.51
18.37

我需要一个向这些条目分组3by3的向量,具有叠加,如(使用R语法): 封[0:2],封闭件[1:3],封锁[2:4],封锁[3:5] ... 我该怎么办?

一般来说,我如何改变心态,正确编程?

非常感谢你的建议 马可

7 个答案:

答案 0 :(得分:8)

解决你的最后一点,“如何改变我的心态,在q中正确编程?”:

您需要利用(/),扫描(\)和.z.s而不是使用循环。

例如,您的问题可以通过以下方式解决: (请注意,这些对于您的特定问题实际上并不是最佳解决方案 - 索引是更好的方法 - 但是下面的这些解决方案应该有助于解决问题)

price:18.54 18.53 18.53 18.52 18.57 18.9 18.9 18.77 18.59 18.51 18.37

q)3#'{1_x}\[8;price]
18.54 18.53 18.53
18.53 18.53 18.52
18.53 18.52 18.57
18.52 18.57 18.9
18.57 18.9  18.9
18.9  18.9  18.77
18.9  18.77 18.59
18.77 18.59 18.51
18.59 18.51 18.37

即迭代列表,每次切断一次,每次迭代前3次

或类似地

q)3#'{1 rotate x}\[8;price]
18.54 18.53 18.53
18.53 18.53 18.52
18.53 18.52 18.57
18.52 18.57 18.9
18.57 18.9  18.9
18.9  18.9  18.77
18.9  18.77 18.59
18.77 18.59 18.51
18.59 18.51 18.37

即。旋转1次,每次旋转前3次

使用.z.s方法

q){$[2<count x;enlist[3#x],.z.s 1_x;()]}[price]
18.54 18.53 18.53
18.53 18.53 18.52
18.53 18.52 18.57
18.52 18.57 18.9
18.57 18.9  18.9
18.9  18.9  18.77
18.9  18.77 18.59
18.77 18.59 18.51
18.59 18.51 18.37

即。如果剩下至少3个元素,则先取3,然后砍掉第一个项目,并将相同的函数重新应用到缩短的列表中。

在这个例子中使用over(/)会很复杂,但一般而言,替换“while”类型的构造是有用的

i:0
a:0;
while[i<10;i+:1;a+:10] 
使用

可以更好地实现

q){x+10}/[10;0]
100

即。添加10次,初始(种子)值为零。

b:();  
while[not 18~last b;b,:1?20]      

即保持在1到20之间追加随机数,直到你达到18,然后停止。

使用

可以更好地实现

q){x,1?20}/[{not 18~last x};()]
1 2 16 5 8 18

即附加一个介于1和20之间的随机数,只要检查函数返回true就会迭代,以()作为种子值开始

还有很多其他选项可以使用扫描和结束,具体取决于你迭代的函数是monadic / diadic等。

作为一个广泛的概括: 使用“function each i”可以在q中实现“for i = 1:10”类型的循环, 可以使用“function / [numOfTimes; seed]”在q中实现“do”类型循环, 使用“function / [booleanCheckFunction; seed]”可以在q中实现“while”类型循环

答案 1 :(得分:3)

flip (-2_price;-1_1_price;2_price)

如前所述,使用内置函数总是比使用&#39;要么 /。这就是为什么在100万个元素的vecor上,来自最佳答案的代码需要永远完成并使用堆的GB。 JPC和Harshal的索引方法要快几英里,但上面的翻转速度要快三倍。

一旦获得格式的数据,您只需使用each将闭包应用于列表的元素。

始终关注什么\ t告诉你这是一个好习惯 - KDB不会为你优化任何事情。

答案 2 :(得分:3)

Q确实有传统的循环结构:do重复一个给定次数的语句,while在给定条件成立时重复。此外,q“副词”eachover等允许您在向量的元素上“循环”一个函数。

但是,要充分利用q的强大功能,您应该学习如何避免显式循环。

简化您的具体示例(使用简单的向量而不是1列表),以下是重组价格向量的方法:

q)price:18.54 18.53 18.53 18.52 18.57 18.9 18.9 18.77 18.59 18.51 18.37
q)2_flip(prev x;x:prev x;x:price)
18.54 18.53 18.53
18.53 18.53 18.52
18.53 18.52 18.57
18.52 18.57 18.9
18.57 18.9  18.9
18.9  18.9  18.77
18.9  18.77 18.59
18.77 18.59 18.51
18.59 18.51 18.37

以下是它的工作原理。 (请记住:q从右到左进行评估。)prev函数将价格转移到向量中的右侧(在开始时预先设置空值并丢弃最后一个值:

q)prev price
0n 18.54 18.53 18.53 18.52 18.57 18.9 18.9 18.77 18.59 18.51
q)prev prev price
0n 0n 18.54 18.53 18.53 18.52 18.57 18.9 18.9 18.77 18.59

我们将原始价格向量与两个移位的$ 3 \ times n $矩阵相结合。该矩阵的列是我们想要的组。 flip函数转换矩阵,以便您将组作为行获取,最后我们使用_运算符删除包含空值的前两行。

答案 3 :(得分:2)

对于嵌套循环,我发现有用的东西是创建一个交叉列表。 E.g

`i = 1:10

 for j=1:20
    for k=1:30
      f(i, j, k)

`

你可以

il: 1 _til 11
jl: 1_til 21
kl: 1_til 31
lst: il cross jl cross kl
raze g(x) each til count ls

其中g定义为

g: {[i]
itr: first lst[i];
jtr: first 1_lst[i];
ktr: last lst[i];

f(itr, jtr, ktr)
}

希望这澄清一下。至于闭包部分那里不知道R语法。如果你能说出你想要的输出,可以提供帮助。

答案 4 :(得分:2)

一种方法是计算你关心的指数,然后将其索引到数组中 -

q) f:{y til[x]+/:neg[x]_til count y} // [x] = sublist length [y] = list
q) f[3;18.54 18.53 18.53 18.52 18.57 18.9 18.9 18.77 18.59 18.51 18.37]
    18.54 18.53 18.53
    18.53 18.53 18.52
    18.53 18.52 18.57
    18.52 18.57 18.9
    18.57 18.9  18.9
    18.9  18.9  18.77
    18.9  18.77 18.59
    18.77 18.59 18.51

答案 5 :(得分:2)

KDB Q是一种矢量处理语言,它的优势在于处理列表,而不是像在命令式语言中那样处理单个 atoms

但是,如果您不知道,Q确实支持循环,并且可以在没有其他方式的情况下使用!这是我在开始从Java迁移到KDB Q时编写的一个例子

isPrime:{[num] i:2; flag:1b; while[i<=sqrt num; if[(num mod i)~0;flag:0b];i:i+1]; flag}

它还有do-while种语法

    i : 0;
    do [5;
        // Iterated action involving i
        0N!i; //printing i
        i : i + 1
    ];

看看here

答案 6 :(得分:0)

像上面的一些用户建议的那样,我认为最好的想法就是计算你想要的指数。如果可能的话,避免使用lambdas并使用运算符(这是更好的风格)。

 q)v:18.54 18.53 18.53 18.52 18.57 18.9 18.9 18.77 18.59 18.51 18.37
 q)v (0 1 2)+/:til count v ///generate a list of indices from 0 to the count of v, then add 0 1 2 to each of those indices
18.54 18.53 18.53
18.53 18.53 18.52
18.53 18.52 18.57
18.52 18.57 18.9
18.57 18.9  18.9
18.9  18.9  18.77
18.9  18.77 18.59
18.77 18.59 18.51
18.59 18.51 18.37
18.51 18.37
18.37