Question

I need to generate a "sane" sequence so as to populate a gcombobox() from gWidgets2. The widget deals with the number of rows from a data frame, which will be subset via head(). So the sequence is fine to begin from 5 (not necessarily from 1) and to span in "intelligent" steps until nrow(DF).

I came up with the following implementation:

sane_steps <- function(x){
  if(x<50){
    res <- seq.int(5, x, 5)
  } else if(x<100){
    res <- c(seq.int(5, 49, 5), seq.int(50, x, 10))
  } else if(x<1000){
    res <- c(seq.int(5, 49, 5), seq.int(50, 99, 10), seq.int(100, x, 100))
  } else if(x<10000){
    res <- c(seq.int(5, 49, 5), seq.int(50, 99, 10), seq.int(100, 999, 100), 
             seq.int(1000, x, 1000))
  } else {
    res <- c(seq.int(5, 49, 5), seq.int(50, 99, 10), seq.int(100, 999, 100), 
             seq.int(1000, 9999, 1000), seq.int(10000, x, 10000))
  }
  if(!any(res %in% x)) res <- c(res, x)
  return(res)
}

So that:

> sane_steps(99)
 [1]  5 10 15 20 25 30 35 40 45 50 60 70 80 90 99
> sane_steps(523)
 [1]   5  10  15  20  25  30  35  40  45  50  60  70  80  90 100 200 300 400 500 523
> sane_steps(4548)
 [1]    5   10   15   20   25   30   35   40   45   50   60   70   80   90  100  200
[17]  300  400  500  600  700  800  900 1000 2000 3000 4000 4548
> sane_steps(27304)
 [1]     5    10    15    20    25    30    35    40    45    50    60    70    80
[14]    90   100   200   300   400   500   600   700   800   900  1000  2000  3000
[27]  4000  5000  6000  7000  8000  9000 10000 20000 27304

Is there a more efficient way to define sane_steps()? And is there perhaps an existing R function that facilitates generating such "sane" sequences?

Était-ce utile?

La solution

You could pre-create the sequence manually and subset.

sane_steps <- (function() {
  master_seq <- unlist(lapply(seq_len(.Machine$double.digits), function(x) {
    by <- 10^x
    seq(by, 10*by, by)
  }))
  master_seq <- c(seq(5, 50, 5), master_seq[-seq_len(5)])
  function(y) c(master_seq[master_seq < y], y)
})()

Example

> sane_steps(99)
 [1]  5 10 15 20 25 30 35 40 45 50 60 70 80 90 99
> sane_steps(523)
 [1]   5  10  15  20  25  30  35  40  45  50  60  70  80  90 100 100 200 300 400 500 523
> sane_steps(4548)
 [1]    5   10   15   20   25   30   35   40   45   50   60   70   80   90  100  100  200  300  400  500  600  700  800  900 1000 1000 2000 3000 4000
[30] 4548
> sane_steps(27304)
 [1]     5    10    15    20    25    30    35    40    45    50    60    70    80    90   100   100   200   300   400   500   600   700   800   900
[25]  1000  1000  2000  3000  4000  5000  6000  7000  8000  9000 10000 10000 20000 27304

Autres conseils

Based on the accepted answer, I came up with a slightly tweaked version:

seq_sane <- (function(){
  master_seq <- unlist(lapply(seq_len(.Machine$double.digits), function(x){
    by <- 10^x
    seq.int(by, 10*by-1, by)
  }))
  master_seq <- c(seq.int(1, 4, 1), seq.int(5, 50, 5), master_seq[-seq_len(5)])
  function(y) c(master_seq[master_seq < y], y)
})()
#lapply(c(9,10,11,49,50,51,99,100,101,999,1000,1001,9999,10000,10001,385744), seq_sane)
#lapply(c(99,523,4548,27304), seq_sane)

This:

  • chooses a more appropriate name
  • fixes a bug where the by elements in the output were double (e.g. 100, 1000, etc.)
  • uses seq.int which should be faster
  • it also allows for values smaller than 5 (expands the scope of the original question)
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top