10

What i want to have is a matrix in which each element is a list itself. See the following example:

1       2       3
1  1,2,4  1,2      1
2  Null   3,4,5,6  1,3  

I saw this post, and tried the following but got an error :

 b <- array()
 b[j, i, ] <- A[i]

where A is a vector itself. The error was:

 Error in b[j, i, ] <- A[i] : incorrect number of subscripts

How should I define and access each element of the matrix and each element of the contained lists?

Update1 :

b<-matrix(list(),nrow = length(d), ncol =length(c))

Error in b[j, i] <- A[i] : replacement has length zero

I want to specify that each element is a list and then try to fill it with various list with different length from zero to n.

Update2 :

 running what @BondedDust commented :
 b<-matrix(rep(list(),(c*d)),,nrow = length(d), ncol =length(c))
 Erorr in b[[j*nrow(b)+i]] <- A[i] : attempt to select less than one element

A :

A[1]<-c(3)     F[[1]]<-numeric(0)   E[[1]]<-numeric(0)
A[2]<-c(1)     F[2]<-c(1)           E[2]<-c(1)
A[3]<-c(1)     F[3]<-c(2)           E[[3]]<-numeric(0)
A[[4]]<-c(1,3) F[[4]]<-numeric(0)   E[[4]]<-numeric(0)
A[5]<-c(4)     F[5]<-c(4)           E[5]<-c(4)

A :values of row 1 , F:row 2 and E :row 3. ( 5 column )

this data is not in this form and is not stored any where,they are the output of another function (there is function in the place of A[i]).the data just show what dose A look likes reproducibly and therefore shows the position in the matrix and gives back the error in update2.A[4] is the element of column 4 row 2.

Community
  • 1
  • 1
