Dear Diego:
Could you look up my project repository in github? In my project site, you could able to see all my workflow, and this part of code must be optimized as elegant as possible. Could you give me favor ? Thanks
Hi :
I have implemented several functions where some function behaved very similar way and share some identical structure. However, I intend to reuse the code more efficiently in my wrapper functions to make function body smaller for the sake of easy to test and debug. I am trying to find better way to construct my wrapper function as small as possible. How can I efficiently reuse the code multiple times in wrapper function easily ? What's the strategy to efficiently use same code structure in many times? Can anyone give me possible idea to overcome this issue ? Any idea ?
obj.List is list of peak interval as GRanges object, intList is list of integer list as overlap position index, val.List is list of pvalue, threshold could be numeric scalar. This is the wrapper function where two small sub functions' code is shared same pattern :
myFunc <- function(obj.List, intList, threshold, ...) {
#
func.1 <- function() {
keepIdx <- lapply(intList, function(ele_) {
keepMe <- sapply(val.List, function(x) x<=threshold)
res <- ele_[keepMe]
})
expand.Keep <- Map(unlist,
mapply(extractList, obj.List, keepIdx))
return(expand.Keep)
}
func.2 <- function() {
dropIdx <- lapply(intList, function(ele_) {
drop_ <- sapply(val.List, function(x) x > threshold)
res <- ele_[drop_]
})
expand.drop <- Map(unlist,
mapply(extractList, obj.List, keepIdx))
return(expand.drop)
}
# then use the output of func.1 and func.2 as an argument for another function
# in this wrapper
# how can I make this wrapper more efficient ? How to resue the code ?
}
I am just trying to make function body of this wrapper smaller, while I can call func.1, func.2 as an argument in the wrapper to trigger another sub function. How can I make this happen ? Any way efficiently optimize the code structure of above wrapper function ? Can anyone give me possible idea to make above code more efficient ? Thanks a lot
I am not completely sure I understand what you are trying to do. Maybe an example with your desired use case and expected output would help. For more advance R programming I would recommend reading Advanced R, by Hadley Wickham (half-way to finish it myself). My guess is that you want something similar to functionals, or perhaps, a closure, but not completely sure.
You mention that one of your objectives is to obtain code that it is easy to test and debug. I also see from your repository that you intend to create an R package. One thing I highly recommend you to do for testing is use unit testing. There are many options in R, like those provided by the packages RUnit, testit and testthat. I now use testthat because I found it easy to implement. You can know more about how to use it in the book (written by Hadley Wickham) R packages, which has a section dedicated to unit testing.
Dear Diego:
Could you look up my project repository in github? In my project site, you could able to see all my workflow, and this part of code must be optimized as elegant as possible. Could you give me favor ? Thanks
I am not sure what I can accomplish by looking at your workflow. I still don't understand what you are trying to do. At any rate, you didn't include the link to your github and you don't show up by name.
Dear Diego:
Thanks again for your quick respond. Here is my project repository in github. Thanks a lot.
Best regards :
Jurat
May take a closer look later if I have time but in the meantime I added a small update to my answer.
Dear Diego :
I also intend to use testthat package for unit testing. Before unit testing, I need to make sure whole pipeline of packages is desired both in code quality and readability. How can I overcome repeated code block in my workflow ? How can I make this more efficient ? Any contribution on this packages is highly appreciated. Thank you very much :)
Best regards :
Jurat
Welcome to the world of functional programming. In R, a function can return a function. Yea, you heard it right: the return value can be a function :)
So you might do something like this:
and then,
func.1 = s("keepIdx")
func.2 = s("dropIdx")
Note that the two functions live in different environments; so there is no conflict between the two lapply.func, as they live in the environment of their respective functions.
> func.1
function() {
myIdx <- lapply(intList, lapply.func)
expand <- Map(unlist, mapply(extractList, obj.List, myIdx))
}
<environment: 0xe848530>
> func.2
function() {
myIdx <- lapply(intList, lapply.func)
expand <- Map(unlist, mapply(extractList, obj.List, myIdx))
}
<environment: 0xe854840>
> get("lapply.func", env = environment(func.1))
function(ele_) {keepMe <- sapply(val.List, function(x) x<=threshold); res <- ele_[keepMe]}
<environment: 0xe848530>
> get("lapply.func", env = environment(func.2))
function(ele_) {drop_ <- sapply(val.List, function(x) x > threshold); res <- ele_[drop_]}
<environment: 0xe854840>
You might need to debug / tweak the above code according to your code-logic, but I hope you got the idea.
Dear Santosh Anand:
Thanks for your wonderful idea on my issue. Apparently reducing function body of wrapper is desired in functional programming world, so I am struggling to accomplish this nicely. FYI, in my work flow, I'll need to use output of func.1 as func.2 as an argument for another functions instead. Could you look up my workflow right here. How can I make the implementation of my wrapper more prettier and easy to read ? Could you give me possible idea to make my code more robust ? many thanks :)
Best regards :
Jurat
I'll need to use output of func.1 as func.2 as an argument for another functions instead.
But why that is difficult?
another_function(func.1(arguments_of_func_1), func.2(arguments_of_func_2), ..........)
Dear Santosh:
I got weird error when I took your advise where your suggesting code frame work couldn't be tested with real data. Why this happen ? I fill out all parameter in your revised function, but couldn't return expected value. Could you give me idea please ? Any better and robust solution based on your scratch function ? Thank you :)
Best regards :
Jurat
...and what was the error?
paste the relevant part of code also
Here is code I use your framework:
func <- function(peakset, .ovHit, tau.s, .globalSC ,keepOrDrop, ...) {
# check input param
if(keepOrDrop == "keepIdx") {
lapply.func <- function(ele_) {
keep_ <- sapply(.globalSC, function(x) x<=tau.s)
res <- ele_[keep_]
}
} else if(keepOrDrop == "dropIdx"){
lapply.func <- function(ele_) {
drop_ <- sapply(.globalSC, function(x) x > tau.s)
res <- ele_[drop_]
}
}
.expandHit <- function() {
.hitIdx <- lapply(.ovHit, lapply.func)
.expandAsGR <- Map(unlist,
mapply(extractList, peakset, .hitIdx))
.expandAsGR[[1L]] <- unique(.expandAsGR)
.expandAsGR <- setNames(.expandAsGR, names(peakset))
}
}
#' @example
.Confirmed.ERs <- func(total.ERs, keepList, tau.s=1.0E-08, comb.p, "keepIdx")
.Discarded.ERs <- func(total.ERs, keepList, tau.s=1.0E-08, comb.p, "dropIdx")
.Confirmed.ERs
function() { .hitIdx <- lapply(.ovHit, lapply.func) .expandAsGR <- Map(unlist, mapply(extractList, peakset, .hitIdx)) .expandAsGR[[1L]] <- unique(.expandAsGR) .expandAsGR <- setNames(.expandAsGR, names(peakset)) } <bytecode: 0x0000000023d7ef90=""> <environment: 0x0000000026eef210="">
.Confirmed.ERs must be returned as an data object rather than function itself because all parameter is filled. Why this happen ? Thank you :)
Best regards:
Jurat
return(lapply.func)from both places. .hitIdx <- lapply(.ovHit, lapply.func) => The lapply.func as defined takes an argument ele_, which has no default. You must pass that while calling it.Any chance to make your solution more elegant and dynamic ? I think let keepOrDrop as logical vector could be easier. How can I make the your framework more prettier and robust ? Thank you very much :)
Best regards :
Jurat
lapply.func <- function(ele_) {
keep_ <- sapply(.globalSC, function(x) x<=tau.s)
res <- ele_[keep_]
}
This function has argument ele_, with no default value. When yo call this function in lapply, that ele_ must be passed something like this
.hitIdx <- lapply(.ovHit, lapply.func, ele_=?)
in lapply, first argument is list of objects, second argument is the function, so I think no need to call ele_, lapply return list like objects. Can I make this function call simpler ? I still lost how to correctly call the functions ? sorry for this simple question.
in lapply, first argument is list of objects, second argument is the function
... and the third argument is the arguments that the function inside lapply will take.
PS: If you are editing your earlier posts by changing the content, then you should add an EDIT/UPDATE comment saying what have you edited. Else somebody looking at the earlier posts will be completely lost
Dear Santosh :
To keep this conversation thread clean and easy to read by others, I'll open new comment thread. To correctly use function call, I can try this way, but still no luck with this :
keepOrDropIdx <- lapply(intList, lapply.func, ele_= 1:seq_along(intList))
lapply.fun go through each element of intList , so its input could be intList[[i]], But my attempt still didn't return data object. How can I fix this issue ? Any idea?
Best regards :
Jurat
WTF? And you removed all the old discussions!!! The only suggestion I have is that you first go and read the fundamentals before writing complex codes.
See also the remark by Damian Kao. Mods may please close this thread.
Log in to answer this question.
I'll keep this post open because there is a healthy discussion going on. I enjoy discussing programming issues also, however, this is really more suited to stackexchange as it is tangentially related to bioinformatics.
Agreed 100% (stackexchange)!