2013-05-24 1 views
8

J'apprends q sur la base de données kdb. Je suis préoccupé par le fait qu'il n'y a pas de boucles en q. Je dois écrire un algorithme que j'écrirais avec plusieurs boucles for imbriquées dans un programme verbeux comme C. Mais dans q je suis bloqué par le fait que je ne peux pas boucler.KDB/Q: comment boucler sans boucles?

Juste pour donner un exemple précis (un des nombreux), j'ai ce simple vecteur (colonne de table):

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 

je besoin d'un vecteur que les groupes 3by3 ces entrées, avec superposition, comme (en utilisant R syntaxe): fermetures [0: 2], fermetures [1: 3], fermetures [2: 4], fermetures [3: 5] ... Comment puis-je faire?

En général, comment dois-je changer ma mentalité, programmer correctement en q?

Merci beaucoup pour vos suggestions Marco

+1

Il n'est pas vrai que q n'a pas de boucles, c'est juste que vous êtes découragé de les utiliser sauf si vous en avez vraiment besoin. c'est la bonne chose à faire, et pour cela, vous voudriez vérifier les mots-clés 'while' et' do'. – mollmerx

Répondre

2

En ce qui concerne les boucles imbriquées quelque chose que je trouve utile est la création d'une liste croisée. Par exemple,

`pour i = 1: 10

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

`

en q vous pouvez

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 

où g est défini comme

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

f(itr, jtr, ktr) 
} 

Hope this clarifie. En ce qui concerne les fermetures, la partie R ne s'y trouve pas. Peut vous aider si vous pouvez dire quelle sortie vous voulez.

+0

Dans R, la notation, par ex. [1: 3] signifie le vecteur (1,2,3). Donc je voulais dire que je voulais cette sortie (en prenant le vecteur "fermetures" comme ci-dessus): 18,54 18,53 18,53 18,52 18,57 18,9 18,9 18,77 18,59 18,51 18,37 –

+0

Dans R la notation, par ex. [1: 3] signifie le vecteur (1,2,3). Donc je voulais dire que je voulais cette sortie (en prenant le vecteur « fermetures » comme ci-dessus): (18,54 18,53 18,53) (18,53 18,53 18,52) (18,53 18,52 18,57) ....... -à-dire (fermetures [0] fermetures [1] fermetures [2]) (fermetures [1] fermetures [2] fermetures [3]) (fermetures [2] fermetures [3] fermetures [4]) ...... Quoi qu'il en soit, j'ai résolu le problème temporairement en utilisant aq while loop. Mais il semble si naturel en q. Je pense juste que je suis sur le mauvais chemin avec l'approche mentale –

+0

cela devrait résoudre le problème pour vous. '{[x; y] 3 # y _ x} [(1 2 3 4 5 6 7 8 9)] jusqu'à 7' –

2

Une méthode serait de calculer les indices qui vous passionnent et puis index dans le tableau -

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 
2

KDB Q étant un langage de traitement vectoriel, il est la force réside dans le traitement listes par opposition à un traitement individuel atomes comme régulièrement dans les langues impératives. Cependant, au cas où vous ne le sauriez pas, Q prend en charge les boucles et peut être utilisé dans les cas où cela ne semble pas être le cas autrement! Voici un exemple que j'avais écrit alors que j'avais commencé la migration de Java vers KDB Q

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

Il a également do-while un peu la syntaxe

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

Jetez un oeil here

0

Comme certains des utilisateurs ci-dessus J'ai suggéré, je pense que le meilleur pense à faire ici est de calculer les indices que vous voulez. Lorsque cela est possible, évitez les lambdas et utilisez les opérateurs (c'est le meilleur style).

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 
8

En répondant à votre dernier point sur "comment ai-je besoin de changer ma mentalité, pour programmer correctement en q?« :.

Vous devez utiliser sur (/), scan (\) et .zs plutôt que d'utiliser des boucles

