Skip to content

silent recycling in logical indexing

7 messages · Ben Bolker, Charles C. Berry, William Dunlap

#
Sorry if this has been covered here somewhere in the past, but ...

  Does anyone know why logical vectors are *silently* recycled, even
when they are incommensurate lengths, when doing logical indexing?  This
is as documented:

  For ?[?-indexing only: ?i?, ?j?, ?...? can be logical
          vectors, indicating elements/slices to select.  Such vectors
          are recycled if necessary to match the corresponding extent.

but IMO weird:
[1]  TRUE FALSE

## (TRUE, FALSE) gets recycled to (TRUE,FALSE,TRUE) and selects
##  the first and third elements

If we do logical operations instead we do get a warning:
[1] TRUE TRUE TRUE
Warning message:
In x | y : longer object length is not a multiple of shorter object length

  Is it just too expensive to test for incomplete recycling when doing
subsetting, or is there a sensible use case for incomplete recycling?

  Ll. 546ff of main/src/subscript.c suggest that there is a place in the
code where we already know if incomplete recycling has happened ...

 Thoughts?

   cheers
     Ben Bolker
#
One use case is when you want to extract every third item, starting with
the second, of an arbitrary vector with
    x[c(FALSE, TRUE, FALSE)]
instead of
    x[seq_along(x) %% 3 == 2]

Bill Dunlap
TIBCO Software
wdunlap tibco.com
On Thu, Jan 4, 2018 at 11:56 AM, Ben Bolker <bbolker at gmail.com> wrote:

            

  
  
#
It is convenient to use a single `TRUE' in programmatic manipulation of subscripts in the same manner as using an empty subscript interactively:
[1] 0 2 0
[1] 0 2 0

HTH,

Chuck
#
Hmm.

Chuck: I don't see how this example represents
incomplete/incommensurate recycling. Doesn't TRUE replicate from
length-1 to length-3 in this case (mat[c(TRUE,FALSE),2] would be an
example of incomplete recycling)?

William: clever, but maybe too clever unless you really need the
speed? (The clever way is 8 times faster in the following case ...)

x <- rep(1,1e6)
rbenchmark::benchmark(x[c(FALSE,TRUE,FALSE)],x[seq_along(x) %% 3 == 2])

On the other hand, it takes 0.025 vs 0.003 seconds per iteration ...
fortunes::fortune("7ms")
On Thu, Jan 4, 2018 at 4:09 PM, Berry, Charles <ccberry at ucsd.edu> wrote:
#
PS I'm tempted to insert a warning at this point and see how often it
actually gets triggered ...
On Thu, Jan 4, 2018 at 4:44 PM, Ben Bolker <bbolker at gmail.com> wrote:
#
It doesn't. I took your subject line to be the theme of your posting and `incommensurate lengths' to be an instance used to emphasize how silent recycling might `bite' the user. 

Chuck
#
I have never used this construct.  However, part of my job is seeing how
well CRAN packages work in our reimplementation of the R language
and I am continually surprised by the inventiveness of package writers.

Bill Dunlap
TIBCO Software
wdunlap tibco.com
On Thu, Jan 4, 2018 at 1:44 PM, Ben Bolker <bbolker at gmail.com> wrote: