does Sas provide mechanism of chain-expressions?
does Sas provide mechanism of In-clause?
Simple examples:
a = '09MAY2010'd;
b = '17MAY2010'd;
if (a<=c<=b) then do; /*code*/ end;
if (c in (a:b)) then do; /*code*/ end;
maybe any good techniques of if/where statements?
your suggestions and advises, please.
Thanks!
Your example, changed a bit:
data _null_;
a = '09MAY2010'd;
b = '17MAY2010'd;
c = '17MAY2010'd;
if (a<=c<=b) then do;
putlog "a<=c<=b";
end;
select (c);
when (a, b) putlog "in a, b";
when ('17MAY2010'd) putlog "'17MAY2010'd";/* not used, only first match is executed */
otherwise;
end;
run;
IN operator used with IF or in WHERE clause requires constants in the list.
Apart from the IN operator, which only accepts constant values inside the paranthesis, there is also an (undocumented) IN function, which can be used with variables, so instead of if c in(a,b) you can use if in(c,a,b) which will work also when a and b are variables.
Another possibility is to use WHICHN or WHICHC functions, which has the same syntax, and which return 0 (FALSE) when a match is not found, and otherwise the number of the (first) match.
Related
I'm trying to create a function that will cast boolean values to 't' or 'f', or '' if NULL.
CREATE OR REPLACE FUNCTION bool(b BOOLEAN) RETURNS VARCHAR
AS $$
BEGIN
IF b IS NULL THEN
RETURN '';
END IF;
IF b THEN
RETURN 't';
ELSE
RETURN 'f';
END IF;
END;
$$ LANGUAGE PLPGSQL CALLED ON NULL INPUT;
However, the following always returns NULL. What gives?
SELECT bool(NULL)
bool is also a built-in function and type cast (because there is a data type with that name).
You need to either explicitly reference your function by prefixing it with the schema:
select public.bool(null);
or give your function a different name.
Unrelated, but: your function can be simplified to:
CREATE OR REPLACE FUNCTION bool(b BOOLEAN)
RETURNS VARCHAR
AS $$
select coalesce(case when b then 't' else 'f' end, '');
$$
language sql
called on null input;
Here's a small macro I want to call at the start of my macro functions.
It is the equivalent of %if not %length(&x) %then %let x = &val.
I want to use it as it's more readable and will help me to parse my code to build documentation (Which I need to do with regex as I can't install external softwares).
%macro def
/*---------------------
Assign default value
---------------------*/
(_x_data_x_ /* variable name (to be passed raw without &) */
,value /* default value */
);
%if not %length(&&&_x_data_x_) %then %let &_x_data_x_ = &value;
%mend;
Here's how it works:
%macro test(a,b);
%def(b,&a)
%put "&b";
%mend;
%test(%str(,)); /* prints "," */
I chose the unusual parameter name _x_data_x_ because the macro fails when it's fed a value equal to the parameter's name (i.e. if my b parameter was named _x_data_x_).
Can I make it really safe, apart from choosing obscure names ?
That is the correct approach.
You could make the macro more robust by adding checks:
%* Prevent self reference because
%* assignment will not bubble to containing scope;
%if %upcase(%superq(x_data_x)) eq X_DATA_X %then %do;
%put ERROR: x_data_x=%superq(x_data_x) is not allowed;
%abort cancel;
%end;
%* Prevent reference to non-existent because
%* assignment will automatically localize
%* and not bubble to containing scope;
%if not %symexist (%superq(x_data_x)) %then %do;
%put ERROR: x_data_x=%superq(x_data_x) is invalid;
%put ERROR: %superq(x_data_x) does not exist in callee scope;
%abort cancel;
%end;
Sorry, I couldn't find a better fitting title, feel free to edit the title if you find a more suthing one. Here is my question, I know I can create a small version of IF/ELSE statement like this:
(condiction) ? numFound = true : numFound = false;
but, is there a way of having two statements inside the first condition, ex.
(condition) ? numFound = true, break: numFound = false;
normal version of if/else statement I want to write
if (condition)
{
numFound = true;
break;
}
else
numFound = false;
Sorry for the noob question, and thanks for the help!
In short, it isn't possible. The Ternary operator requires the operands to evaluate to a value, and code blocks don't. Comma expressions don't work, because they will set the value to the last one executed- break doesn't evaluate to a value. Additionally, break isn't a function to be evaluated, it's a statement.
The advice is to not use conditionals/ternary operators when you are doing things more complex than their base use- they're harder to parse by humans and any decent compiler will compile x = condition ? this:that the same as if(condition){x=this}else{x=that} (or optimize both to the same assembly).
No you cannot do that. The "small version" of the if/else is called the conditional operator. It is the only operator in c++ taking three operands and commonly also simply called "the ternary operator". From here:
Exp1 ? Exp2 : Exp3;
where Exp1, Exp2, and Exp3 are expressions. Notice the use and
placement of the colon. The value of a ? expression is determined like
this: Exp1 is evaluated. If it is true, then Exp2 is evaluated and
becomes the value of the entire ? expression. If Exp1 is false, then
Exp3 is evaluated and its value becomes the value of the expression.
And for some clarification what is an expression see this question. break is not an expression, but a statement, hence you cannot use it inside a ternary.
Anyhow I would advise you not to hide the break within more stuff in a single line. In a loop a break is something extremely important and it makes sense to make it stand out from the "normal" buissness that happens inside the loop. If I dont immediately see a break (or a return) in a loop then I assume that it does its full iteration. Overlooking a break can cause mayor confusion and misunderstanding.
You could use comma expressions. A comma expression of the form (expr1, expr2) evaluates expr1 (and ignores the value to which it evaluates) and then expr2, which's value is then the result of the overall comma expression.
int main(int argc, char* argv[]) {
bool r = (argc==1) ? (printf("no parameters"),true) : (printf("parameters"),false);
return 0;
}
My friend you're in luck. Use comma operator:
(condition) ? numFound=true, x=1, y=2: numFound = false;
Of course if you're specific to break; it won't work.
Your break doesn't work here but the task itself works. But be careful! Strange things can happen. See these examples:
0?printf("One"),printf("One"):printf("Two"),printf("Two"); /* TwoTwo */
0?(printf("One"),printf("One")):(printf("Two"),printf("Two")); /* TwoTwo */
1?printf("One"),printf("One"):printf("Two"),printf("Two"); /* OneOneTwo (!) */
1?(printf("One"),printf("One")):(printf("Two"),printf("Two")); /* OneOne */
This happens because of the comma operator which evaluates an expression fomr left to right and returns the value of the second statement for the whole expression.
The next step is to check the binding precedence of (), ?: and ,. We find here that the opertators are ordered from strong to weak like
()
?:
,
Therefore the third example I posted is evaluated as follows:
1?printf("One"),printf("One"):printf("Two"),printf("Two")
-> (1?printf("One"),printf("One"):printf("Two")),printf("Two")
-> (printf("One"),printf("One")),printf("Two")
-> OneOneTwo
I do really not recommend using the so called ternary operator in more complicated cases. Stick to clear code. You know "Code is read more than it is written."
I have this rule in yacc file and a separate c++ file for the action of the rule.
But the output is not expected as shown with the print statement below .This is the rule in parser.y :
RecordItem : IdentifierList ':' TypeDenoter
{
char * result = declareRecordItem ($1 , $3);
$$ = result;
printf(" >>> inside RecordItem >> : %s\n",result);
}
;
and this is the function 'declareRecordItem' in main.cpp file :
char* declareRecordItem( std::vector<char* >* varList , char* type){
string stm = " ";
string identifier;
for(int i=0 ; i < varList-> size() ; i++)
{
identifier= string((*varList)[i]) ;
symtab[identifier] = string(type);
stm = stm + " " + string(type);
}
char * result = (char*)stm.c_str();
printf(">>> inside declareRecordItem >> : %s\n",result);
return result ;
}
The output in declareRecordItem function is correct but when it returns to the RecordItem rule, it does not produce any thing or sometimes strange symbols are printed as shown. Any idea !.
>>> inside declareRecordItem >> : i32 i32
>>> inside RecordItem >> :
Inside declareRecordItem, you create a local variable stm of type std::string, and then return the value: (char*)stm.c_str();
However, stm ceases to exist as soon as declareRecordItem returns, and the pointer returned by stm.c_str() is no longer valid. It is quite possible that the memory it now points to has been reused to hold some other object.
So if you want to retain the value of the string, you should either
return the std::string itself, relying on RVO for efficiency, or
create and return a dynamic object (i.e. new std::string()), or
make a C-style copy of the string buffer (i.e. strdup(stm.c_str()))
In both the latter two cases, you will need to manually free the copy once you are finished with it. In the first case, you will still need to make a copy of the underlying C string if you need to retain a C string.
Mixing C and C++ string handling is confusing and leads to cluttered code. If you are going to use C++, I recommend using std::string* throughout, although you end up with the same manual memory management regime as you would have with C style strings. For compilers and other applications with symbol tables, a good compromise is to put the string into the symbol table (or a map of immutable symbol names) as soon as possible, even in the lexical scanner, and then pass around references to the symbols (or interned names). Then you can free the entire repository of retained strings at the end of the compilation.
I repeadetly need to concatenate of format strings, and is wondering what is the shortest (or easiest to read) way to concatenate strings outside of the writefln() function, in D?
That is, I like the behaviour of writefln, where you can do for example:
// Some code to init y="2013", m="01", d="02" ...
writefln("%s-%s-%s", y, m, d);
... but I want to do this without writing it out on stdout. Is there an equally simple way?
The only think I found was the format function in std.string, but that requires you to provide string buffer of predefined length as the first argument, which is inconvenient most of the time.
The other alternative I found out was to do (by use of "join" in std.array):
// Some code to init y="2013", m="01", d="02" ...
datestr = [y, m, d].join("-");
... which is quite handy, but only works if you use the same "separator" of course.
Any more general way to do this, that is shorter than the above examples, and don't require providing a predefined-length buffer string?
You seem to confuse format with sformat. format does exactly what you want:
datestr = format("%s-%s-%s", y, m, d);
Even better: to catch potential mismatches between the format-string and the arguments, at compile-time instead of run-time:
datestr = format!"%s-%s-%s"(y, m, d);
The most basic way to concatenate strings would be with ~:
datestr = y ~ "-" ~ m ~ "-" ~ d;
More on that: http://dlang.org/arrays.html#array-concatenation