1:nrow(.) can't refer to former defined object with pipe %>%
Asked Answered
K

1

1

For some reason I wanted to run 1:nrow(.), where . refers to the dataframe defined before. It is something like this:

library(tidyverse)
data.frame(1:10) %>%
  1:nrow(.)

I get the error Error in :(., 1, nrow(.)) : 3 arguments passed to ':' which requires 2. But data.frame(1:10) %>% nrow(.) works as expected.

I tried to change rownames using {} in a pipe but it doesnt work:

data.frame(1:10) %>%
{rownames(.) <- letters[1:nrow(.)]}

I expected the result to be data.frame(1:10, row.names= letters[1:10]) but it is not.

Kelby answered 2/5, 2023 at 12:5 Comment(6)
Remembering that the pipe passes the object to its left as the first argument to the function on its right, what did you expect :(df, 1, nrow(df)) to do? You're mixing scalars and data frames in a way that is not at all obvious to resolve.Elihu
I'm not sure what your exact question is here (you didnt really explain if you want to know why this happens, or a workaround) but one workaround is: seq_len(data.frame(1:10) %>% nrow(.))Sneeze
@Elihu I dont understand why you write :(df, 1, nrow(df)). : works like i:j?Kelby
Look at your error message. : is a function. You've supplied two arguments, 1 and nrow(.). The pipe supplies a third, data.frame(1:10), which is inserted in the first position, resulting in a call with three parameters to a function which expects only two. Hence the error.Elihu
Maybe using seq is an option for you: data.frame(1:10) %>% {seq(1, nrow(.))}Axiology
@Elihu After reading your comment and the accepted answer multiple times I finally got there :-D Thanks!Kelby
W
3

Put it in { }.

data.frame(1:10) %>% {1:nrow(.)}
# [1]  1  2  3  4  5  6  7  8  9 10

Or use:

data.frame(1:10) %>% nrow %>% 1:.
# [1]  1  2  3  4  5  6  7  8  9 10

You are using the pipe for a nested call. Pipe:Using the dot for secondary purposes:

Often, some attribute or property of lhs is desired in the rhs call in addition to the value of lhs itself, e.g. the number of rows or columns. It is perfectly valid to use the dot placeholder several times in the rhs call, but by design the behavior is slightly different when using it inside nested function calls. In particular, if the placeholder is only used in a nested function call, lhs will also be placed as the first argument! The reason for this is that in most use-cases this produces the most readable code. For example, iris %>% subset(1:nrow(.) %% 2 == 0) is equivalent to iris %>% subset(., 1:nrow(.) %% 2 == 0) but slightly more compact. It is possible to overrule this behavior by enclosing the rhs in braces. For example, 1:10 %>% {c(min(.), max(.))} is equivalent to c(min(1:10), max(1:10)).


And for the second part of the question, you just update the rownames. To see the result add a ..

data.frame(1:10) %>% {rownames(.) <- letters[1:nrow(.)]; .}
#  X1.10
#a     1
#b     2
#c     3
#d     4
#e     5
#f     6
#g     7
#h     8
#i     9
#j    10
Wrongheaded answered 2/5, 2023 at 12:9 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.