Par exemple, votre problème pourrait être résolu de la manière suivante: (notez que celles-ci pas vraiment être les meilleures solutions pour votre problème particulier - l'indexation est la meilleure approche là - mais ces solutions ci-dessous devrait néanmoins aider à obtenir le point à travers)

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 

c.-à-itérer sur la liste, hacher un hors chaque fois, prendre 3 premiers de chaque itération

ou similaire

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 

-à-dire en rotation par 1 huit fois, prendre la première 3 de chaque rotation

En utilisant une approche .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 

-à-dire s'il existe au moins 3 éléments à gauche, prenez d'abord 3, puis coupez le premier article et réappliquez la même fonction à la liste abrégée.

En utilisant plus (/) serait alambiqué dans cet exemple, mais en général plus est usful pour remplacer "tandis que" le type construit

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

est mieux réalisé en utilisant

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

-à-dire ajouter 10, dix fois avec une valeur de départ (graine) de zéro. Par exemple, vous pouvez ajouter des nombres aléatoires entre 1 et 20 jusqu'à ce que vous atteigniez 18, puis arrêtez-vous.

est mieux réalisé en utilisant

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

-à-dire ajouter un nombre aléatoire entre 1 et 20, itérer tant que la fonction de contrôle renvoie true, à commencer par() comme valeur de départ

Il y a beaucoup de d'autres options pour utiliser scan et over, selon que la fonction que vous itérez est monadique/diadique, etc.

En général: une boucle de type "pour i = 1: 10" peut être obtenue en q en utilisant "fonction chaque i", une boucle de type "do" peut être obtenue en q en utilisant des "fonctions/[numOfTimes; graines]" une boucle "while" de type peut être obtenue en q en utilisant "fonction/[booleanCheckFunction; graines]"

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

Comme mentionné précédemment, l'utilisation de builtins est toujours plus rapide que l'itération avec 'ou /. C'est pourquoi sur un vecor de 1 million d'éléments, le code de la réponse supérieure prend une éternité à compléter et utilise des Go de tas. La méthode d'indexation de JPC et Harshal est miles plus rapide, mais le flip ci-dessus est encore trois fois plus rapide.

Une fois que vous avez les données dans le format dont vous avez besoin, utilisez simplement each pour appliquer votre fermeture aux éléments de la liste.En gardant toujours un œil sur ce qui vous dit que c'est une bonne pratique, KDB n'optimisera rien pour vous.

3

Q possède des constructions de bouclage traditionnelles: do pour répéter une instruction donnée nombre de fois et while pour répéter tant qu'une condition donnée est valide. De plus, q "adverbes" each, over, etc. vous permet de "boucler" une fonction sur les éléments d'un vecteur. Toutefois, pour tirer pleinement parti de la puissance de q, vous devez apprendre à éviter les boucles explicites.

votre exemple spécifique Simplifier (utiliser un simple vecteur plutôt qu'une table 1 colonne), voici comment vous pouvez regrouper un vecteur de prix:

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 

Voici comment cela fonctionne. (Rappelez-vous: q évalue de droite à gauche.) La fonction prev déplace les prix à droite dans le vecteur (préfixer valeurs nulles au début et à jeter la dernière valeur:

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 

Nous combinons le vecteur de prix initial avec deux sont décalées dans une matrice $ 3 \ times n $ Les colonnes de cette matrice sont les groupes que nous voulons La fonction flip transpose la matrice afin que vous obteniez les groupes comme des lignes et finalement nous laissons tomber les deux premières lignes qui contiennent des valeurs nulles en utilisant l'opérateur _

+0

Ceci ne fournit pas de réponse à la question. Pour critiquer ou demander des éclaircissements à un auteur, laissez un commentaire sous son article. –

+0

@ wai-ha-lee: Cela répond à la question spécifique de savoir comment regrouper les prix sans boucle. Qu'est-ce que j'ai raté? –

+0

Votre réponse est énoncée sans explication et pourrait être classée comme code seulement, ce qui signifie que son utilité est limitée à la résolution du problème spécifique en question. Avec des commentaires/explications, une réponse est beaucoup plus utile à l'ensemble de la communauté. –

Questions connexes