R remove redundant parentheses from formula string or expression - string

I have many formula strings similar to this:
str <- "( (( A ) * J ) - (( J ) * G ) ) / Z "
There are many parentheses which don't need to be there, (A*J - J*G)/Z is sufficient. Is there a function or package in R that can take care of this?
I tried functions for R expressions and as well as.formula but did not find what I need.

We can use R parser to do the job. The trick is that R knows when parentheses are needed based on the parse tree, so we can simply remove them from the tree:
See this:
simplify <- function(e)
{
if( mode(e) %in% c("name","numeric") ) return(e)
op <- as.character(e[[1]])
if( op == "(" ) return(simplify(e[[2]]))
if( op %in% c("+","-","*","/","^") ) return(call(op, simplify(e[[2]]), simplify(e[[3]])))
}
simplifytext <- function(s) deparse(simplify(parse(text=s)[[1]]))
Inputs:
str <- "( (( A ) * J ) - (( J ) * G ) ) / Z "
str2 <- gsub("-", "/", gsub("*", "+", str, fixed=TRUE))
Results:
> str2
[1] "( (( A ) + J ) / (( J ) + G ) ) / Z "
> simplifytext(str)
[1] "(A * J - J * G)/Z"
> simplifytext(str2)
[1] "(A + J)/(J + G)/Z"

Here are a couple of approaches:
R parsing
rmParen <- function(e) {
if (length(e) > 1) {
if (identical(e[[1]], as.symbol("("))) e <- e[[2]]
if (length(e) > 1) for (i in 1:length(e)) e[[i]] <- Recall(e[[i]])
}
e
}
s <- "( (( A ) * J ) - (( J ) * G ) ) / Z "
rmParen(parse(text = s)[[1]])
The last line returns:
(A * J - J * G)/Z
This works in all cases I tried but you might want to test it out a bit more.
If you want a character string as the return value then use deparse as in deparse(rmParen(parse(text = s)[[1]])). Note that deparse has a width.cutoff argument which is set to 60 by default but can be set to be larger if the actual expressions exceed that length.
Ryacas
library(Ryacas)
s <- "( (( A ) * J ) - (( J ) * G ) ) / Z "
Simplify(s)
The last line returns:
expression((A - G) * J/Z)
Note that its actually the print method that invokes the computation so if you want to save it then try yacas(Simplify(s))$text or as.character(yacas(Simplify(s))) .
ADDED: Ryacas solution.

Related

Problem with spec block in literate haskell file

I have this block of code on my literate haskell file
\end{code}
\paragraph{Valorização}
Codigo em C
\begin{spec}
double co(double x, int n){
double a = 1;
double b = -1 * x * x / 2;
double c = 12;
double d = 18;
for(; n > 0; n--){
a = a + b;
b = b * (-1 * x * x) / c;
c = c + d;
d = 8 + d;
}
return a;
}
\end{spec}
\subsection*{Problema 4}
What's happening is, when using lhs2tex and the pdflatex, what's inside the spec block is being completely ignored, and everything after it is forward, like it has a tab before it... Maybe this is something common? I'm not used to this... First time using it
By the way, if I remove the spec block everything else is formatted correctly
The following answer is based on speculation. If you would provide an MCVE—a short .lhs file that clearly demonstrates the issue—perhaps a better answer could emerge.
I think the issue is that lhs2TeX is not meant for C code. It gets confused by the spec block, thinks that it is Haskell code, and outputs problematic TeX commands. In fact, I can't even get your posted code past pdflatex—the .tex is that broken. You can use a different mechanism to output C code. The minted package should do.
\documentclass{article}
%include lhs2TeX.fmt
\usepackage{minted}
\setlength{\parindent}{0pt}
\begin{document}
Some C code:
\begin{minted}{c}
double co(double x, int n){
double a = 1;
double b = -1 * x * x / 2;
double c = 12;
double d = 18;
for(; n > 0; n--){
a = a + b;
b = b * (-1 * x * x) / c;
c = c + d;
d = 8 + d;
}
return a;
}
\end{minted}
It can be directly translated into Haskell:
\begin{code}
co :: Double -> Int -> Double
co x = worker 1 (-1 * x * x / 2) 12 18
where worker a _ _ _ 0 = a
worker a b c d n = worker (a + b) (b * (-1 * x * x) / c) (c + d) (8 + d) (n - 1)
\end{code}
As you can see, \textit{Haskell} code passes through just fine.
\end{document}
PS: The weird for-loop can be written while(n-- > 0) { ... }, no?

