6

Currently, I have

extract_modulo = function(x, n, fn=`[`) fn(x, (n-1L) %% length(x) + 1L)
`%[mod%` = function (x, n) extract_modulo(x, n)

And then:

seq(12) %[mod% 14
#[1] 2

Is this already built into R somewhere? I would think so, because R has several functions that recycle values (e.g., paste). However, I'm not finding anything with help('[['), ??index, or ??mod. I would think an R notation for this would be something like seq(12)[/14/] or as.list(seq(12))[[/14/]], for example.

Ana Nimbus
  • 635
  • 3
  • 16
  • The oarray package implements arrays with different offsets. – G. Grothendieck Oct 27 '17 at 00:56
  • I looked at the oarray package [documentation](https://cran.r-project.org/web/packages/Oarray/Oarray.pdf), but did not find the modulo indexing feature I am looking for. Perhaps I am overlooking it. Would @G.Grothendieck or another user care to point out what I am overlooking? – Ana Nimbus Oct 27 '17 at 16:10
  • My comment was that it implements offsets. – G. Grothendieck Oct 27 '17 at 16:14

1 Answers1

0

rep_len() is a fast .Internal function, and appropriate for this use or when recycling arguments in your own function. For this particular case, where you're looking for the value at an index position beyond the length of a vector, rep_len(x, n)[n] will always do what you're looking for, for any nonnegative whole number 'n', and any non NULL x.

rep_len(seq(12), 14)[14]
# [1] 2
rep_len(letters, 125)[125]
# [1] "u"

And if it turns out you didn't need to recycle x, it works just as fine with an n value that is less than length(x)

rep_len(seq(12), 5)[5]
# [1] 5
rep_len(seq(12), 0)[0]
# integer(0)
# as would be expected, there is nothing there

You could of course create a wrapper if you'd like:

recycle_index <- function(x, n) rep_len(x, n)[n]
recycle_index(seq(12), 14)
# [1] 2
De Novo
  • 7,120
  • 1
  • 23
  • 39
  • In using `rep_len` for modulo indexing, R appears to actually create the corresponding vector, which makes this method less and less memory efficient as the corresponding index increases. I suppose a variation of this technique could be faster (if it doesn't create and throw away the index vector too often), depending on the application and machine, since look-up is being used instead of modulo division. – Ana Nimbus Apr 10 '18 at 21:09
  • Also: 1) `rep_len` fails when a negative values is specified for the `length.out` argument, 2) modulo indexing when `n = 0` would fail when using the `rep_len` technique, because `rep_len` returns `integer(0)` when `length.out == 0`. – Ana Nimbus Mar 19 '21 at 16:15