17

While looking at an answer posted recently on SO, I noticed an unfamiliar assignment statement. Instead of the usual form of myVar<- myValue, it used the form myVar[]<- myValue, i.e. the object on lefthand side is indexed with empty square brackets. Personally, I had never seen such an assignment, but it had a highly useful effect-- it reshaped the assigned data 'myValue' to the shape of 'myVar'.

I would like to use this in my code as this makes things lot easier. However the documentation for "<-" seems to be silent on it.

Is this a well established feature and one can rely on it to work in all cases?

Also, my guess is that it might be a side effect of a function call stack, i.e. calling <- and [ in sequence, but I could not figure out how. Can someone throw some light on that?

Here's an example--

# A dataframe
df1 <- data.frame(a = 1:4, b = 11:14)

# simple assignment assigns to class of RHS
df1 <- c(21:24, 31:34)
df1 
#[1] 21 22 23 24 31 32 33 34
class(df1)
#[1] "integer"

#assignment with [] casts to class of LHS 
df1<- data.frame(a = 1:4, b = 11:14)
df1[]<- c(21:24,31:34)
df1

#    a  b
# 1 21 31
# 2 22 32
# 3 23 33
# 4 24 34


# recycling to preserve shape
df1[]<- c(101:102)
df1

#     a   b
# 1 101 101
# 2 102 102
# 3 101 101
# 4 102 102

class(df1)
#data.frame

# reshaping 

df1<- data.frame(a = 1:4, b = 11:14)
df1[] <- matrix(1:8, 2,4)
df1 #matrix reshaped 
class(df1)
#[1] "data.frame"

# flattening 
x<- 1:8
x[] <- matrix(1:8,4,2)
x
#[1] 1 2 3 4 5 6 7 8
R.S.
  • 2,093
  • 14
  • 29
  • 3
    Some hints: check out `?Extract` and try running `'[<-'(df1,,,8:1)` – joran Dec 16 '16 at 20:14
  • @joran : yes.. that seems to be where i should have looked. Many thanks. I'd look at it and revert tomorrow . well past late here.. – R.S. Dec 16 '16 at 20:30
  • 3
    You can dig out the logic from `body("[<-.data.frame")` if you feel inclined, but it's not a pleasant function to read through. What you are asking about will be the case where `i` and `j` are both missing in the function call. – nrussell Dec 16 '16 at 22:13
  • My apologies to all the kind folks taking interest in my question. Been unable able to give your suggestions enough time because of some unforeseens . Will look up and post what I find as soon as I can. -R.S. – R.S. Dec 18 '16 at 17:50

1 Answers1

7

This is an intentional and documented feature. As joran mentioned, the documentation page "Extract" includes this in the "Atomic Vectors" section:

An empty index selects all values: this is most often used to replace all the entries but keep the attributes.

However, in the case of recursive objects (data.frames or lists, for example), the attributes are only kept for the subsetted object. Its parts don't get such protection.

Here's an example:

animals <- factor(c('cat', 'dog', 'fish'))
df_factor <- data.frame(x = animals)
rownames(df_factor) <- c('meow', 'bark', 'blub')
str(df_factor)
# 'data.frame': 3 obs. of  1 variable:
#   $ x: Factor w/ 3 levels "cat","dog","fish": 1 2 3

df_factor[] <- 'cat'
str(df_factor)
# 'data.frame': 3 obs. of  1 variable:
#   $ x: chr  "cat" "cat" "cat"
rownames(df_factor)
# [1] "meow" "bark" "blub"

df_factor kept its rownames attribute, but the x column is just the character vector used in the assignment instead of a factor. We can keep the class and levels of x by specifically replacing its values:

df_factor <- data.frame(x = animals)
df_factor$x[] <- 'cat'
str(df_factor)
# 'data.frame': 3 obs. of  1 variable:
#   $ x: Factor w/ 3 levels "cat","dog","fish": 1 1 1

So replacement with empty subsetting is very safe for vectors, matrices, and arrays, because their elements can't have their own attributes. But it requires some care when dealing with list-like objects.

Nathan Werth
  • 5,093
  • 18
  • 25
  • 1
    Thanks for the great reply. I had seen that line from documented that you had highlighted and it seemed to suggest (to me) that the operation was very safe , but I had examples to the contrary. The remark that `sub-parts will get no such protection` puts the finger on it, and the example deals with it. The only other point I would like to add (which is actually inherent in this reply ) is that this operation is reliable only when LHS is more complex than RHS – R.S. Jul 14 '17 at 23:41