Intersect of two planes - divide by zero

I have following alghoritm to find line intersection of two planes:
public static function getIntersectOf2Planes ( self $P1 , self $P2 )
{
/* Line equation in parametric form:
x = x0 + t*a
y = y0 + t*b
z = z0 + t*c
*/
$x0 = ( $P1->B * $P2->D - $P2->B * $P1->D ) / ( $P1->A * $P2->B - $P2->A * $P1->B ) ;
$a = ( $P1->B * $P2->C - $P2->B * $P1->C );
$y0 = ( $P2->A * $P1->D - $P1->A * $P2->D ) / ( $P1->A * $P2->B - $P2->A * $P1->B ) ;
$b = ( $P2->A * $P1->C - $P1->A * $P2->C );
$z0 = 0;
$c = ( $P1->A * $P2->B - $P2->A * $P1->B );
$IntersectionLine = new Line3D( $x0, $a, $y0, $b, $z0, $c );
return $IntersectionLine;
}
and it works fine, but to compute $x0 and $y0 i have to divide by:
( $P1->A * $P2->B - $P2->A * $P1->B )
and in some cases, the value of this expression is equal to zero, so I get an "dividing by zero" error :(
What should I do in this case?
I know, that the case when this expression is equal to zero, doesn't mean that there is no intersection, because it's happen when I have planes perpendicular to one of the axies.
For example for:
Plane1:
A = 0
B = 0
C = 100
D = 0
Plane2:
A = 50
B = 0
C = 0
D = -250
so the equation of line should exists.
PS I wrote this code with a view to:
https://math.stackexchange.com/questions/2766615/line-by-two-planes-intersection?noredirect=1#comment5706281_2766615
In short, you have to implement the intersection algorithm for the case when (a1*b2 - a2*b1) = 0 (ie. when the planes are not independent when you set z=0).
To expand on that, first we need to understand how you got this far. First let us write down the equation of two planes:
a1x + b1y + c1z + d1 = 0
and
a2x + b2y + c2z + d2 = 0
When two planes intersect, the intersection is a line. So, the most usual way to solve that is by finding a point first on such a line and then figuring out its orientation (a, b, c) in your case. The orientation is a straight forward cross product. The intersection point is typically calculated by setting one of the co-ordinates to 0 and then solving the 2 linear equations that you get. In your code, this is done by setting:
z = 0
But this only works when the equations
a1x + b1y + d1 = 0 and a2x + b2y + d2 = 0
are capable of giving a solution for x and y, which is not the case when a1b2-a2b1=0. So In such cases, you can solve the same by setting either x or y to 0 which again gives two linear equations that you can solve to obtain a point on the line. Then you can compute the parametric form much like how you did. For example (setting y to 0):
x0 = (c1d2 - c2d1)/(a1c2 - a2c1)
y0 = 0
z0 = (a2d1 - a1d2)/(a1c2 - a2c1)
But for this to be a defined value you need to have (a1c2 - a2c1) to be non-zero. Does this help?

Getting all strings in a lua script

I'm trying to encode some strings in my lua script, and since that I have a lua script with over 200k characters, encrypting each string query in the script with a function such as this example below
local string = "stackoverflow"
local string = [[stackoverflow]]
local string = [==[stackoverflow]==]
local string = 'stackoverflow'
to
local string=decode("jkrtbfmviwcfn",519211)
Trying to provide all above results to thread through a gsub and have the gsub encode the string text with a random offset number.
So far, I was only capable of gsubbing full quotation marks through.
function encode(x,offset,a)
for char in string.gmatch(x, "%a") do
local encrypted = string.byte(char) + offset
while encrypted > 122 do
encrypted = encrypted - 26
end
while encrypted < 97 do
encrypted = encrypted + 26
end
a[#a+1] = string.char(encrypted)
end
return table.concat(a)
end
luacode=[==[thatstring.Value="Encryptme!" testvalue.Value=[[string with
a linebreak]] string.Text="STOP!"]==]
luacode=luacode:gsub([=["(.-)"]=],function(s)
print("Caught "..s)
local offset=math.random(1,4)
local encoded=encode(s,offset,{})
return [[decode("]]..encoded..[[",]]..offset..[[)]]
end)
print("\n"..luacode)
With its output being
Caught Encryptme!
Caught STOP!
thatstring.Value=decode("crgvctxqi",4) testvalue.Value=[[string with
a linebreak]] string.Text=decode("opkl",2)
Any better solutions?
local function strings_and_comments(lua_code, callback)
-- lua_code must be valid Lua code (an error may be raised on syntax error)
-- callback will be invoked as callback(object_type, value, start_pos, end_pos)
-- callback("comment", comment_text, start_pos, end_pos) -- for comments
-- callback("string", string_value, start_pos, end_pos) -- for string literals
local objects = {} -- possible comments and string literals in the code
-- search for all start positions of comments (with false positives)
for pos, br1, eq, br2 in lua_code:gmatch"()%-%-(%-*%[?)(=*)(%[?)" do
table.insert(objects, {start_pos = pos,
terminator = br1 == "[" and br2 == "[" and "]"..eq.."]" or "\n"})
end
-- search for all start positions of string literals (with false positives)
for pos, eq in lua_code:gmatch"()%[(=*)%[[%[=]*" do
table.insert(objects, {is_string = true, start_pos = pos,
terminator = "]"..eq.."]"})
end
for pos, quote in lua_code:gmatch"()(['\"])" do
table.insert(objects, {is_string = true, start_pos = pos, quote = quote})
end
table.sort(objects, function(a, b) return a.start_pos < b.start_pos end)
local end_pos = 0
for _, object in ipairs(objects) do
local start_pos, ok, symbol = object.start_pos
if start_pos > end_pos then
if object.terminator == "\n" then
end_pos = lua_code:find("\n", start_pos + 1, true) or #lua_code
-- exclude last spaces and newline
while lua_code:sub(end_pos, end_pos):match"%s" do
end_pos = end_pos - 1
end
elseif object.terminator then
ok, end_pos = lua_code:find(object.terminator, start_pos + 1, true)
assert(ok, "Not a valid Lua code")
else
end_pos = start_pos
repeat
ok, end_pos, symbol = lua_code:find("(\\?.)", end_pos + 1)
assert(ok, "Not a valid Lua code")
until symbol == object.quote
end
local value = lua_code:sub(start_pos, end_pos):gsub("^%-*%s*", "")
if object.terminator ~= "\n" then
value = assert((loadstring or load)("return "..value))()
end
callback(object.is_string and "string" or "comment", value, start_pos, end_pos)
end
end
end
local inv256
local function encode(str)
local seed = math.random(0x7FFFFFFF)
local result = '",'..seed..'))'
if not inv256 then
inv256 = {}
for M = 0, 127 do
local inv = -1
repeat inv = inv + 2
until inv * (2*M + 1) % 256 == 1
inv256[M] = inv
end
end
repeat
seed = seed * 3
until seed > 2^43
local K = 8186484168865098 + seed
result = '(decode("'..str:gsub('.',
function(m)
local L = K % 274877906944 -- 2^38
local H = (K - L) / 274877906944
local M = H % 128
m = m:byte()
local c = (m * inv256[M] - (H - M) / 128) % 256
K = L * 21271 + H + c + m
return ('%02x'):format(c)
end
)..result
return result
end
function hide_strings_in_lua_code(lua_code)
local text = { [[
local function decode(str, seed)
repeat
seed = seed * 3
until seed > 2^43
local K = 8186484168865098 + seed
return (str:gsub('%x%x',
function(c)
local L = K % 274877906944 -- 2^38
local H = (K - L) / 274877906944
local M = H % 128
c = tonumber(c, 16)
local m = (c + (H - M) / 128) * (2*M + 1) % 256
K = L * 21271 + H + c + m
return string.char(m)
end
))
end
]] }
local pos = 1
strings_and_comments(lua_code,
function (object_type, value, start_pos, end_pos)
if object_type == "string" then
table.insert(text, lua_code:sub(pos, start_pos - 1))
table.insert(text, encode(value))
pos = end_pos + 1
end
end)
table.insert(text, lua_code:sub(pos))
return table.concat(text)
end
Usage:
math.randomseed(os.time())
-- This is the program to be converted
local luacode = [===[
print"Hello world!"
print[[string with
a linebreak]]
local str1 = "stackoverflow"
local str2 = [[stackoverflow]]
local str3 = [==[stackoverflow]==]
local str4 = 'stackoverflow'
print(str1)
print(str2)
print(str3)
print(str4)
]===]
-- Conversion
print(hide_strings_in_lua_code(luacode))
Output (converted program)
local function decode(str, seed)
repeat
seed = seed * 3
until seed > 2^43
local K = 8186484168865098 + seed
return (str:gsub('%x%x',
function(c)
local L = K % 274877906944 -- 2^38
local H = (K - L) / 274877906944
local M = H % 128
c = tonumber(c, 16)
local m = (c + (H - M) / 128) * (2*M + 1) % 256
K = L * 21271 + H + c + m
return string.char(m)
end
))
end
print(decode("ef869b23b69b7fbc7f89bbe7",2686976))
print(decode("c2dc20f7061c452db49302f8a1d9317aad1009711e0984",1210253312))
local str1 = (decode("84854df4599affe9c894060431",415105024))
local str2 = (decode("a5d7db792f0b514417827f34e3",1736704000))
local str3 = (decode("6a61bcf9fd6f403ed1b4846e58",1256259584))
local str4 = (decode("cad56d9dea239514aca9c8b8e0",1030488064))
print(str1)
print(str2)
print(str3)
print(str4)
Output of output (output produced by the converted program)
Hello world!
string with
a linebreak
stackoverflow
stackoverflow
stackoverflow
stackoverflow

How do you sort and efficiently find elements in a cell array (of strings) in Octave?

Is there built-in functionality for this?
GNU Octave search a cell array of strings in linear time O(n):
(The 15 year old code in this answer was tested and correct on GNU Octave 3.8.2, 5.2.0 and 7.1.0)
The other answer has cellidx which was depreciated by octave, it still runs but they say to use ismember instead, like this:
%linear time string index search.
a = ["hello"; "unsorted"; "world"; "moobar"]
b = cellstr(a)
%b =
%{
% [1,1] = hello
% [2,1] = unsorted
% [3,1] = world
% [4,1] = moobar
%}
find(ismember(b, 'world')) %returns 3
ismember finds 'world' in index slot 3. This is a expensive linear time O(n) operation because it has to iterate through all elements whether or not it is found.
To achieve a logarathmic time O(log n) solution, then your list needs to come pre-sorted and then you can use binary search:
If your cell array is already sorted, you can do O(log-n) worst case:
function i = binsearch(array, val, low, high)
%binary search algorithm for numerics, Usage:
%myarray = [ 30, 40, 50.15 ]; %already sorted list
%binsearch(myarray, 30, 1, 3) %item 30 is in slot 1
if ( high < low )
i = 0;
else
mid = floor((low + high) / 2);
if ( array(mid) > val )
i = binsearch(array, val, low, mid-1);
elseif ( array(mid) < val )
i = binsearch(array, val, mid+1, high);
else
i = mid;
endif
endif
endfunction
function i = binsearch_str(array, val, low, high)
% binary search for strings, usage:
%myarray2 = [ "abc"; "def"; "ghi"]; #already sorted list
%binsearch_str(myarray2, "abc", 1, 3) #item abc is in slot 1
if ( high < low )
i = 0;
else
mid = floor((low + high) / 2);
if ( mystrcmp(array(mid, [1:end]), val) == 1 )
i = binsearch(array, val, low, mid-1);
elseif ( mystrcmp(array(mid, [1:end]), val) == -1 )
i = binsearch_str(array, val, mid+1, high);
else
i = mid;
endif
endif
endfunction
function ret = mystrcmp(a, b)
%this function is just an octave string compare, its behavior follows the
%strcmp(str1,str2)'s in C and java.lang.String.compareTo(...)'s in Java,
%that is:
% -returns 1 if string a > b
% -returns 0 if string a == b
% -return -1 if string a < b
% The gt() operator does not support cell array. If the single word
% is passed as an one-element cell array, converts it to a string.
a_as_string = a;
if iscellstr( a )
a_as_string = a{1}; %a was passed as a single-element cell array.
endif
% The gt() operator does not support cell array. If the single word
% is passed as an one-element cell array, converts it to a string.
b_as_string = b;
if iscellstr( b )
b_as_string = b{1}; %b was passed as a single-element cell array.
endif
% Space-pad the shortest word so as they can be used with gt() and lt() operators.
if length(a_as_string) > length( b_as_string )
b_as_string( length( b_as_string ) + 1 : length( a_as_string ) ) = " ";
elseif length(a_as_string) < length( b_as_string )
a_as_string( length( a_as_string ) + 1 : length( b_as_string ) ) = " ";
endif
letters_gt = gt(a_as_string, b_as_string); %list of boolean a > b
letters_lt = lt(a_as_string, b_as_string); %list of boolean a < b
ret = 0;
%octave makes us roll our own string compare because
%strings are arrays of numerics
len = length(letters_gt);
for i = 1:len
if letters_gt(i) > letters_lt(i)
ret = 1;
return
elseif letters_gt(i) < letters_lt(i)
ret = -1;
return
endif
end;
endfunction
%Assuming that myarray is already sorted, (it must be for binary
%search to finish in logarithmic time `O(log-n))` worst case, then do
myarray = [ 30, 40, 50.15 ]; %already sorted list
binsearch(myarray, 30, 1, 3) %item 30 is in slot 1
binsearch(myarray, 40, 1, 3) %item 40 is in slot 2
binsearch(myarray, 50, 1, 3) %50 does not exist so return 0
binsearch(myarray, 50.15, 1, 3) %50.15 is in slot 3
%same but for strings:
myarray2 = [ "abc"; "def"; "ghi"]; %already sorted list
binsearch_str(myarray2, "abc", 1, 3) %item abc is in slot 1
binsearch_str(myarray2, "def", 1, 3) %item def is in slot 2
binsearch_str(myarray2, "zzz", 1, 3) %zzz does not exist so return 0
binsearch_str(myarray2, "ghi", 1, 3) %item ghi is in slot 3
To sort your array if it isn't already:
Complexity of sorting depends on the kind of data you have and whatever sorting algorithm GNU octave language writers selected, it's somewhere between O(n*log(n)) and O(n*n).
myarray = [ 9, 40, -3, 3.14, 20 ]; %not sorted list
myarray = sort(myarray)
myarray2 = [ "the"; "cat"; "sat"; "on"; "the"; "mat"]; %not sorted list
myarray2 = sortrows(myarray2)
Code buffs to make this backward compatible with GNU Octave 3. 5. and 7. goes to #Paulo Carvalho in the other answer here.
Yes check this: http://www.obihiro.ac.jp/~suzukim/masuda/octave/html3/octave_36.html#SEC75
a = ["hello"; "world"];
c = cellstr (a)
⇒ c =
{
[1,1] = hello
[2,1] = world
}
>>> cellidx(c, 'hello')
ans = 1
>>> cellidx(c, 'world')
ans = 2
The cellidx solution does not meet the OP's efficiency requirement, and is deprecated (as noted by help cellidx).
Håvard Geithus in a comment suggested using the lookup() function on a sorted cell array of strings, which is significantly more efficient than cellidx. It's still a binary search though, whereas most modern languages (and even many 20 year old ones) give us easy access to associative arrays, which would be a much better approach.
While Octave doesn't obviously have associated arrays, that's effectively what the interpreter is using for ocatve's variables, including structs, so you can make us of that, as described here:
http://math-blog.com/2011/05/09/associative-arrays-and-cellular-automata-in-octave/
Built-in Function: struct ("field", value, "field", value,...)
Built-in Function: isstruct (expr)
Built-in Function: rmfield (s, f)
Function File: [k1,..., v1] = setfield (s, k1, v1,...)
Function File: [t, p] = orderfields (s1, s2)
Built-in Function: fieldnames (struct)
Built-in Function: isfield (expr, name)
Function File: [v1,...] = getfield (s, key,...)
Function File: substruct (type, subs,...)
Converting Matlab to Octave is there a containers.Map equivalent? suggests using javaObject("java.util.Hashtable"). That would come with some setup overhead, but would be a performance win if you're using it a lot. It may even be viable to link in some library written in C or C++? Do think about whether this is a maintainable option though.
Caveat: I'm relatively new to Octave, and writing this up as I research it myself (which is how I wound up here). I haven't yet run tests on the efficiency of these techniques, and while I've got a fair knowledge of the underlying algorithms, I may be making unreasonable assumptions about what's actually efficient in Octave.
This is a version of mystrcmp() that works in Octave of recent version (7.1.0):
function ret = mystrcmp(a, b)
%this function is just an octave string compare, its behavior follows the
%strcmp(str1,str2)'s in C and java.lang.String.compareTo(...)'s in Java,
%that is:
% -returns 1 if string a > b
% -returns 0 if string a == b
% -return -1 if string a < b
% The gt() operator does not support cell array. If the single word
% is passed as an one-element cell array, converts it to a string.
a_as_string = a;
if iscellstr( a )
a_as_string = a{1}; %a was passed as a single-element cell array.
endif
% The gt() operator does not support cell array. If the single word
% is passed as an one-element cell array, converts it to a string.
b_as_string = b;
if iscellstr( b )
b_as_string = b{1}; %b was passed as a single-element cell array.
endif
% Space-pad the shortest word so as they can be used with gt() and lt() operators.
if length(a_as_string) > length( b_as_string )
b_as_string( length( b_as_string ) + 1 : length( a_as_string ) ) = " ";
elseif length(a_as_string) < length( b_as_string )
a_as_string( length( a_as_string ) + 1 : length( b_as_string ) ) = " ";
endif
letters_gt = gt(a_as_string, b_as_string); %list of boolean a > b
letters_lt = lt(a_as_string, b_as_string); %list of boolean a < b
ret = 0;
%octave makes us roll our own string compare because
%strings are arrays of numerics
len = length(letters_gt);
for i = 1:len
if letters_gt(i) > letters_lt(i)
ret = 1;
return
elseif letters_gt(i) < letters_lt(i)
ret = -1;
return
endif
end;
endfunction

Use character string as function argument

I'm sure this is simple, but I cannot find a solution ...
I would like to use a variable containing a character string as argument for a function.
x <- c(1:10)
myoptions <- "trim=0, na.rm=FALSE"
Now, something like
foo <- mean(x, myoptions)
should be the same as
foo <- mean(x, trim=0, na.rm=FALSE)
Thanks in advance!
You can use eval and parse:
foo <- eval(parse(text = paste("mean(x,", myoptions, ")")))
A more natural way to do what you want is to use do.call. For example,
R> l[["trim"]] = 0
R> l[["na.rm"]] = FALSE
R> l[["x"]] = 1:10
##Or l <- list(trim = 0, na.rm = FALSE, x = 1:10)
R> do.call(mean, l)
[1] 5.5
If for some reason you really want to use a myoptions string, you could always use strsplit to coarce it into a list form. For example,
R> y = "trim=0, na.rm=FALSE"
R> strsplit(y, ", ")
[[1]]
[1] "trim=0" "na.rm=FALSE"
R> strsplit(y, ", ")[[1]][1]
[1] "trim=0"
Here's a third answer that both uses parse, alist and do.call. My motivation for this new answer, is in the case where arguments are passed interactively from a client-side as chars. Then I guess, there is no good way around not using parse. Suggested solution with strsplit, cannot understand the context whether a comma , means next argument or next argument within an argument. strsplit does not understand context as strsplit is not a parser.
here arguments can be passed as "a=c(2,4), b=3,5" or list("c(a=(2,4)","b=3","5")
#' convert and evaluate a list of char args to a list of arguments
#'
#' #param listOfCharArgs a list of chars
#'
#' #return
#' #export
#'
#' #examples
#' myCharArgs = list('x=c(1:3,NA)',"trim=0","TRUE")
#' myArgs = callMeMaybe(myCharArgs)
#' do.call(mean,myArgs)
callMeMaybe2 = function(listOfCharArgs) {
CharArgs = unlist(listOfCharArgs)
if(is.null(CharArgs)) return(alist())
.out = eval(parse(text = paste0("alist(",
paste(parse(text=CharArgs),collapse = ","),")")))
}
myCharArgs = list('x=c(1:3,NA)',"trim=0","TRUE")
myArgs = callMeMaybe2(myCharArgs)
do.call(mean,myArgs)
[1] 2
Using all of do.call, eval and parse (combining kohske's and csgillespie's answers, and also WoDoSc's answer to 'Pass a comma separated string as a list'):
x <- c(1:10)
myoptions <- "trim = 0, na.rm = FALSE"
do.call(
what = mean,
args = append(list(x = x), eval(parse(text = paste0("list(", myoptions, ")"))))
)
This solution can be quite resilient in a more complex case, such as shown below.
myfn <- function(x, y = 0, z = 0, ...) {
print(paste("x:", x))
print(paste("y:", y))
print(paste("z:", z))
if (length(list(...)) > 0) {
print("other:")
print(list(...))
}
}
myextraargs <- paste(
"y = c(11, 14), z = 47,",
"t = data.frame(p = c('apple', 'plum'), j = c(7, 2), k = c(3, 21))"
)
do.call(
what = myfn,
args = append(
list(x = 7),
eval(parse(text = paste0("list(", myextraargs, ")")))
)
)
results in:
[1] "x: 7"
[1] "y: 11" "y: 14"
[1] "z: 47"
[1] "other:"
$t
p j k
1 apple 7 3
2 plum 2 21
...and...
myextraargs <- NULL
do.call(
what = myfn,
args = append(
list(x = 7),
eval(parse(text = paste0("list(", myextraargs, ")")))
)
)
results in
[1] "x: 7"
[1] "y: 0"
[1] "z: 0"

Resources