Checking whether values are Upper case or lower case - kdb

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

Related

Purescript: Convert Maybe Type to Type

The following simple code converts an Integer value to a string value and logs it.
module Main where
import Effect (Effect)
import Effect.Console (log)
import Prelude ((<>), Unit, discard)
import Data.Int (toStringAs, radix)
type CustomerFeedback = {
customerServiceScore :: Int,
productQualityScore :: Int,
onTimeDeliveryScore :: Int
}
feedback :: CustomerFeedback
feedback = {
customerServiceScore : 4,
productQualityScore : 2,
onTimeDeliveryScore : 6
}
stringifyCustomerFeedback :: CustomerFeedback -> String
stringifyCustomerFeedback feedback = "Service: " <> toStringAs (radix 10) feedback.customerServiceScore
main ∷ Effect Unit
main = do
log (stringifyCustomerFeedback(feedback))
However, running this code produces the following error:
Could not match type
Maybe Radix
with type
Radix
while checking that type Maybe Radix
is at least as general as type Radix
while checking that expression radix 10
has type Radix
in value declaration stringifyCustomerFeedback
Questions would be as follows:
How do you change the code above so it outputs a string as expected and not an error?
What's the point of a Maybe Radix type if using it where you would use a Radix causes an error? How do you use a Maybe value?
The idea of the radix function is that you give it a number and it creates a Radix from it. But not every number constitutes a valid Radix. For example, if you give it -5, it shouldn't work. And neither should 0 or 1 for example. For some technical reasons, radices above 32 are also deemed invalid.
So that's why it returns Maybe: it would be Nothing in case the number you gave it wasn't a "valid" radix.
And the use case for that function is when you don't actually know the number ahead of time. Like if you get it from the user. Or from some sort of config file or whatnot. In that case, if you get a Nothing, you would interpret that as "invalid user input" or "corrupted config file" and report an error accordingly. And you won't even get as far as calling toStringAs. This is one of the big selling points of static types: applied properly, they can force you to write a correct, reliable program, without ignoring edge cases.
However, in case you already know that you're interested in decimal radix, just use decimal. It's a Maybe-free constant provided by the library, along with some other frequently used ones, such as binary and octal.
stringifyCustomerFeedback feedback = "Service: " <> toStringAs decimal feedback.customerServiceScore

How can I convert this select statement to functional form?

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

Having problems with questdlg in matlab

I'm sorry for having only a part of the code but it is unnecessarily complicated. I want to have multiple question dialog boxes embedded with cases. The first switch case which is switch secim works fine when I put the last option twice which is 'Uc','Uc' and unless I write it that way it shows only the other options. But when I do the same thing for the inner switch case which isswitch secim2 it gives an error on the line secim2 = questdlg('İslem?', ... and when I delete the second 'Birim vektor' it works fine but doesn't show the Birim vektor option at all. How do I fix this?
secim = questdlg('Vektorler kac boyutlu?', ...
'Vektor', ...
'Bir','İki','Uc','Uc');
switch secim
case 'Bir'
secim2 = questdlg('İslem?', ...
'Vektor', ...,
'Toplam','Fark','Skaler Carpim','Birim vektor');
switch secim2
...
If you see the documentation, the syntax you're using in secim when you're repeating 'Uc' is:
button = questdlg(qstring,title,str1,str2,str3,default)
As mentioned in the documentation, default should be one of str1, str2 and str3 and hence when you repeat 'Uc', it takes 'Uc' as the default value and you have no problem.
In secim2, 'Birim vektor' doesn't match any of the three strings and hence you'd get this warning:
Warning: Default character vector does not match any button
character vector name.
If you repeat 'Birim vektor', it doesn't match with any of the valid syntaxes.
Above explanation is also pointed out in the comments.
For more than three strings, use listdlg.
choices = {'Toplam' ,'Fark','Skaler Carpim','Birim vektor'};
SelInd = listdlg('Name','Vektor', 'PromptString','İslem?','ListString',choices,...
'CancelString', 'Default Choice', 'SelectionMode','single',...
'ListSize',[200 100]) %adjust listsize as per requirement
SelInd(end+1) = 4; %Default Choice (Biriam vektor)
secim2 = choices{SelInd(1)};
which gives:

