0

I just started r about a week ago. In my directory, I have csv files named 001, 002,...010,...331. In my partial function below, the user is requested to enter id (e.g. 1:9). The id is then converted into 001, 002, 003,...009. However, if the user enters say 1:10 for the id, the function will output id [10] as "0010" instead of as "010". This causes the rest of my function to fail. Any suggestions on what might be going on? If I enter 1:10, I want to get 001, 002, 003, 004, 005, 006, 007, 008, 009 and 010.

pollutantmean <- function(directory, pollutant, id) {

    if((id>=1) && (id<10)) {
            fn <- paste("00",id,sep="")
            print(fn)
    } else if((id>=10) && (id<=99)) {
            fn <- paste("0",id,sep="")
            print(fn)
    } else {
            fn <- id
            print(fn)
    }

Please I don't want to use R apply function for this. I have not gotten that far.

Cerbrus
  • 70,800
  • 18
  • 132
  • 147
sedeh
  • 7,083
  • 6
  • 48
  • 65
  • 3
    You could save yourself a lot of time using `sprintf` - e.g. `sprintf("%03d",1:10)` – thelatemail May 13 '14 at 05:30
  • I just replaced all that with `fn <- sprintf("%03d",id)` and it worked like charm. This looks just like `System.out.printf` in Java. But any clue why my first method failed? I can't fathom it. And we've not been taught this sleek sprintf method in class which suggests my first method may still work with some tweaks. – sedeh May 13 '14 at 05:41

3 Answers3

3

This puts leading "0"'s to a width of 3 characters with the numeric values being taken as stings.

sprintf("%03s", 1:10)
 [1] "001" "002" "003" "004" "005" "006" "007" "008" "009" "010"
IRTFM
  • 258,963
  • 21
  • 364
  • 487
2

The problems is that you are using an if statement and the short circuiting && operator. In this case && will only look at the first element of the vector id and make a decision there. In this case (1>=1) && (1<10) so it executes that first block. Then you call fn <- paste("00",id,sep="") which is vectorized so it operates on the entire id vector so it adds '00' to every element. You seem to be treating the function like there is some implicit loop but there is not.

Of course @thelastemail's suggestion of fn <- sprintf("%03d",id) is the right one in this case, but just for the sake of discussion, your code could be re-written as

fn <- paste(ifelse(id<10, "00", ifelse(id<100, "0", "")),id,sep="")

because ifelse does have a kind of implied loop in that it can make different decisions for every element in the vector.

MrFlick
  • 195,160
  • 17
  • 277
  • 295
  • This also works. Great! Do you know how I can format to 3 decimal places without using sprintf? Sprintf outputs a string. I want an integer. – sedeh May 13 '14 at 06:33
  • @sedeh Well, first, integers don't have decimal places. And if you're worried about formatting, then it sounds like you do want a string. Otherwise, what's the difference between 010 and 10? The value you feed into sprintf is the "numeric" value, and what you get out is the formatted "character" value. – MrFlick May 13 '14 at 13:06
2

Your function is close but its only evaluating a single number id. I added a for loop to handle a range of numbers:

pollutantmean <- function(idrange) {
  for(id in idrange){
  if((id>=1) && (id<10)) {
    fn <- paste("00",id,sep="")
    print(fn)
  } else if((id>=10) && (id<=99)) {
    fn <- paste("0",id,sep="")
    print(fn)
  } else {
    fn <- id
    print(fn)
  }}
}

I removed the directory and pollutant arguments but they can easily be added back in. This function will evaluate all the numbers in the range of interest and print them out:

R> pollutantmean(1:10)
[1] "001"
[1] "002"
[1] "003"
[1] "004"
[1] "005"
[1] "006"
[1] "007"
[1] "008"
[1] "009"
[1] "010"
R> 
Stedy
  • 7,359
  • 14
  • 57
  • 77