academic.user
  • 639
  • 2
  • 9
  • 28
  • @DavidArenburg isn't `matrix(list(c(1,2,3)))` what he needs? – Molx May 02 '15 at 22:00
  • 1
    It is _not_ impossible to have list elements in matrices. – IRTFM May 02 '15 at 22:02
  • The documentation for `matrix` does not say that only atomic vectors can be given as arguments to the data parameter. It only says that `as.vector` will remove attributes. (Which strips Dates, POSIXct, and factor arguments of their classes.) If they are just lists (which are after all another form of "R vectors"), then there is no violence to the data. – IRTFM May 02 '15 at 22:21
  • To the edit. Setting an object as an empty array does not allow you to have dynamic array dimensioning. That may be a feature of arrays in other languages but NOT in R. – IRTFM May 02 '15 at 22:26
  • The task would have been easier if you had actually tested that code. See my edit. (It's not possible to do `E[1] <- numeric(0)`. Need "[[" and the `c()` is superfluous. – IRTFM May 03 '15 at 01:42
  • 1
    Furthermore, as I explained before, R matrices are indexed in _column_- _major_ _order_. I suppose you can always use the `t()` function is if absolution needs to be as you described. – IRTFM May 03 '15 at 01:49
  • @BondedDust,sorry for not checking it. I create list of list of list my self for this task but I prefer to have defined matrix to avoid creating list by adding rows and to have a general form , the data included was a data which reproduce the update2 error.(I included further explanation and correct the mistakes) but thanks for all your helps.the desired answer would be your comment(update2) (defining row and column or in the exact format you explained) without the error. – academic.user May 03 '15 at 11:04

1 Answers1

19

This builds that matrix although the print method does not display it in the manner you imagined:

 matrix( list(c(1,2,4), c(NULL), c(1,2), c(3,4,5,6), c(1), c(1,3)), 2,3)
 #---------
     [,1]      [,2]      [,3]     
[1,] Numeric,3 Numeric,2 1        
[2,] NULL      Numeric,4 Numeric,2

Inspect the first element:

> Mlist <- matrix( list(c(1,2,4), c(NULL), c(1,2), c(3,4,5,6), c(1), c(1,3)), 2,3)
> Mlist[1,1]
[[1]]
[1] 1 2 4

> is.matrix(Mlist)
[1] TRUE
> class( Mlist[1,1] )
[1] "list"

Demonstration of creating "matrix of lists" from a list:

> will.become.a.matrix <- list(c(1,2,4), c(NULL), c(1,2), c(3,4,5,6), c(1), c(1,3))
> is.matrix(will.become.a.matrix)
[1] FALSE
> dim(will.become.a.matrix) <- c(2,3)
> is.matrix(will.become.a.matrix)
[1] TRUE
> dim(will.become.a.matrix)
[1] 2 3
> class(will.become.a.matrix[1,1])
[1] "list"

Further requested demonstration:

 A<- list(); F=list() E=list()
 A[1]<-c(3) ;  F[[1]]<-numeric(0);  E[[1]]<-numeric(0)
 A[2]<-c(1) ;  F[2]<-c(1)   ;        E[2]<-c(1)
 A[3]<-c(1) ;  F[3]<-c(2)  ;         E[[3]]<-numeric(0)
 A[[4]]<-list(1,3) ;F[[4]]<-numeric(0) ; E[[4]]<-numeric(0)
 A[5]<-c(4) ; F[5]<-c(4)       ;    E[5]<-c(4)
 Mlist= c(A,F,E)
 M <- matrix(Mlist, length(A), 3)
#=====================================
> M
     [,1]   [,2]      [,3]     
[1,] 3      Numeric,0 Numeric,0
[2,] 1      1         1        
[3,] 1      2         Numeric,0
[4,] List,2 Numeric,0 Numeric,0
[5,] 4      4         4        

You asked (in comments) "....is there a way to define number of column and rows , but not the element itself because they are unknown?"

Answered (initially in comments)

b<-matrix(rep(list(), 6),nrow = 2, ncol =3) 
#.... then replace the NULL items with values. 
# Need to use "[[": for assignment (which your 'Update 1' did not 
# ....and your Update2 only did for some but not all of the assignments.)

b[[1]] <- c(1,2,3,4) 
IRTFM
  • 258,963
  • 21
  • 364
  • 487
  • thanks for your answer, the length of each element is unknown and it is much more bigger than this example, and I try to fill this in a loop, what is known is just the length of row an column which is itself based on other variables. – academic.user May 02 '15 at 22:04
  • While this does create the desired matrix, the entries of the matrix aren't lists but rather atomic vectors, as indicated by David Arenburg. – Eike P. May 02 '15 at 22:06
  • 1
    @jhin: I don't see how you can maintain that incorrect position after I showed you that the first element was a list. – IRTFM May 02 '15 at 22:08
  • @BondedDust, How to generalized it, define the structure first then access to each element to fill it ? – academic.user May 02 '15 at 22:13
  • @BondedDust You're right, sorry. I thought that list was just due to indexing. This is really weird! It creates a list with a single element for each matrix entry...? By the way, the fact that there are really list elements in the matrix might become more obvious if you included, e.g., `list("blah", 1)` as an element in your list, because then printing the matrix directly displays a "list" element. – Eike P. May 02 '15 at 22:15
  • 1
    Create a list with as many elements as needed. Make sure that the elements are arranged in "column-major order" and then assign a dimension of m x n using `dim<-()` – IRTFM May 02 '15 at 22:15
  • sorry, I didn't get it , would you please clarify it in your answer by an example? – academic.user May 02 '15 at 22:18
  • Here's a very ugly way to print the matrix with all elements (except `NULL` which becomes empty): `apply(m, c(1,2), function(x) paste(eval(parse(text=x)), collapse = " "))`. Is there any better approach to do it? – Molx May 02 '15 at 22:21
  • 1
    It is a common occurrence to get a matrix or array of lists from `tapply` when the value returned by the function argument is a list. – IRTFM May 02 '15 at 22:24
  • Thanks for the answer again @BondedDust, please see the update is there a way to define number of column and rows , but not the element itself because they are unknown,there was no problem with the definition but with the assignments. – academic.user May 02 '15 at 22:38
  • @BondedDust elements are not known at this step they are calculated by a function so I can not create the list as you suggested. and then create the matrix.I want to define this matrix type then access to each element to fill it. – academic.user May 02 '15 at 22:46
  • 1
    `b<-matrix(rep(list(), 6),nrow = 2, ncol =3)` .... then replace the NULL items with values. Need to use "[[": `b[[1]] <- c(1,2,3,4)` – IRTFM May 02 '15 at 22:52
  • thanks, I define it like `b<-matrix(rep(list(),(length(d)*length(c))),nrow = length(c), ncol =length(d))`and the try `b[j, i] <- A[i]` but still get this error :`subscript out of bounds` – academic.user May 02 '15 at 22:54
  • 2
    As I said... need to use "[[": `b[[ j*nrow(b)+i]]` – IRTFM May 02 '15 at 22:54
  • thank you so much,but, this way I will access to each element t by its number, and not by the index of row and column,is there any other way? – academic.user May 02 '15 at 22:58
  • I am still not succeeded, this will gives me this error :`attempt to select less than one element`, please see the update2 – academic.user May 02 '15 at 23:21
  • If you do not post what `A` is (reproducibly) there is not hope for useful comment. – IRTFM May 03 '15 at 00:03
  • I couldn't provide the exact function which reproduce A as it depends on lots of other things. but a small output of it would be the one I included in the question,thank you – academic.user May 03 '15 at 01:06
  • While this answer probably could solve the problem, it is not really a matrix of lists, but rather a list of numeric vectors that can be indexed by row and column: `str(matrix( list(c(1,2,4), c(NULL), c(1,2), c(3,4,5,6), c(1), c(1,3)), 2,3))` gives `List of 6 $ : num [1:3] 1 2 4 $ : NULL $ : num [1:2] 1 2 $ : num [1:4] 3 4 5 6 $ : num 1 $ : num [1:2] 1 3 - attr(*, "dim")= int [1:2] 2 3` – Johannes Ranke Dec 02 '22 at 07:53
  • @JohannesRanke Assuming it's called `M`. `M[ 3, drop=FALSE`] does return a list. `is.list(M[ 3,drop=FALSE]) #[1] TRUE`. So does `is.list(M[ 1,2,drop=FALSE])` – IRTFM Dec 02 '22 at 19:26
  • @IRTFM sorry for being nitpicky. In my mind it's like this: M is a list, so it is not surprising that subsetting the list with `[` gives a list. I don't know why you used `drop = FALSE`, it does not make a difference on my end. However, if you extract one of its elements, e.g. `M[[3]]` you get a numeric vector, right? Of course M is not just a regular list, as it has a dim attribute which makes it matrix-like. Just my 2 cents. I stumbled across this because I just started to use such objects in a package. – Johannes Ranke Dec 04 '22 at 13:40
  • I used `drop = FALSE` because the "[.data.frame" function will coerce lists that are one-level lists to atomic vectors.At the time I wrote it I thought that "[" applied to matrices holding list might be behaving in a similar fashion, but now that I look I see that it's a specific class generic and I don't really know what functions is being applied when the argument is a matrix. If it gives the same result without the arguemnt then one possible inference is that the matrix function did a coercive act on its inputs. – IRTFM Dec 04 '22 at 23:53