How to remove duplicate results from a cts:uris when distinct values does not work - duplicates

I have the following code that returns an array of array of results I try to use distinct-values to remove duplicates and it does nothing I have tried also removing using looping functions by comparing values with no success.
I have tried converting to "xs anyAtomicType" and using distinct values
I have tried putting in json array and extracting the sub-array
I have tried tokenizing, xdmp quote, string-before/after and many others
declare function local:verify-user-uri($dir as xs:string)
{
for $each in cts:uris($dir, ())
let $uIds := (for $d in $each
where contains($d, "/profile.xml")
return $d)
return $uIds
};
I get back duplicated result in form of:
/users/123-343-/profile.xml
/users/122-222-/profile.xml
/users/123-343-/profile.xml
/users/122-222-/profile.xml
/users/123-343-/profile.xml
/users/122-222-/profile.xml
I am expecting:
/users/123-343-/profile.xml
/users/122-222-/profile.xml

Is it possible that you have simply invoked this function 3 times and didn't realize it?
You have declared $dir to be a single xs:string. If your $dir happened to be a sequence of strings of the same directory, or if you otherwise invoked the function 3 times with the directory variable.
It can easily happen with function mapping enabled (default behavior). https://docs.marklogic.com/guide/xquery/enhanced#id_55459
There are a couple of things that you can do as a diagnostic:
1.) Remove the explicit type on the $dir parameter in the function:
declare function local:verify-user-uri($dir)
{
for $each in cts:uris($dir, ())
let $uIds := (for $d in $each
where contains($d, "/profile.xml")
return $d)
return $uIds
};
do you get an error executing cts:uris() that looks like this:
[1.0-ml] XDMP-ARGTYPE: )err:XPT0004) cts:uris(("/users/", "/users/", "/users/"), ()) -- arg1 is not of type xs:string?
2.) try disabling function mapping by adding the following to the prolog:
declare option xdmp:mapping "false";
and see if you then get an invalid coercion error like:
[1.0-ml] XDMP-AS (err:XPTY0004) $dir as xs:string -- Invalid coersion ("/users/", "/users/", "/users/") as xs:string
3.) You could also add something to the end of the sequence of values returned from the function to indicate how many times it has executed:
declare function local:verify-user-uri($dir as xs:string)
{
for $each in cts:uris($dir, ())
let $uIds := (for $d in $each
where contains($d, "/profile.xml")
return $d)
return $uIds, "#"
};
And see how many times you see "#" in the result. If more than one, you are invoking the function multiple times.

Next to the good suggestions from Mads, I notice a couple of other things about your code:
It doesn't make sense to iterate over $each as it contains one uri only. Keep in mind that a FLWOR statement ends with a return, which tells what should be the result per item
Beware that the first arg to cts:uris only marks a start, not an end. If you feed in /aaa/, you also get back /bbb/ etc, though not vice versa.
To be honest, I think you are looking for cts:uri-match() instead, which would reduce your function to a one-liner:
declare function local:verify-user-uri($dir as xs:string) {
cts:uri-match($dir || "*/profile.xml")
};
HTH!
PS: I do recommend always disabling function mapping as Mads recommends. It can prevent a lot of confusion.

Related

How to collect attributes and values in function

