This is a test version of Biostars. For the public version, visit https://www.biostars.org.
Any way coercing simple "list" to S4 "List" objects in R (with reproducible example)?

Hi everyone: Is there any way to coerce simple list-like object to S4 "List" objects? I need to do some vectorization on my data. Apparently, I used nested-lapply on my functions, and I checked its return type as "list". I want "List" like objects. How can I do that? Thanks.

Here is the reproducible example to clarify the issue:

data

foo <- GRanges(
  seqnames=Rle(c("chr1", "chr2", "chr3", "chr4"), c(3, 2, 1, 2)),
  ranges=IRanges(seq(1, by=9, len=8), seq(7, by=9, len=8)),
  rangeName=letters[seq(1:8)], score=sample(1:20, 8, replace = FALSE))

bar <- GRanges(
  seqnames=Rle(c("chr1", "chr2", "chr3","chr4"), c(4, 3, 1, 1)),
  ranges=IRanges(seq(2, by=5, len=9), seq(4, by=5, len=9)),
  rangeName=letters[seq(1:9)], score=sample(1:20, 9, replace = FALSE))

moo <- GRanges(
  seqnames=Rle(c("chr1", "chr2", "chr3","chr4"), c(3, 4, 2,1)),
  ranges=IRanges(seq(5, by=7, len=10), seq(8, by=7, len=10)),
  rangeName=letters[seq(1:10)], score=sample(1:20, 10, replace = FALSE))

I need let res_rm_multi_overlap as S4 "List" objects? Is that possible to do such coercion in R ? Any possible approach, solution, or idea are appreciated. Thanks

Best regards: Jurat

s4 coercion data manipulation list

Why exactly do you want the results as an S4 object? What do you need to do with the results that requires that?

Hi, Thanks for your quick respond. The main reason to need such coercion is, to remove multiple intersected regions by extractList methods from S4Vectors (if you run the script, you will see some has multiple index, means multiple intersection happens). This is possible step that I am going to continue if such coercion is possible to do:

    res_rm_multi_overlap <- lapply(res, function(ele_) {
      su <- lapply(grl, function(tt) {
        idx0 <- as(which.min(extractList(tt$score, ele_)), "List")
        idx0 <- idx0[!is.na(idx0)]
      })
    su <- su[!duplicated(su)]
  })

but this function raised an error, and most likely that I need to coerce res to "List", otherwise extractList method won't work. Could you give me any possible idea to overcome this issues? Thanks

Jurat

Hi Jurat, this is still a bit confusing for some reasons, I am not quite sure what you are trying to achieve here, but my gut feeling tells me there is an easier way to accomplish it. Also there is no pvalue in the grl example structure you have provided just a score. The error I am getting when running your code is:

Error in which.min(extractList(tt$pvalue, ele_)) : 


 error in evaluating the argument 'x' in selecting a method for function 'which.min': Error in relist(flesh, PartitioningByEnd(skeleton)) : 
  shape of 'skeleton' is not compatible with 'NROW(flesh)'

> grl
GRangesList object of length 2:
[[1]] 
GRanges object with 9 ranges and 2 metadata columns:
      seqnames    ranges strand |   rangeName     score
         <Rle> <IRanges>  <Rle> | <character> <integer>
  [1]     chr1  [ 2,  4]      * |           a         6
  [2]     chr1  [ 7,  9]      * |           b        10
  [3]     chr1  [12, 14]      * |           c        13
  [4]     chr1  [17, 19]      * |           d         3
  [5]     chr2  [22, 24]      * |           e        16
  [6]     chr2  [27, 29]      * |           f        15
  [7]     chr2  [32, 34]      * |           g        17
  [8]     chr3  [37, 39]      * |           h         9
  [9]     chr4  [42, 44]      * |           i         5