Algorithm to evaluate value of Boolean expression

I had programming interview which consisted of 3 interviewers, 45 min each.
While first two interviewers gave me 2-3 short coding questions (i.e reverse linked list, implement rand(7) using rand(5) etc ) third interviewer used whole timeslot for single question:
You are given string representing correctly formed and parenthesized
boolean expression consisting of characters T, F, &, |, !, (, ) an
spaces. T stands for True, F for False, & for logical AND, | for
logical OR, ! for negate. & has greater priority than |. Any of these
chars is followed by a space in input string. I was to evaluate value
of expression and print it (output should be T or F). Example: Input:
! ( T | F & F ) Output: F
I tried to implement variation of Shunting Yard algorithm to solve the problem (to turn input in postfix form, and then to evaluate postfix expression), but failed to code it properly in given timeframe, so I ended up explaining in pseudocode and words what I wanted.
My recruiter said that first two interviewers gave me "HIRE", while third interviewer gave me "NO HIRE", and since the final decision is "logical AND", he thanked me for my time.
My questions:
Do you think that this question is appropriate to code on whiteboard in approx. 40 mins? To me it seems to much code for such a short timeslot and dimensions of whiteboard.
Is there shorter approach than to use Shunting yard algorithm for this problem?
Well, once you have some experience with parsers postfix algorithm is quite simple.
1. From left to right evaluate for each char:
if its operand, push on the stack.
if its operator, pop A, then pop B then push B operand A onto the stack. Last item on the stack will be the result. If there's none or more than one means you're doing it wrong (assuming the postfix notation is valid).
Infix to postfix is quite simple as well. That being said I don't think it's an appropriate task for 40 minutes if You don't know the algorithms. Here is a boolean postfix evaluation method I wrote at some stage (uses Lambda as well):
public static boolean evaluateBool(String s)
{
Stack<Object> stack = new Stack<>();
StringBuilder expression =new StringBuilder(s);
expression.chars().forEach(ch->
{
if(ch=='0') stack.push(false);
else if(ch=='1') stack.push(true);
else if(ch=='A'||ch=='R'||ch=='X')
{
boolean op1 = (boolean) stack.pop();
boolean op2 = (boolean) stack.pop();
switch(ch)
{
case 'A' : stack.push(op2&&op1); break;
case 'R' : stack.push(op2||op1); break;
case 'X' : stack.push(op2^op1); break;
}//endSwitch
}else
if(ch=='N')
{
boolean op1 = (boolean) stack.pop();
stack.push(!op1);
}//endIF
});
return (boolean) stack.pop();
}
In your case to make it working (with that snippet) you would first have to parse the expression and replace special characters like "!","|","^" etc with something plain like letters or just use integer char value in your if cases.

Best way to create generic/method consistency for sort.data.frame?

