5

I'm having an issue in R where I can run an ifelse statement on elements in a list, but as soon as I place the ifelse statement within the lapply function, it no longer works.

Here's my example. I'm working with a list of three dataframes:

> dflist
[[1]]
  ID1 tID1
1  m1    1
2  m2    2
3  m3    3
4  m4    4
5  m5    5

[[2]]
  ID2 tID2
1  m7    7
2  m8    8
3  m9    9
4 m10   10
5 m11   11

[[3]]
  ID3 tID3
1 m13   13
2 m14   14
3 m15   15
4 m16   16
5 m17   17
6 m18   18

If a dataframe has an odd number of rows, I want R to label it "ODD". If the dataframe has an even number of rows, I just want R to output the same dataframe. I would like the output to be a list.

This works when I write standalone ifelse statements:

> ifelse(nrow(dflist[[1]])%%2==!0, "ODD", dflist[1])
[1] "ODD"

> ifelse(nrow(dflist[[3]])%%2==!0, "ODD", dflist[3])
[[1]]
  ID3 tID3
1 m13   13
2 m14   14
3 m15   15
4 m16   16
5 m17   17
6 m18   18

But I get an error message as soon I put it into an lapply statement.

> lapply(dflist, function(x) ifelse(nrow(dflist[[x]])%%2==!0, "ODD", dflist[x]))

 Error in dflist[[x]] : invalid subscript type 'list' 
> 

Any ideas for why this happens and how to fix it? Thank you

dcossyleon
  • 115
  • 2
  • 7
  • Did you meant to name it? – akrun Apr 06 '17 at 15:07
  • I think you meant to do `lapply(seq_along(dflist), ...)` – Shape Apr 06 '17 at 15:10
  • @akrun - that worked perfectly. thanks! I'm not sure how, but I'm glad it did. – dcossyleon Apr 06 '17 at 18:05
  • @dcoss The reason is that you are checking whether the nrow is odd or even and the output for that logical condition is of length 1. For those cases, `if/else` can be used. `ifelse` is used when the length is greater than 1. – akrun Apr 07 '17 at 05:09

2 Answers2

6

If we need to return either "ODD" or dataset, then use if/else

lapply(dflist, function(x) if(nrow(x)%%2==1) "ODD" else x)

data

dflist <- list(data.frame(col1 = 1:3, col2=4:6), data.frame(col1=1:4, col2=5:8))
akrun
  • 874,273
  • 37
  • 540
  • 662
3

When you use lapply, you then just reference the parameter of the anonymous function, rather than your original list name. So instead of doing:

  lapply(dflist, function(x) ifelse(nrow(dflist[[x]])%%2==!0, "ODD", dflist[x]))

You just need to change to reference the list items you are putting in the function, i.e. "x"; so it should be:

 lapply(dflist, function(x) ifelse(nrow(x)%%2==!0, "ODD", x))
  • 1
    Ok, that mostly works except that it output is a bit weird: it outputs as a list within a list, which is not such a big deal. But in the case where the dataframe has even rows, and it just needs to return the same dataframe, it is returning only the first column of that dataframe as a vector with many levels – dcossyleon Apr 06 '17 at 15:35
  • So then if you just want to identify the dataframes that have an even number of rows, why not just use filter in the way of Filter(function(x){nrow(x) %%2 == 0}, dflist) – SolomonRoberts Apr 07 '17 at 15:58