【问题标题】:KDB/Q: how to loop without loops?KDB/Q:如何在没有循环的情况下进行循环?
【发布时间】:2013-05-24 08:07:20
【问题描述】:

我在 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]... 我该怎么办?

一般来说,我需要如何改变心态,才能在q中正确编程?

非常感谢您的建议 马可

【问题讨论】:

  • q 没有循环并不是真的,只是不鼓励你使用它们,除非你真的必须这样做。在某些情况下,使用循环绝对是正确的做法,为此您需要查看 while 和 do 关键字。

标签: kdb


【解决方案1】:

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

您需要使用 over (/)、scan (\) 和 .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 (/) 会很复杂,但通常 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 就进行迭代,以 () 作为种子值开始

还有许多其他选项可以使用 scan 和 over,具体取决于您要迭代的函数是 monadic/diadic 等。

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

【讨论】:

    【解决方案2】:
    flip (-2_price;-1_1_price;2_price)
    

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

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

    始终关注 \t 告诉您的内容是一种好习惯 - KDB 不会为您优化任何内容。

    【讨论】:

      【解决方案3】:

      至于嵌套循环,我发现有用的是创建一个交叉列表。 例如

      `for 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 语法。如果你能说出你想要什么输出,可以提供帮助。

      【讨论】:

      • R 中的符号,例如[1:3] 表示向量 (1,2,3)。所以我的意思是我想要这个输出(如上所述采用向量“闭包”):18.54 18.53 18.53 18.52 18.57 18.9 18.9 18.77 18.59 18.51 18.37
      • R 中的符号,例如[1:3] 表示向量 (1,2,3)。所以我的意思是我想要这个输出(如上所述采用向量“闭包”): (18.54 18.53 18.53 ) (18.53 18.53 18.52) (18.53 18.52 18.57 ) ......即 (closures[0]closures[1 ] 闭包[2] ) (闭包[1] 闭包[2] 闭包[3] )(闭包[2] 闭包[3] 闭包[4] ) ...... 无论如何我使用 q while 循环暂时解决了这个问题.但它在 q 中看起来很不自然。我只是觉得我在心理方法上走错路了
      • 这应该可以为您解决问题。 {[x;y] 3#y _ x} [(1 2 3 4 5 6 7 8 9)] each til 7
      【解决方案4】:

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

      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
      

      【讨论】:

      • 酷。我有 {x 翻转 til[y]+\:til count[x]-y-1}
      【解决方案5】:

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

      但是,如果您不知道,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】:

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

        但是,要充分利用 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 函数转置矩阵,以便您将组作为行,最后我们使用 _ 运算符删除包含空值的前两行。

        【讨论】:

        • 这并没有提供问题的答案。要批评或要求作者澄清,请在其帖子下方发表评论。
        • @wai-ha-lee:这回答了如何在没有循环的情况下对价格进行分组的具体问题。我错过了什么?
        • 您的答案没有解释,可以归类为纯代码,这意味着它的用处仅限于解决手头的具体问题。使用 cmets/explanation,答案对更广泛的社区更有用。
        【解决方案7】:

        就像上面的一些用户所建议的那样,我认为最好的方法是计算你想要的指数。尽可能避免使用 lambda 表达式并使用运算符(这是更好的风格)。

         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
        

        【讨论】:

          猜你喜欢
          • 2021-03-31
          • 1970-01-01
          • 1970-01-01
          • 2023-03-03
          • 1970-01-01
          • 2017-10-30
          • 1970-01-01
          • 2015-11-15
          • 1970-01-01
          相关资源
          最近更新 更多