I've finally decided to put the sort.data.frame method that's floating around the internet into an R package. It just gets requested too much to be left to an ad hoc method of distribution.
However, it's written with arguments that make it incompatible with the generic sort function:
sort(x,decreasing,...)
sort.data.frame(form,dat)
If I change sort.data.frame to take decreasing as an argument as in sort.data.frame(form,decreasing,dat) and discard decreasing, then it loses its simplicity because you'll always have to specify dat= and can't really use positional arguments. If I add it to the end as in sort.data.frame(form,dat,decreasing), then the order doesn't match with the generic function. If I hope that decreasing gets caught up in the dots `sort.data.frame(form,dat,...), then when using position-based matching I believe the generic function will assign the second position to decreasing and it will get discarded. What's the best way to harmonize these two functions?
The full function is:
# Sort a data frame
sort.data.frame <- function(form,dat){
# Author: Kevin Wright
# http://tolstoy.newcastle.edu.au/R/help/04/09/4300.html
# Some ideas from Andy Liaw
# http://tolstoy.newcastle.edu.au/R/help/04/07/1076.html
# Use + for ascending, - for decending.
# Sorting is left to right in the formula
# Useage is either of the following:
# sort.data.frame(~Block-Variety,Oats)
# sort.data.frame(Oats,~-Variety+Block)
# If dat is the formula, then switch form and dat
if(inherits(dat,"formula")){
f=dat
dat=form
form=f
}
if(form[[1]] != "~") {
stop("Formula must be one-sided.")
}
# Make the formula into character and remove spaces
formc <- as.character(form[2])
formc <- gsub(" ","",formc)
# If the first character is not + or -, add +
if(!is.element(substring(formc,1,1),c("+","-"))) {
formc <- paste("+",formc,sep="")
}
# Extract the variables from the formula
vars <- unlist(strsplit(formc, "[\\+\\-]"))
vars <- vars[vars!=""] # Remove spurious "" terms
# Build a list of arguments to pass to "order" function
calllist <- list()
pos=1 # Position of + or -
for(i in 1:length(vars)){
varsign <- substring(formc,pos,pos)
pos <- pos+1+nchar(vars[i])
if(is.factor(dat[,vars[i]])){
if(varsign=="-")
calllist[[i]] <- -rank(dat[,vars[i]])
else
calllist[[i]] <- rank(dat[,vars[i]])
}
else {
if(varsign=="-")
calllist[[i]] <- -dat[,vars[i]]
else
calllist[[i]] <- dat[,vars[i]]
}
}
dat[do.call("order",calllist),]
}
Example:
library(datasets)
sort.data.frame(~len+dose,ToothGrowth)
Use the arrange function in plyr. It allows you to individually pick which variables should be in ascending and descending order:
arrange(ToothGrowth, len, dose)
arrange(ToothGrowth, desc(len), dose)
arrange(ToothGrowth, len, desc(dose))
arrange(ToothGrowth, desc(len), desc(dose))
It also has an elegant implementation:
arrange <- function (df, ...) {
ord <- eval(substitute(order(...)), df, parent.frame())
unrowname(df[ord, ])
}
And desc is just an ordinary function:
desc <- function (x) -xtfrm(x)
Reading the help for xtfrm is highly recommended if you're writing this sort of function.
There are a few problems there. sort.data.frame needs to have the same arguments as the generic, so at a minimum it needs to be
sort.data.frame(x, decreasing = FALSE, ...) {
....
}
To have dispatch work, the first argument needs to be the object dispatched on. So I would start with:
sort.data.frame(x, decreasing = FALSE, formula = ~ ., ...) {
....
}
where x is your dat, formula is your form, and we provide a default for formula to include everything. (I haven't studied your code in detail to see exactly what form represents.)
Of course, you don't need to specify decreasing in the call, so:
sort(ToothGrowth, formula = ~ len + dose)
would be how to call the function using the above specifications.
Otherwise, if you don't want sort.data.frame to be an S3 generic, call it something else and then you are free to have whatever arguments you want.
I agree with #Gavin that x must come first. I'd put the decreasing parameter after the formula though - since it probably isn't used that much, and hardly ever as a positional argument.
The formula argument would be used much more and therefore should be the second argument. I also strongly agree with #Gavin that it should be called formula, and not form.
sort.data.frame(x, formula = ~ ., decreasing = FALSE, ...) {
...
}
You might want to extend the decreasing argument to allow a logical vector where each TRUE/FALSE value corresponds to one column in the formula:
d <- data.frame(A=1:10, B=10:1)
sort(d, ~ A+B, decreasing=c(A=TRUE, B=FALSE)) # sort by decreasing A, increasing B