How can I convert this select statement to functional form? - kdb

I am having a couple of issues to put this in a functional format.
select from tableName where i=fby[(last;i);([]column_one;column_two)]
This is what I got:
?[tableName;fby;enlist(=;`i;(enlist;last;`i);(+:;(!;enlist`column_one`column_two;(enlist;`column_one;`column_two))));0b;()]
but I get a type error.
Any suggestions?

Consider using the following function, adjust from the buildQuery function given in the whitepaper on Parse Trees. This is a pretty useful tool for quickly developing in q, this version is an improvement on that given in the linked whitepaper, having been extended to handle updates by reference (i.e., update x:3 from `tab)
\c 30 200
tidy:{ssr/[;("\"~~";"~~\"");("";"")] $[","=first x;1_x;x]};
strBrk:{y,(";" sv x),z};
//replace k representation with equivalent q keyword
kreplace:{[x] $[`=qval:.q?x;x;"~~",string[qval],"~~"]};
funcK:{$[0=t:type x;.z.s each x;t<100h;x;kreplace x]};
//replace eg ,`FD`ABC`DEF with "enlist`FD`ABC`DEF"
ereplace:{"~~enlist",(.Q.s1 first x),"~~"};
ereptest:{((0=type x) & (1=count x) & (11=type first x)) | ((11=type x)&(1=count x))};
funcEn:{$[ereptest x;ereplace x;0=type x;.z.s each x;x]};
basic:{tidy .Q.s1 funcK funcEn x};
addbraks:{"(",x,")"};
//where clause needs to be a list of where clauses, so if only one whereclause need to enlist.
stringify:{$[(0=type x) & 1=count x;"enlist ";""],basic x};
//if a dictionary apply to both, keys and values
ab:{$[(0=count x) | -1=type x;.Q.s1 x;99=type x;(addbraks stringify key x),"!",stringify value x;stringify x]};
inner:{[x]
idxs:2 3 4 5 6 inter ainds:til count x;
x:#[x;idxs;'[ab;eval]];
if[6 in idxs;x[6]:ssr/[;("hopen";"hclose");("iasc";"idesc")] x[6]];
//for select statements within select statements
//This line has been adjusted
x[1]:$[-11=type x 1;x 1;$[11h=type x 1;[idxs,:1;"`",string first x 1];[idxs,:1;.z.s x 1]]];
x:#[x;ainds except idxs;string];
x[0],strBrk[1_x;"[";"]"]
};
buildSelect:{[x]
inner parse x
};
We can use this to create the functional query that will work
q)n:1000
q)tab:([]sym:n?`3;col1:n?100.0;col2:n?10.0)
q)buildSelect "select from tab where i=fby[(last;i);([]col1;col2)]"
"?[tab;enlist (=;`i;(fby;(enlist;last;`i);(flip;(lsq;enlist`col1`col2;(enlist;`col1;`col2)))));0b;()]"
So we have the following as the functional form
?[tab;enlist (=;`i;(fby;(enlist;last;`i);(flip;(lsq;enlist`col1`col2;(enlist;`col1;`col2)))));0b;()]
// Applying this
q)?[tab;enlist (=;`i;(fby;(enlist;last;`i);(flip;(lsq;enlist`col1`col2;(enlist;`col1;`col2)))));0b;()]
sym col1 col2
----------------------
bah 18.70281 3.927524
jjb 35.95293 5.170911
ihm 48.09078 5.159796
...

Glad you were able to fix your problem with converting your query to functional form.
Generally it is the case that when you use parse with a fby in your statement, q will convert this function into its k definition. Usually you should just be able to replace this k code with the q function itself (i.e. change (k){stuff} to fby) and this should run properly when turning the query into functional form.
Additionally, if you check out https://code.kx.com/v2/wp/parse-trees/ it goes into more detail about parse trees and functional form. Additionally, it contains a script called buildQuery which will return the functional form of the query of interest as a string which can be quite handy and save time when a functional form is complex.

I actually got it myself ->
?[tableName;((=;`i;(fby;(enlist;last;`i);(+:;(!;enlist`column_one`column_two;(enlist;`column_one;`column_two)))));(in;`venue;enlist`venueone`venuetwo));0b;()]
The issues was a () missing from the statement. Works fine now.
**if someone wants to add a more detailed explanation on how manual parse trees are built and how the generic (k){} function can be replaced with the actual function in q feel free to add your answer and I'll accept and upvote it

Related

PureScript - Simple Multiline Computation

Consider the following JavaScript function, which performs a computation over several lines to clearly indicate the programmer's intent:
function computation(first, second) {
const a = first * first;
const b = second - 4;
const c = a + b;
return c;
}
computation(12, 3)
//143
computation(-3, 2.6)
//7.6
I have tried using do notation to solve this with PureScript but I seem to be just short of understanding some key concept. The do notation examples in the documentation only covers do notation when the value being bound is an array (https://book.purescript.org/chapter4.html#do-notation), but in my example I would like the values to be simple values of the Int or Number type.
While it is possible to perform this computation in one line, it makes the code harder to debug and does not scale to many operations.
How would the computation method be written correctly in PureScript so that...
If computation involved 1000 intermediate steps, instead of 3, the code would not suffer from excessive indenting but would be as readable as possible
Each step of the computation is on its own line, so that, for example, the code could be reviewed line by line by a supervisor, etc., for quality
You don't need the do notation. The do notation is intended for computations happening in a monad, whereas your computation is naked.
To define some intermediate values before returning result, use the let .. in construct:
computation first second =
let a = first * first
b = second - 4
c = a + b
in c
But if you really want to use do, you can do that as well: it also supports naked computations just to give you some choice. The difference is that within a do you can have multiple lets on the same level (and they work the same as one let with multiple definitions) and you don't need an in:
computation first second = do
let a = first * first -- first let
b = second - 4
let c = a + b -- second let
c -- no in

Checking whether values are Upper case or lower case

I'm trying to build a function in q/kdb+ that can detect whether the string passed to the function is Upper case (True) OR lower case (false)
I have done several attempts but I'm constantly hitting a road block
Here's my function, would appreciate the help. TIA
isAllCaps: {[input] if[input = lower; show 0b; show 1b]}
The above function basically takes an input as specified. It then checks from the if statement whether it is lower, if it is lower then it should return a false(0b), if not then return a true (1b). Really struggling with something so simple here. I'm just getting the following error:
evaluation error:
type
[1] isAllCaps:{[input] if[input = lower; show 0b; show 1b]}
^
[0] isAllCaps"a"
I have also tried other methods but only certain inputs were coming out to be successful.
For instance:
isAllCaps: {[x] if[ x = upper type 10h; show 1b; show 0b]}
This equates to if x is upper type string, show true, else show false. Again, getting a type error. Idk why? All the tests are in strings i.e., "John_Citizen" etc. etc.
EDIT
Tried this but I'm getting 2 outputs.
isAllCaps: {[L] if[L = lower L; show 0b; show 1b] } Am I missing something?
Try following code:
isAllCaps: {[L] show L~upper L};
It shows 1b if string is uppercase, and 0b otherwise.
There are 2 mistakes in you code
~ should be used to compare strings. = does character-wise comparison. I.e. "aa"~"aa" gives 1b, but "aa"="aa" gives 11b
Use if-else, instead of if. See 10.1.1 Basic Conditional Evaluation for more details
You can use the in-built uppercase alphabet .Q.A to achieve what you want:
{all x in .Q.A}
This lambda will return 1b if the input string consists only of capital letters and false otherwise.
Start by removing some misapprehensions.
lower returns the lower case of its argument.
show displays and returns its result. You can use it as you have to ensure the function’s result is printed on the console, but it is not required as, for example return would be in JavaScript.
If you have a boolean as the result of a test, that can just be your result.
Compare strings for equality using Match ~ rather than Equals
That said, two strategies: test for lower-case chars .Q.a, or convert to upper case and see if there is a difference.
q){not any x in .Q.a}"AAA_123"
1b
q){not any x in .Q.a}"AaA_123"
0b
The second strategy could hardly be simpler to write:
q){x~upper x}"AaA_123"
0b
q){x~upper x}"AAA_123"
1b
Together with the Apply . operator, the Zen monks construction gives you fast ‘point-free’ code – no need for a lambda:
q).[~] 1 upper\"AaA_123"
0b
q).[~] 1 upper\"AAA_123"
1b

Conditional declaration by array of records

I try to create many components depending on the value of constant elements. These elements are organized in an array of records.
Dymola prints the translation log for the example below:
But I'm sure to use fixed conditions because I only perform allowed operations on constant values.
Here is the simple example of what I wantet to do:
model ConditionalComponent
type Enum = enumeration(one,two,three);
record Tmp
parameter Integer ID;
parameter Boolean active;
end Tmp;
record TmpNamed
parameter Enum name;
extends Tmp;
end TmpNamed;
function reorder
input TmpNamed inp[:];
output Tmp out[size(inp,1)];
algorithm
for elem in inp loop
out[elem.name] := Tmp(elem.ID, elem.active);
end for;
end reorder;
constant TmpNamed testIn[:] = {
TmpNamed(Enum.two,20,true),
TmpNamed(Enum.one,10,true),
TmpNamed(Enum.three,30,true)};
constant Tmp testOut1[:] = reorder({
TmpNamed(Enum.two,20,true),
TmpNamed(Enum.one,10,true),
TmpNamed(Enum.three,30,true)});
constant Tmp testOut2[:] = reorder(testIn);
constant Boolean active1 = testOut1[Enum.one].active;
constant Boolean active2 = testOut2[Enum.one].active;
Real t1=0 if testOut1[Enum.one].active;
//Real t2=0 if testOut2[Enum.one].active;
//Real t3=0 if active1;
//Real t4=0 if active2;
end ConditionalComponent;
The function reorder is intended to ease the management of large lists of named active components. Normally the constant testOut2 is used and created within the package ConditionalComponent. But for testing purposes ConditionalComponent is a model here. Actually I only want to use the line
Real t2=0 if testOut2[choice].active;
parameter Enum choice = Enum.one;
within other components, that have a parameter of type Enum. The declarations for t1, t3, t4 are only some tests that work, depending on what is left uncommented.
For example leaving the declaration for t1 and t3 uncommented works. But if one uses only the declaration for t1, it is not translated by Dymola.
The difference between t1 and t2 is, that the argument for reorder is passed directly or via the constant testIn.
I'm sure, that most parameter and constant prefixes are unnecessary and I tried hard to figure out the problem. But unfortunately I cannot decide whether Dymola is not working correctly or I did something wrong. And I've got no idea how to debug the translation process to figure it out by myself.
Can anyone tell me, what am I doing wrong?
Not something wrong, but it's just currently seen as too complicated and not handled.
A work-around is to split subscripting and element access:
constant Tmp testOut1_one=testOut1[Enum.one];
Real t1=0 if testOut1_one.active;

Sub- or Function Procedure not defined

I am writing my first macro for Libre Office right now and I have come into a bit of a problem: My code throws the error: BASIC Runtime error; Sub- or Function procedure not defined.
The line with the "If Cells (RowCnt,ChkCol......) throws the error.
I've looked through other entries on here, but I could not find the error... can anyone help me?
REM ***** BASIC *****
Sub Zeilennausblenden_Nullsummen
BeginRow=4
EndRow = 46
ChkCol= D
For RowCnt = BeginRow To EndRow step 1
If Cells(RowCnt,ChkCol).Value > 1 Then
Cells(RowCnt,ChkCol).EntireRow.Hidden = True
End if
Next
End Sub
PS: The function should hide all rows in which an integer higher than "1" appears in column "D"
Thanks in advance
Here is what the code looks like in LibreOffice Basic (aka StarBasic):
Sub Zeilennausblenden_Nullsummen
BeginRow=4
EndRow = 46
ChkCol= 3
oSheet = ThisComponent.Sheets(0)
For RowCnt = BeginRow To EndRow step 1
oCell = oSheet.getCellByPosition(ChkCol,RowCnt)
If oCell.Value > 1 Then
oRow = oSheet.getRows().getByIndex(RowCnt)
oRow.IsVisible = False
End if
Next
End Sub
I wasn't sure if BeginRow should be 3 or 4, because it's zero-based. You can test it and decide.
Note that a macro is not necessary in order to accomplish this task. The easiest way is to go to Data -> More Filters -> Standard Filter.
That's because CELLS isn't a StarBasic function.
It's VBA (different programming language). Some versions of OpenOffice support the use of it if a statement (Option VBASupport 1) is put in first line of source code.
Check the net for Andrew Pitonyak's "OpenOffice Macros Explained" document - very good for learning and available in German translation, too.

Designing Function to Reduce Return Variables in Matlab

This is NOT a question where I need to know how to add A+B in MATLAB. This is more of a code design question.
I have few function files that return a numeric matrix and index info on the matrix. For example
function [Mat1, IdxID, IdxDate, IdxVal, IdxMarker, IdxOpen, ...] = First ()
....
.... % where IdxId = 1 ; IdxDate = 2 ; ...
end
function [Mat1, IdxUid, IdxName, IdxVal, Mat2, IdxUid2, IdxSalary2, ...] = Second ()
....
.... % where IdxUid= 1 ; IdxName= 2 ; ...
end
As you can see the code becomes clunky and when I call these functions, I have to declare an equal number of outputs to catch all the indices. The advantage is if I suddenly swap ID & Date columns, the calling functions do not change as I simply make ID=2, Date=1. I also have the advantage of renaming these variables inside the function.
Is there a better way to do this? I'm testing whether struct or cell can be used for indices. I can't use datasets or cell for returning numeric matrix. Too much time is lost in translating it into numbers. Thanks.
Yes, you can return arrays/cells/structs instead. For instance, id can be a struct with multiple variables. Your function definition could be as follows.
function [Mat, Id] = Second ()
...
end
In your function, have the following set:
Id.Name
Id.Val
Id.Salary
...
If you find that you have multiple structs with the same exact structure, you can even consider objects.
Please clarify with more details on the structure if you want a more detailed answer.