[[2]] 
GRanges object with 10 ranges and 2 metadata columns:
       seqnames   ranges strand | rangeName score
   [1]     chr1 [ 5,  8]      * |         a     7
   [2]     chr1 [12, 15]      * |         b    16
   [3]     chr1 [19, 22]      * |         c     6
   [4]     chr2 [26, 29]      * |         d    14
   [5]     chr2 [33, 36]      * |         e     8
   [6]     chr2 [40, 43]      * |         f    17
   [7]     chr2 [47, 50]      * |         g    18
   [8]     chr3 [54, 57]      * |         h     1
   [9]     chr3 [61, 64]      * |         i    10
  [10]     chr4 [68, 71]      * |         j    12

To answer the headline of your question, lists can be converted to S4 Lists just fine as you expected:

> as(list(c(1:2), c(2:3)), "List")
IntegerList of length 2
[[1]] 1 2
[[2]] 2 3

Dear Michael: I am sorry that I forgot to update scripts from my original post, now I updated (just replace pvalue with score). I really want res_rm_multi_overlap as "List" objects, in this case I can expand them by this way (my wanted to do):

res.expand <- lapply(res_rm_multi_overlap, function(ele_) {
  su <- lapply(grl, function(tt) {
    idx0 <- as(which.min(extractList(tt$score, ele_)), "List")
    idx1 <- unlist(extractROWS(seq_along(tt), ele_)[idx0])
    tt[idx1]
  })
})

but res.expand won't work unless res_rm_multi_overlap as "List". that's why I raise up this question. Thank you very much Michael.

Best regards: Jurat

I think you should tell us the task behind your filtering attempt, I am quite sure this approach is suffering from an XY problem. Note that extractROWS are internal functions of the S4 vector classes and are not be used as accessors, there is hence no documentation on their correct usage.

Dear Michael: I bet my attempt is worth to try. Here is proof of my words:

bar.ovHit <- res[[1]]
bar.ov_keepOne <- as(which.max(extractList(bar$score, bar.ovHit)), "List")
bar.ov.idx <- bar.ov_keepOne[!is.na(bar.ov_keepOne)]
bar.ov <- unlist(extractList(seq_along(bar), bar.ovHit)[bar.ov.idx])
bar[bar.ov]

so, my attempt works good to me, but if use nested-lapply to get done this in more compatible way, result of lapply would not comply with "List". Here I am considering geometric property of data, means that list element from res (a.k.a, list of hit-index) are matched to list element of grl pair wise. That's why I used nested lapply. I will be grateful if you are able to give me any possibilities to solve this issue. Thanks a lot

Right, but what are you actually trying to do? The answer to this should have nothing to do with R or anything that you've posted here.

If I am able to coerce res_rm_multi_overlap as hit-index vector with keeping only one region from multiple intersection, then I will do vector sum, such as:

K <- Reduce('+', lapply( res_rm_multi_overlap) function(ele_) { lengths(ele_)} ) + lengths(foo)

attention: before computing vector sum K, res_rm_multi_overlap must be as hit-index vector.

Yes, this is not the end, so I will do this filtering:

foo <- foo[K >= 2L];
res_rm_multi_overlap.ok <-  res_rm_multi_overlap[K >= 2L]

then expand res_rm_multi_overlap.ok as GRangesList object or data.frame.

problem is, res_rm_multi_overlap is not "List", all methods like extractList, lengths from S4Vector can't work. That's why I attempt to do this coercion. May be using nested lapply is not good idea, but what's the best alternative then ? Please point me out where was my wrong. Thanks a lot !

You're not answering the question. What are you actually trying to do?

Do not mention anything having to do with R in your reply.

Thank you for your reminding. I just solved the problem. In this case, should I provide my solution here?

I tried this way for res_rm_multi_overlap:

as.res_rm <- as(res_rm_multi_overlap, "List")

and it gave me this:

as(res_rm_multi_overlap, "List")
List of length 2

why result of this coercion is empty, and not expandable as res_rm_multi_overlap like a hit-index vector?

Hello Jurat Shahidin!

We believe that this post does not fit the main topic of this site.

No longer relevant.

For this reason we have closed your question. This allows us to keep the site focused on the topics that the community can help with.

If you disagree please tell us why in a reply below, we'll be happy to talk about it.

Cheers!

0 answers

No answers yet.

Log in to answer this question.