8

kdb データベースで q を学習しています。q にループがないことが気になります。C のような冗長なプログラムで、ネストされた for ループをいくつか使用して記述するアルゴリズムを作成する必要があります。しかし、q では、ループできないという事実に行き詰まります。

特定の例 (多くの例の 1 つ) を示すために、この単純なベクトル (列テーブル) があります。

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

これらのエントリを (R 構文を使用して) 重ね合わせで 3by3 にグループ化するベクトルが必要です: クロージャー[0:2]、クロージャー[1:3]、クロージャー[2:4]、クロージャー[3:5]...どのようにできるのか?

一般に、q で正しくプログラミングするには、どのように考え方を変える必要がありますか?

あなたの提案をどうもありがとうマルコ

4

7 に答える 7

10

「qで正しくプログラミングするには、どうすれば考え方を変える必要がありますか?」についての最後のポイントに対処します。

ループを使用するのではなく、オーバー (/)、スキャン (\)、および .zs を使用する必要があります。

たとえば、問題は次の方法で解決できます。

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

つまり、リストを反復し、毎回 1 つを切り捨て、各反復の最初の 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 を 8 回回転し、各回転の最初の 3 回を取得します。

.zs アプローチの使用

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 つを取得し、次に最初の項目を切り取り、短縮されたリストに同じ関数を再適用します。

この例ではオーバー (/) を使用すると複雑になりますが、一般的にオーバーは「while」型構造を置き換えるのに便利です

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

を使用するとよりよく達成されます

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

つまり、開始 (シード) 値 0 で 10 を 10 回追加します。

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

つまり、18 に到達するまで 1 から 20 までの乱数を追加し続け、その後停止します。

を使用するとよりよく達成されます

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

つまり、1 から 20 までの乱数を追加し、() をシード値として開始して、チェック関数が true を返すまで繰り返します。

反復している関数がモナド/ダイアディックなどであるかどうかに応じて、スキャンとオーバーを使用するための他の多くのオプションがあります。

大まかに一般化すると、「for i=1:10」タイプのループは「function each i」を使用して q で実現でき、「do」タイプのループは「function/[numOfTimes;seed]」を使用して q で実現できます。 「function/[booleanCheckFunction;seed]」を使用して、「while」タイプのループをqで実現できます

于 2014-08-01T13:40:13.690 に答える
3
flip (-2_price;-1_1_price;2_price)

すでに述べたように、ビルトインを使用すると、' または / を使用した反復よりも常に高速になります。そのため、100 万要素のベクトルでは、一番上の回答のコードが完了するまでに永遠に時間がかかり、GB のヒープを使用します。JPC と Harshal のインデックス作成方法は何マイルも高速ですが、上記のフリップはさらに 3 倍高速です。

必要な形式のデータを取得したら、リストの要素にクロージャーを適用するためにeachを使用するだけです。

\t の指示に常に注意することをお勧めします。KDB は何も最適化しません。

于 2015-06-11T14:17:27.010 に答える
2

1つの方法は、関心のあるインデックスを計算してから、配列にインデックスを付けることです-

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
于 2013-05-24T17:38:39.137 に答える
2

ネストされたループに関しては、クロスリストを作成するのが便利だと思いました。例えば

`i=1:10 の場合

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

`

qでできます

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構文がわかりません。必要な出力を指定できれば役立ちます。

于 2013-05-24T12:23:14.923 に答える
0

上記のユーザーの何人かが提案したように、ここで行う最善の方法は、必要なインデックスを計算することだと思います。可能であれば、ラムダを避けて演算子を使用してください (より良いスタイルです)。

 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
于 2013-08-13T20:52:58.160 に答える