Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Surprising result with data.frame subset using dot #121

Open
jordansread opened this issue Mar 24, 2016 · 8 comments
Open

Surprising result with data.frame subset using dot #121

jordansread opened this issue Mar 24, 2016 · 8 comments

Comments

@jordansread
Copy link

Hi, apologies if this is user error or my misuse of the package.

I have simplified something I ran into to a very small reproducible example. Without the context, it probably doesn't make much sense why I would be doing this in the first place, but I hope that doesn't matter.

I have x, and want to return 'a.special.key:

x = data.frame(key='a.special.key', stringsAsFactors = FALSE)

I would expect the following to return "a.special.key"

x %>% .$key[1]

but instead, it returns NA

I don't quite understand what order the eval is actually happening here, because both x$key[1] and x[1]$key would return the proper text.

digging into it, it seems the eval is

x[x$key, 1]

which is NA

I am thinking I am just misusing the pipe and dot in this context (probably instead should x%>% .[1,'key']) but I thought the behavior was a bit unexpected and the documentation didn't mention a gotcha like this

Is this worth noting in the documentation? Maybe in {magrittr}?

@timelyportfolio
Copy link

I think proper form would be to include in {}, so something like this

x %>% {.$key[1]}

or the very ugly

x %>% `$`('key') %>% `[`(1)

@jordansread
Copy link
Author

ahh, that is a good solution. works for a list too, thanks

@timelyportfolio
Copy link

I probably should have included the aliases use_series and extract also for a complete list. These aliases are designed specifically for this.

x %>% use_series('key') %>% extract(1)

I also caught an error in the answer above in the very ugly. I changed it to properly read.

x %>% `$`('key') %>% `[`(1)

@smbache
Copy link
Member

smbache commented Mar 24, 2016

Or even

x %$% key[1]

@rundel
Copy link

rundel commented Apr 5, 2016

I just had a student run into a similar issue trying to convert latitude and longitudes. The following code produces the "wrong" output

c(48,52) %>% sum(.[1], .[2]/60)   
##  [1] 148.8667

as it appears to be evaluating sum(c(48,52), c(48,52)[1], c(48,52)[2]/60) instead of sum(c(48,52)[1], c(48,52)[2]/60). Wrapping the 2nd expression in {'s, as described above, does fix things

c(48,52) %>% {sum(.[1], .[2]/60)}
##  [1] 48.86667

but this seems like very counter-intuitive behavior from magrittr.

@abelborges
Copy link

@rundel if I understood well the rules of the magrittr's main pipe operator, when you do

x %>% f

the interpreter will take x to be the first argument of the f call. The reason your second implementation works is that you used the magrittr "short implementation" of anonymous functions. This could be done with

c(48, 52) %>% (function(x) sum(x[1], x[2]/60))

as well.

I'm sorry for any misunderstanding and would be grateful for any corrections.

@franknarf1
Copy link

I ran into this today. A simple example:

1:3 %>% .[-1][-1]
# Error in .[.[-1], -1] : incorrect number of dimensions
1:3 %>% { .[-1][-1] }
# [1] 3

My real problem is in data.table, where if I assign in a chain, I need to ask the object to print twice before I'll see it in the console. The usual approach is to add a [] on the end of the chain, but that breaks here without the {}. Here's my full example:

library(data.table)
list(a = 1, b = 2) %>% stack %>% 
  setDT %>% setnames(c("v", "id")) %>% .[, id := as.character(id)] %>% print

I'd prefer to use the [] approach rather than wrap in {} or add print, if that's possible.

@smbache
Copy link
Member

smbache commented Nov 11, 2016

The "issue" is how the parser interpretes the calls to [. Really, it's the fact that magrittr will understand data %>% .[i, j] that is not obvious, and as your output shows, when multiple [][] are used, the precedence of operations are messed up. You can do this:

1:3 %>% .[-1] %>% .[-1]

and the other example:

list(a = 1, b = 2) %>% stack %>% 
    setDT %>% setnames(c("v", "id")) %>% .[, id := as.character(id)] %>% .[]

Whether that's preferable to an explicit print is debatable (just realized how much my brain wants to read "debatable" as "datatable").
In fact, I'm currently "fighting" myself a bit on how magrittr should treat these special operators in the next version, as any special rule would mess up this style:data %>% [(i, j). Since [ is just a function, this would not be desirable to break.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

6 participants