[Rd] suggestion: "." in [lsv]apply()

Sokol Serguei @oko| @end|ng |rom |n@@-tou|ou@e@|r
Thu Apr 16 20:02:17 CEST 2020


Thanks Henrik,

Probably, it will be the solution I'll retain.

Best,
Serguei.

Le 16/04/2020 à 18:50, Henrik Bengtsson a écrit :
> I'm sure this exists elsewhere, but, as a trade-off, could you achieve
> what you want with a separate helper function F(expr) that constructs
> the function you want to pass to [lsv]apply()?  Something that would
> allow you to write:
>
> sapply(split(mtcars, mtcars$cyl), F(summary(lm(mpg ~ wt,.))$r.squared))
>
> Such an F() function would apply elsewhere too.
>
> /Henrik
>
> On Thu, Apr 16, 2020 at 9:30 AM Michael Mahoney
> <mike.mahoney.218 using gmail.com> wrote:
>> This syntax is already implemented in the {purrr} package, more or
>> less -- you need to add a tilde before your function call for it to
>> work exactly as written:
>>
>> purrr::map_dbl(split(mtcars, mtcars$cyl), ~ summary(lm(wt ~ mpg, .))$r.squared)
>>
>> is equivalent to
>>
>> sapply(split(mtcars, mtcars$cyl), function(d) summary(lm(mpg ~ wt,
>> d))$r.squared)
>>
>> Seems like using this package is probably an easier solution for this
>> wish than adding a reserved variable and adding additional syntax to
>> the apply family as a whole.
>>
>> Thanks,
>>
>> -Mike
>>
>>> From: Sokol Serguei <sokol using insa-toulouse.fr>
>>> Date: Thu, Apr 16, 2020 at 12:03 PM
>>> Subject: Re: [Rd] suggestion: "." in [lsv]apply()
>>> To: William Dunlap <wdunlap using tibco.com>
>>> Cc: r-devel <r-devel using r-project.org>
>>>
>>>
>>> Thanks Bill,
>>>
>>> Clearly, my first proposition for wsapply() is quick and dirty one.
>>> However, if "." becomes a reserved variable with this new syntax,
>>> wsapply() can be fixed (at least for your example and alike) as:
>>>
>>> wsapply=function(l, fun, ...) {
>>>       .=substitute(fun)
>>>       if (is.name(.) || is.call(.) && .[[1]]==as.name("function")) {
>>>           sapply(l, fun, ...)
>>>       } else {
>>>           sapply(l, function(d) eval(., list(.=d)), ...)
>>>       }
>>> }
>>>
>>> Will it do the job?
>>>
>>> Best,
>>> Serguei.
>>>
>>> Le 16/04/2020 à 17:07, William Dunlap a écrit :
>>>> Passing in a function passes not only an argument list but also an
>>>> environment from which to get free variables. Since your function
>>>> doesn't pay attention to the environment you get things like the
>>>> following.
>>>>
>>>>> wsapply(list(1,2:3), paste(., ":", deparse(s)))
>>>> [[1]]
>>>> [1] "1 : paste(., \":\", deparse(s))"
>>>>
>>>> [[2]]
>>>> [1] "2 : paste(., \":\", deparse(s))" "3 : paste(., \":\", deparse(s))"
>>>>
>>>> Bill Dunlap
>>>> TIBCO Software
>>>> wdunlap tibco.com <http://tibco.com>
>>>>
>>>>
>>>> On Thu, Apr 16, 2020 at 7:25 AM Sokol Serguei <sokol using insa-toulouse.fr
>>>> <mailto:sokol using insa-toulouse.fr>> wrote:
>>>>
>>>>      Hi,
>>>>
>>>>      I would like to make a suggestion for a small syntactic
>>>>      modification of
>>>>      FUN argument in the family of functions [lsv]apply(). The idea is to
>>>>      allow one-liner expressions without typing "function(item) {...}" to
>>>>      surround them. The argument to the anonymous function is simply
>>>>      referred
>>>>      as ".". Let take an example. With this new feature, the following call
>>>>
>>>>      sapply(split(mtcars, mtcars$cyl), function(d) summary(lm(mpg ~ wt,
>>>>      d))$r.squared)
>>>>      #        4         6         8
>>>>      #0.5086326 0.4645102 0.4229655
>>>>
>>>>
>>>>      could be rewritten as
>>>>
>>>>      sapply(split(mtcars, mtcars$cyl), summary(lm(mpg ~ wt, .))$r.squared)
>>>>
>>>>      "Not a big saving in typing" you can say but multiplied by the
>>>>      number of
>>>>      [lsv]apply usage and a neater look, I think, the idea merits to be
>>>>      considered.
>>>>      To illustrate a possible implementation, I propose a wrapper
>>>>      example for
>>>>      sapply():
>>>>
>>>>      wsapply=function(l, fun, ...) {
>>>>           s=substitute(fun)
>>>>           if (is.name <http://is.name>(s) || is.call(s) &&
>>>>      s[[1]]==as.name <http://as.name>("function")) {
>>>>               sapply(l, fun, ...) # legacy call
>>>>           } else {
>>>>               sapply(l, function(d) eval(s, list(.=d)), ...)
>>>>           }
>>>>      }
>>>>
>>>>      Now, we can do:
>>>>
>>>>      wsapply(split(mtcars, mtcars$cyl), summary(lm(mpg ~ wt, .))$r.squared)
>>>>
>>>>      or, traditional way:
>>>>
>>>>      wsapply(split(mtcars, mtcars$cyl), function(d) summary(lm(mpg ~ wt,
>>>>      d))$r.squared)
>>>>
>>>>      the both work.
>>>>
>>>>      How do you feel about that?
>>>>
>>>>      Best,
>>>>      Serguei.
>>>>
>>>>      ______________________________________________
>>>>      R-devel using r-project.org <mailto:R-devel using r-project.org> mailing list
>>>>      https://stat.ethz.ch/mailman/listinfo/r-devel
>>>>
>>>
>>>          [[alternative HTML version deleted]]
>>>
>>> ______________________________________________
>>> R-devel using r-project.org mailing list
>>> https://stat.ethz.ch/mailman/listinfo/r-devel
>> ______________________________________________
>> R-devel using r-project.org mailing list
>> https://stat.ethz.ch/mailman/listinfo/r-devel



More information about the R-devel mailing list