I would like to reverse an array with a jq function.
The jq function accepts a boolean that tells the function whether or not to reverse the array.
Strangely enough, this function is returning true instead of returning the (possibly sorted) array...
jq Filter
def reverseIfTrue($reverse):
if $reverse then reverse else . end;
reverseIfTrue(true)
json Input
["a","b"]
jq Output
true
jq snippet: https://jqplay.org/s/DMMUme_Qngi
The issue is that the name of the parameter is colliding with the name of the filter, essentially creating a local that obscures the global. Naming the parameter anything else will fix it:
def reverseIfTrue($rev):
if $rev then
reverse
else
.
end
;
Remember that filter parameters always create their non-variable aliases; def foo($bar): ... is documented to be the same as def foo(bar): bar as $bar | ....
Related
I am writing a custom User defined function in kusto where I want to have some optional parameters to the function which will be used in the "where" clause. I want to dynamically handle this. For example: If the value is present, then my where clause should consider that column filter, else it should not be included in the "where" clause>
Eg (psuedo code where value is not null):
function Calculate(string:test)
{
T | where test == test | order by timestamp
}
Eg (psuedo code where value is null or empty. My final query should look like this):
function Calculate(string:test)
{
T | order by timestamp
}
What is the efficient way to implement this. I will call this function from my c# class.
you can define a function with a default value for its argument, and use the logical or operator and the isempty() function to implement the condition you've described.
for example:
(note: the following is demonstrated using a let statement, but can be applied similarly to stored functions)
let T = range x from 1 to 5 step 1 | project x = tostring(x)
;
let F = (_x: string = "") {
T
| where isempty(_x) or _x == x
| order by x desc
}
;
F("abc")
if you run F() or F("") (i.e. no argument, or an empty string as the argument) - it will return all values 1-5.
if you run F("3") - it will return a single record with the value 3.
if you run F("abc") - it will return no records.
I have a for loop and want to filter some nodes, which works fine:
matches($doc/abc/#def, $filterA)
matches($doc/qwert/#xyz, $filterB)
What also works is, when $filterA, $filterB or both are empty, to return every node. What does not work however is to return the node if node abc or qwert do not exist. For the default value i currently use "" (empty string), is there another default value or another function I can use to make it work?
You can test whether the abc and qwert elements exist with the fn:exists() function. If you want it to pass if either of those elements do not exist, you can use fn:not() to negate a test for abc and qwert existence:
fn:not(fn:exists($doc/abc) and fn:exists($doc/qwert))
If you want a condition to pass if either $filterA or $filterB is empty:
fn:not(fn:exists($filterA) and fn:exists($filterB))
You can consolidate the matches() expressions a predicate to avoid repeating $doc (not a huge savings, but something to think of more generally when writing XPath expressions.
$doc[matches(abc/#def, $filterA) and matches(qwert/#xyz, $filterB)]
Putting it all together:
let $filterA := "a"
let $filterB :="b"
let $doc := <doc><abc def="a"/><qwert xyz="b"/></doc>
return
if (fn:not(fn:exists($doc/abc) and fn:exists($doc/qwert))
or fn:not(fn:exists($filterA) and fn:exists($filterB))
or $doc[matches(abc/#def, $filterA) and matches(qwert/#xyz, $filterB)])
then "pass - copy nodes"
else "fail"
let memoize (sequence: seq<'a>) =
let cache = Dictionary()
seq {for i in sequence ->
match cache.TryGetValue i with
| true, v -> printf "cached"
| false,_ -> cache.Add(i ,i)
}
I will call my memoize function inside this function :
let isCached (input:seq<'a>) : seq<'a> = memoize input
If the given sequence item is cached it should print cached otherwise it will continue to add sequence value to cache.
Right now I have problems with types.
When I try to call my function like this :
let seq1 = seq { 1 .. 10 }
isCached seq1
It throws an error
"The type int does not match the type unit"
I want my function to work generic even though I return printfn. Is it possible to achieve that? And while adding value to the cache is it appropriate to give the same value to tuple?
eg:
| false,_ -> cache.Add(i ,i)
I think the problem is that your memoize function does not actually return the item from the source sequence as a next element of the returned sequence. Your version only adds items to the cache, but then it returns unit. You can fix that by writing:
let memoize (sequence: seq<'a>) =
let cache = Dictionary()
seq {for i in sequence do
match cache.TryGetValue i with
| true, v -> printf "cached"
| false,_ -> cache.Add(i ,i)
yield i }
I used explicit yield rather than -> because I think that makes the code more readable. With this change, the code runs as expected for me.
Tomas P beat me to the punch, but I'll post this up anyway just in case it helps.
I'm not too sure what you are trying to achieve here, but I'll say a few things that I think might help.
Firstly, the type error. Your isCached function is defined as taking a seq of type 'a, and returning a seq of type 'a. As written in your question, right now it takes a seq of type 'a, and returns a sequence of type unit. If you try modifying the output specification to seq<'b> (or actually just omitting it altogether and letting type inference do it), you should overcome the type error. This probably still won't do what you want, since you aren't actually returning the cache from that function (you can just add cache as the final line to return it). Thus, try something like:
let memoize (sequence: seq<'a>) =
let cache = Dictionary()
for i in sequence do
match cache.TryGetValue i with
| true, v -> printf "cached"
| false,_ -> cache.Add(i ,i)
cache
let isCached (input:seq<'a>) : seq<'b> = memoize input
All this being said, if you are expecting to iterate over the same sequence a lot, it might be best just to use the library function Seq.cache.
Finally, with regards to using the value as the key in the dictionary... There's nothing stopping you from doing that, but it's really fairly pointless. If you already have a value, then you shouldn't need to look it up in the dictionary. If you are just trying to memoize the sequence, then use the index of the given element as the key. Or use the specific input as the key and the output from that input as the value.
I have note.xml:
<?xml version="1.0"?>
<note>
<to>Tove</to>
<from>Jani</from>
<heading>Reminder</heading>
<body>Don't forget me this weekend!</body>
</note>
and note.xqy:
let $srcDoc:="note.xml"
for $x in doc($srcDoc)/note
return (),
for $x in doc($srcDoc)/note
return ()
For some reasons I need two fors to process note.xml. I don't want to write the processed file name two times, so I define a variable. Strange is, the variable is not defined in the second for:
$ zorba -i -f -q note.xqy
note.xqy>:5,15: static error [err:XPST0008]: "srcDoc": undeclared variable
A let-bound variable in XQuery is only in scope inside the FLWOR expression it is defined in. In your case that is everything before the comma.
Since FLWOR expressions can be nested, one solution would be to split the let into it an enclosing expression and put both loops into the return:
let $srcDoc:="note.xml"
return (
for $x in doc($srcDoc)/note
return (),
for $x in doc($srcDoc)/note
return ()
)
Since you bind a constant at the start of your XQuery script, you can also use declare variable, which only works in that case:
declare variable $srcDoc := "note.xml";
for $x in doc($srcDoc)/note
return (),
for $x in doc($srcDoc)/note
return ()
I want to pass my returned list into case but I'm getting the
"->" Error
Here is my code:
parse ( Element, [] ) -> false;
parse(Element,N) -> re:split(N,"([*+])",[{return,list}]),
parse ( Element, [ Item | ListTail ] ) ->
case ( Item == Element ) of
true -> true;
false -> listFind(Element, ListTail)
end.
I don't know how to pass the returned list into the case, Can anyone help?
If you want to test the result of re:split/3 in a case, you need to get rid of the extraneous function head stuck inside the second clause of parse/2. You also don't need the first clause of parse/2, as it's unnecessary and not used. Just look through the result of re:split/3 for Element, like this:
parse(Element, N) ->
Elements = re:split(N,"([*+])",[{return,list}]),
lists:member(Element, Elements).
If for example the argument N has the value "a*b+c*d+e", the re:split/3 call returns ["a","*","b","+","c","*","d","+","e"] (and let's assume that's really what you want). The call to lists:member/2 then searches that result for the value of Element, returning true if found or false if not found.