I am trying do this:
I want to do function which receives
one node as a parameter. and I it should return a string.
so I need to loop node and I don't know more details,
but I want to concatenate a new json type of string
and returns it.
but seems to be difficult, because I don't know xquery well.
my idea is
declare function local:Do_the_thing($my_node as node()*) as xs:string{
for ($element at $col in (attribute_list($my_node))
let $complete_row_information := concat ("test", "test2");
return $complete_row_information
}
can someone say me, what is going wrong and how to fix it?
if this thing is not in a function it works

How to implement a basic Lua function in Conky?

I am trying to add a function to my Conky which prints the length of a string for debug purposes. The code, inside a file called test.lua, is pretty trivial:
function test(word)
return string.len(word)
end
...and I load it like this. In my conky.config section I have:
lua_load = '/home/xvlaze/test.lua',
lua_draw_hook_pre = 'test'
...in the conky.text section I have:
${lua test "fooo"}
...where test is the name of the function and fooo the string to test.
The expected result should be a printed 4 in Conky, but instead of that I get:
conky: llua_do_call: function conky_test execution failed: /home/xvlaze/test.lua:2: attempt to index a nil value (local 'string')
conky: llua_getstring: function conky_test didn't return a string, result discarded
I have browsed through the documentation, but I can't find anything. Does anybody know where the failure is?
Several guidances on how to implement functions in Conky:
First of all: YOU MUST USE conky_ BEFORE YOUR FUNCTION'S NAME.
Otherwise, you will get the following error when running your Conky:
attempt to call a nil value
Secondly: YOU MUST ALWAYS RETURN A VALUE.
I don't mind repeating it - it is crucial. Otherwise, you will get:
function foobar didn't return a string, result discarded
function_result
...in your terminal, and your Conky will be left empty of values related to your extra code. Nothing will be printed regarding your function.
Last but not least: YOU MUST ALWAYS CALL YOUR FUNCTION LIKE:
lua_load = '/path/to/function.lua',
-- Whatever content...
${lua function_name function_parameter1 function_parameterN} -- In case you use more than one parameter.
In summary, a dummy function template could be:
MAIN FILE (conky.conf):
conky.config = {
-- Whatever content... Lua styled comments.
lua_load = '/path/to/function.lua',
}
conky.text = [[
# Whatever content... In this section comments are started with '#'!
${lua function_name parameter}
]]
FUNCTION FILE:
function conky_function_name(parameter)
-- Whatever content... Remember this is Lua, not conky.text syntax. Always use '--' comments!
return whatever -- No return, no party. A function MUST always return something!
end

lua not modifying function arguments

I've been learning lua and can't seem to make a simple implementation of this binary tree work...
function createTree(tree, max)
if max > 0 then
tree = {data = max, left = {}, right = {}}
createTree(tree.left, max - 1)
createTree(tree.right, max - 1)
end
end
function printTree(tree)
if tree then
print(tree.data)
printTree(tree.left)
printTree(tree.right)
end
end
tree = {}
createTree(tree, 3)
printTree(tree)
the program just returns nil after execution. I've searched around the web to understand how argument passing works in lua (if it is by reference or by value) and found out that some types are passed by reference (like tables and functions) while others by value. Still, I made the global variable "tree" a table before passing it to the "createTree" function, and I even initialized "left" and "right" to be empty tables inside of "createTree" for the same purpose. What am I doing wrong?
It is probably necessary to initialize not by a new table, but only to set its values.
function createTree(tree, max)
if max > 0 then
tree.data = max
tree.left = {}
tree.right = {}
createTree(tree.left, max - 1)
createTree(tree.right, max - 1)
end
end
in Lua, arguments are passed by value. Assigning to an argument does not change the original variable.
Try this:
function createTree(max)
if max == 0 then
return nil
else
return {data = max, left = createTree(max-1), right = createTree(max-1)}
end
end
It is safe to think that for the most of the cases lua passes arguments by value. But for any object other than a number (numbers aren't objects actually), the "value" is actually a pointer to the said object.
When you do something like a={1,2,3} or b="asda" the values on the right are allocated somewhere dynamically, and a and b only get addresses of those. Thus, when you pass a to the function fun(a), the pointer is copied to a new variable inside function, but the a itself is unaffected:
function fun(p)
--p stores address of the same object, but `p` is not `a`
p[1]=3--by using the address you can
p[4]=1--alter the contents of the object
p[2]=nil--this will be seen outside
q={}
p={}--here you assign address of another object to the pointer
p=q--(here too)
end
Functions are also represented by pointers to them, you can use debug library to tinker with function object (change upvalues for example), this may affect how function executes, but, once again, you can not change where external references are pointing.
Strings are immutable objects, you can pass them around, there is a library that does stuff to them, but all the functions in that library return new string. So once, again external variable b from b="asda" would not be affected if you tried to do something with "asda" string inside the function.

golang return multiple values issue

I was wondering why this is valid go code:
func FindUserInfo(id string) (Info, bool) {
it, present := all[id]
return it, present
}
but this isn't
func FindUserInfo(id string) (Info, bool) {
return all[id]
}
is there a way to avoid the temporary variables?
To elaborate on my comment, the Effective Go mentions that the multi-value assignment from accessing a map key is called the "comma ok" pattern.
Sometimes you need to distinguish a missing entry from a zero value. Is there an entry for "UTC" or is that the empty string because it's not in the map at all? You can discriminate with a form of multiple assignment.
var seconds int
var ok bool
seconds, ok = timeZone[tz]
For obvious reasons this is called the “comma ok” idiom. In this example, if tz is present, seconds will be set appropriately and ok will be true; if not, seconds will be set to zero and ok will be false.
Playground demonstrating this
We can see that this differs from calling a regular function where the compiler would tell you that something is wrong:
package main
import "fmt"
func multiValueReturn() (int, int) {
return 0, 0
}
func main() {
fmt.Println(multiValueReturn)
asgn1, _ := multiValueReturn()
asgn2 := multiValueReturn()
}
On the playground this will output
# command-line-arguments
/tmp/sandbox592492597/main.go:14: multiple-value multiValueReturn() in single-value context
This gives us a hint that it may be something the compiler is doing. Searching the source code for "commaOk" gives us a few places to look, including types.unpack
At the time of writing this it this the method's godoc reads:
// unpack takes a getter get and a number of operands n. If n == 1, unpack
// calls the incoming getter for the first operand. If that operand is
// invalid, unpack returns (nil, 0, false). Otherwise, if that operand is a
// function call, or a comma-ok expression and allowCommaOk is set, the result
// is a new getter and operand count providing access to the function results,
// or comma-ok values, respectively. The third result value reports if it
// is indeed the comma-ok case. In all other cases, the incoming getter and
// operand count are returned unchanged, and the third result value is false.
//
// In other words, if there's exactly one operand that - after type-checking
// by calling get - stands for multiple operands, the resulting getter provides
// access to those operands instead.
//
// If the returned getter is called at most once for a given operand index i
// (including i == 0), that operand is guaranteed to cause only one call of
// the incoming getter with that i.
//
The key bits of this being that this method appears to determine whether or not something is actually a "comma ok" case.
Digging into that method tells us that it will check to see if the mode of the operands is indexing a map or if the mode is set to commaok (where this is defined does give us many hints on when it's used, but searching the source for assignments to commaok we can see it's used when getting a value from a channel and type assertions). Remember the bolded bit for later!
if x0.mode == mapindex || x0.mode == commaok {
// comma-ok value
if allowCommaOk {
a := [2]Type{x0.typ, Typ[UntypedBool]}
return func(x *operand, i int) {
x.mode = value
x.expr = x0.expr
x.typ = a[i]
}, 2, true
}
x0.mode = value
}
allowCommaOk is a parameter to the function. Checking out where unpack is called in that file we can see that all callers pass false as an argument. Searching the rest of the repository leads us to assignments.go in the Checker.initVars() method.
l := len(lhs)
get, r, commaOk := unpack(func(x *operand, i int) { check.expr(x, rhs[i]) }, len(rhs), l == 2 && !returnPos.IsValid())
Since it seems that we can only use the "comma ok" pattern to get two return values when doing a multi-value assignment this seems like the right place to look! In the above code the length of the left hand side is checked, and when unpack is called the allowCommaOk parameter is the result of l == 2 && !returnPos.IsValid(). The !returnPos.IsValid() is somewhat confusing here as that would mean that the position has no file or line information associated with it, but we'll just ignore that.
Further down in that method we've got:
var x operand
if commaOk {
var a [2]Type
for i := range a {
get(&x, i)
a[i] = check.initVar(lhs[i], &x, returnPos.IsValid())
}
check.recordCommaOkTypes(rhs[0], a)
return
}
So what does all of this tell us?
Since the unpack method takes an allowCommaOk parameter that's hardcoded to false everywhere except in assignment.go's Checker.initVars() method, we can probably assume that you will only ever get two values when doing an assignment and have two variables on the left-hand side.
The unpack method will determine whether or not you actually do get an ok value in return by checking if you are indexing a slice, grabbing a value from a channel, or doing a type assertion
Since you can only get the ok value when doing an assignment it looks like in your specific case you will always need to use variables
You may save a couple of key strokes by using named returns:
func FindUserInfo(id string) (i Info, ok bool) {
i, ok = all[id]
return
}
But apart from that, I don't think what you want is possible.
Simply put: the reason why your second example isn't valid Go code is because the language specification says so. ;)
Indexing a map only yields a secondary value in an assignment to two variables. Return statement is not an assignment.
An index expression on a map a of type map[K]V used in an assignment or initialization of the special form
v, ok = a[x]
v, ok := a[x]
var v, ok = a[x]
yields an additional untyped boolean value. The value of ok is true if the key x is present in the map, and false otherwise.
Furthermore, indexing a map is not a "single call to a multi-valued function", which is one of the three ways to return values from a function (the second one, the other two not being relevant here):
There are three ways to return values from a function with a result type:
The return value or values may be explicitly listed in the "return" statement. Each expression must be single-valued and assignable to the corresponding element of the function's result type.
The expression list in the "return" statement may be a single call to a multi-valued function. The effect is as if each value returned from that function were assigned to a temporary variable with the type of the respective value, followed by a "return" statement listing these variables, at which point the rules of the previous case apply.
The expression list may be empty if the function's result type specifies names for its result parameters. The result parameters act as ordinary local variables and the function may assign values to them as necessary. The "return" statement returns the values of these variables.
As for your actual question: the only way to avoid temporary variables would be using non-temporary variables, but usually that would be quite unwise - and probably not much of an optimization even when safe.
So, why doesn't the language specification allow this kind of special use of map indexing (or type assertion or channel receive, both of which can also utilize the "comma ok" idiom) in return statements? That's a good question. My guess: to keep the language specification simple.
I'm no Go expert but I believe you are getting compile time error when you are trying to return the array i.e. return all[id]. The reason could be because the functions return type is specially mentioned as (Info, bool) and when you are doing return all[id] it can't map the return type of all[id] to (Info, bool).
However the solution mentioned above, the variables being returned i and ok are the same that are mentioned in the return type of the function (i Info, ok bool) and hence the compiler knows what it's returning as opposed to just doing (i Info, ok bool).
By default, maps in golang return a single value when accessing a key
https://blog.golang.org/go-maps-in-action
Hence, return all[id] won't compile for a function that expects 2 return values.

subfunctions in vim

I created a lot of functions in menu.vim.
I noted that in many functions the same code is used that's why I decided to clean up my file with the use of
subfunctions.
p.e this is code what often returns in my functions:
let zoek = #/
if a:type == "'<,'>"
let r = substitute(zoek, '\\%V', '', 'g')
elseif a:type == "%"
let r = zoek
endif
let a = substitute(r, '\', '', 'g')
if matchstr(d, '>') == '>' || matchstr(d, '<') == '<'
let e = substitute(d, '\zs>\(\d\+\)%<\ze', '\1-', 'g')
endif
How can I create a subfunction from it? How can I invoke it?
Does Vim have subfunctions?
You can have «local» functions by defining them in the dictionary: in the following code
function MyFunc()
let d={}
function d.function()
echo "Foo"
endfunction
call d.function()
endfunction
function d.function is accessible only inside s:MyFunc and is destroyed after s:MyFunc exits. I put «local» in quotes because d.function is really global function named 42 (or another number, it does not matter). It cannot be called without a reference to it and the only way to create a reference is to use function dict.key() (references may be copied after creation, but you can't create a reference using call to function(), though it is possible for MyFunc: function("MyFunc")). Note that number (in this case 42) is incremented each time you create a function and I know neither what is the maximum number nor what will happen when it will be reached. I personally use dictionary functions because they have two other advantages:
Dictionary function defined inside a script-local dictionary cannot be reached without a debugger or explicit passing the function reference (possibly as a part of its container) somewhere.
If more then one function is defined inside a dictionary in order to purge them all you need is to unlet this dictionary. Useful for reloading plugins.
There is only one type of function in Vimscript, but I'm not sure if this is what you are already using in your menu.vim. A user-defined function is defined thus:
function! MyNewFunction()
" your code here
endfunction
You can then call this function elsewhere in your scripts (and inside other functions) using
call MyNewFunction()
Or set a variable equal to the return value of your function using
let my_variable = MyNewFunction()
Of course this is an incredibly simplistic overview, since you say your are already using functions. Much more information, including the use of variables, here:
help user-functions
Apologies if I have not answered your question.