I have a list like this:
x <- 1
y <- 2
z <- "something"
my_list <- list("x" = x, "y" = y, "z" = z)
> my_list
$x
[1] 1
$y
[1] 2
$z
"something"
in truth my list is very long including big text elements such that in output I can not recognise them easily. Therefore I want to put a dashed line after every element of the list in Output like
$x
[1] 1
-------------------------------------
$y
[1] 2
-------------------------------------
$z
[1] "something"
-------------------------------------
Something like this could work.
mylistprint <- function(x){
nn <- names(x)
ll <- length(x)
if (length(nn) != ll) {
nn <- paste("Component", seq.int(ll))
}
for (i in seq_len(ll)) {
cat(nn[i], ":\n")
print(x[[i]])
cat("\n")
cat(strrep("-", 25))
cat("\n")
}
invisible(x)
}
mylistprint(my_list)
The output of this would be:
x :
[1] 1
-------------------------
y :
[1] 2
-------------------------
z :
[1] "something"
-------------------------
Using mapply
Probably a nicer way to do this is using mapply, or at least it is much shorter.
fun1 <- function(x,y) cat(paste0('$', x), y,strrep("-", 25), sep = '\n')
x <- mapply(fun1, names(my_list), my_list)
This prints:
$x
1
-------------------------
$y
2
-------------------------
$z
something
-------------------------
Single line
x <- mapply(function(x,y) cat(paste0('$', x), y,strrep("-", 25), sep = '\n'), names(my_list), my_list)
Wrap it in a function if you want
print.list <- function(list) {
x <- mapply(function(x,y) cat(paste0('$', x), y,strrep("-", 25), sep = '\n'), names(list), list)
}
From my comments, you could run a for loop, printing each element of a list, then printing "--------...-----", then the next element of a list, put this into a function and you are done, for example,
lsprint <- function(list){
for (i in 1:length(list)){
print(names(my_list)[i])
print(my_list[[i]])
print('--------------------')
}
}
lsprint(my_list)
Returns,
[1] "x"
[1] 1
[1] "--------------------"
[1] "y"
[1] 2
[1] "--------------------"
[1] "z"
[1] "something"
[1] "--------------------"
Edit: Added so you get the name
Related
I have a some dataframes q1[[i]] and q2[[i]] contain some (i = 19) lists. For example:
q1
[[1]]
[1] 240.13777778 273.73777778 172.73555556 53.70444444 141.80000000 582.93333333
[[2]]
[1] 2.409867e+02 2.731156e+02 1.680622e+02 5.300222e+01 5.112444e+01 1.048476e+03
...
q2
[[1]]
[1] 70.29000000 69.57666667 48.82000000 22.19000000 31.44666667 143.34000000
[[2]]
[1] 70.2066667 69.5533333 47.9766667 22.0866667 14.0000000 270.3766667
I want to create list, contain such fragments:
qw1
[[1]]
[1] 240.13777778
[1] 70.29000000
[[1]]
[2] 273.73777778
[2] 69.57666667
qw2
[[2]]
[1] 2.409867e+02
[1] 70.2066667
[[2]]
[2] 2.731156e+02
[2] 69.5533333
...
and calculate norm for each block (for example)
qw2
[[2]]
[1] 2.409867e+02 -> norm
[1] 70.2066667
...
[[2]]
[2] 2.731156e+02 -> norm
[2] 69.5533333
and create new normlist for plotting (19 lists, insofar as i = 19).
I try to crete same list, but I get only last normlist:
for (i in 1:19){
q1[[i]] <- dfL_F[[assemble_normal[i]]]/0.000450
q2[[i]] <- dfL_RMF[[assemble_normal[i]]]/0.000300
q3[[i]] <- dfL_D[[assemble_normal[i]]]/0.001800
q4[[i]] <- dfL_RMD[[assemble_normal[i]]]/0.001200
length(q1[[i]])
length(q2[[i]])
length(q3[[i]])
length(q4[[i]])
qw1 <- lapply(q1[[i]], `[[`, 1)
qw2 <- lapply(q2[[i]], `[[`, 1)
qw3 <- lapply(q3[[i]], `[[`, 1)
qw4 <- lapply(q4[[i]], `[[`, 1)
nn <- list()
for (j in 1:length(q1[[i]])){
nn[[j]] <- c(qw1[j],qw2[j],qw3[j],qw4[j])
}
qnorm1 <- list()
for (k in 1:length(nn)){
qnorm1[[k]] <- norm(do.call(rbind, lapply(nn[k], as.numeric)),type = "i")
}
}
And I don't know how to get 19 lists contatin two fields for each lists q1[[i]] and q2[[i]], that form a block, there must be such blocks length (q1[[i]]) for each i (length (q1[[i]]) = length (q2[[i]]))?
Code reproducible:
dput(q1)
list(c(240.137777777778, 273.737777777778, 172.735555555556,
53.7044444444444, 141.8, 582.933333333333),c(240.986666666667, 273.115555555556, 168.062222222222, 53.0022222222222, 51.1244444444444, 1048.47555555556)
dput(q2)
list(c(70.29, 69.5766666666667, 48.82, 22.19, 31.4466666666667,
143.34),c(70.2066666666667, 69.5533333333333, 47.9766666666667, 22.0866666666667, 14, 270.376666666667)
dput(qnorm1)
list(305.738611111111, 365.616666666667, 666.443055555556, 608.981111111111, 393.538611111111, 142.288055555556)
But it's only last list qnorm, there should be 19 such lists and they need to be written in general list.
P.S. As a result, I got the required list, but I can't calculate the norm for each block, I get an empty list at the output... Why?
qw <- Map(
function(q1i, q2i) {
stopifnot(length(q1i) == length(q2i))
Map(c, q1i, q2i) # j elementh i block q1[[i]][j], q2[[i]][j]
},
q1, q2 # every block conatin q1[[i]], q2[[i]]
)
# list qw conatin blocks qw1, qw2
stopifnot(length(qw1) == length(qw2))
qnorm11 <- Map(
function(qw1, qw2, qw3, qw4)
{
stopifnot(length(qw1) == length(qw2))
Map(c, (norm(as.matrix(unlist(qw1),type = "1"))),
(norm(as.matrix(unlist(qw2),type = "1"))),
(norm(as.matrix(unlist(qw3),type = "1"))),
(norm(as.matrix(unlist(qw4),type = "1"))))
}, qw1, qw2, qw3, qw4)
Perhaps you can try this
list2env(
setNames(
Map(function(x, y) apply(rbind(x, y), 2, function(v) norm(t(v)), simplify = FALSE), q1, q2),
c("qw1", "qw2")
),
envir = .GlobalEnv
)
We can use append function to add element to list. For example like blow.
a_list <- list()
a_list <- append(a_list, "a")
But I want do to like this. The append_new don't return but change the a_list.
a_list <- list()
append_new(a_list, "a")
It can be used by eval function to do this.
a_list <- list()
eval(parse(text="a_list[[1]]<-a"))
a_list
But if I want to write the function add_element_to_list.
a_list <- list()
add_element_to_list(a_list, "a")
a_list ## same as list("a")
How to write the function? This function like assign but more powerful.
The post use eval(parse(text="")) but it can not write in the custom function append_new.
Simpler:
`append<-` <- function(x, value) {
c(x, value)
}
x <- as.list(1:3)
y <- as.list(1:3)
append(x) <- y
append(x) <- "a"
print(x)
[[1]]
[1] 1
[[2]]
[1] 2
[[3]]
[1] 3
[[4]]
[1] 1
[[5]]
[1] 2
[[6]]
[1] 3
[[7]]
[1] "a"
Using evil parse:
append_new <- function(x, y){
eval(parse(text = paste0(x, "[ length(", x, ") + 1 ]<<- '", y, "'")))
}
a_list <- list()
append_new(x = "a_list", y = "a")
a_list
# [[1]]
# [1] "a"
append_new(x = "a_list", y = "b")
a_list
# [[1]]
# [1] "a"
#
# [[2]]
# [1] "b"
Perhaps something like this?
add_element_to_list <- function(this, that)
{
if(typeof(this) != "list") stop("append_new requires a list as first argument")
assign(deparse(substitute(this)),
append(this, that),
envir = parent.frame(),
inherits = TRUE)
}
a_list <- list()
add_element_to_list(a_list, "a")
a_list
#> [[1]]
#> [1] "a"
add_element_to_list(a_list, "b")
a_list
#> [[1]]
#> [1] "a"
#>
#> [[2]]
#> [1] "b"
I would be very cautious in using something like this in a package though, since it is not idiomatic R. In general, R users expect functions not to modify existing objects but to return new objects.
Of course there are some notable exceptions...
Imagine:
myfunct <- function(x, ...){
dots <- list(...)
...
}
How do I distinguish in the course of the function whether dots derived from myfunct('something') (no dots) or myfunct('something', NULL) (dots includes explicit NULL)?
In my experimentation both cases lead to is.null(dots) equating to TRUE.
Does it help ?
f <- function(x, ...){
missing(...)
}
> f(2)
[1] TRUE
> f(2, NULL)
[1] FALSE
g <- function(x, ...){
length(list(...))
}
> g(2)
[1] 0
> g(2, NULL)
[1] 1
I eventually came up with the following:
myfunct <- function(...)
{
my_dots <- match.call(expand.dots = FALSE)[['...']]
no_dots <- is.null(my_dots)
# Process the dots
if(!no_dots)
{
my_dots <- lapply(my_dots, eval)
}
# Exemplary return
return(my_dots)
}
This yields:
> myfunct(1)
[[1]]
[1] 1
> myfunct(NULL)
[[1]]
NULL
> myfunct()
NULL
> myfunct(1, NULL, 'A')
[[1]]
[1] 1
[[2]]
NULL
[[3]]
[1] "A"
Say I have a list:
> fs
[[1]]
NULL
[[2]]
NULL
[[3]]
NULL
[[4]]
[1] 61.90298 58.29699 54.90104 51.70293 48.69110
I want to "reverse fill" the rest of the list by using it's values. Example:
The [[3]] should have the function value of [[4]] pairs:
c( myFunction(fs[[4]][1], fs[[4]][2]), myFunction(fs[[4]][2], fs[[4]][3]), .... )
The [[2]] should have myFunction values of [[3]] etc...
I hope that's clear. What's the right way to do it? For loops? *applys? My last attempt, which leaves 1-3 empty:
n = length(fs)
for (i in rev(1:(n-1)))
child_fs = fs[[i+1]]
res = c()
for (j in 1:(i+1))
up = v(child_fs[j])
do = v(child_fs[j+1])
this_f = myFunction(up, do)
res[j] = this_f
fs[[i]] = res
Make fs easily reproducible
fs <- list(NULL, NULL, NULL, c(61.90298, 58.29699, 54.90104, 51.70293, 48.69110))
To be able to show an example, make a trivial myFunction
myFunction <- function(a, b) {a + b}
You can loop over all but the last positions in fs (in reverse order), and compute each. Just call myFunciton with the vectors which are the next higher position's vectors without the last and without the first element.
for (i in rev(seq_along(fs))[-1]) {
fs[[i]] <- myFunction(head(fs[[i+1]], -1), tail(fs[[i+1]], -1))
}
That assumes myFunction is vectorized (given vectors for inputs, will give a vector for output). If it isn't, you can easily make a version which is.
myFunction <- function(a, b) {a[[1]] + b[[1]]}
for (i in rev(seq_along(fs))[-1]) {
fs[[i]] <- Vectorize(myFunction)(head(fs[[i+1]], -1), tail(fs[[i+1]], -1))
}
In either case, you get
> fs
[[1]]
[1] 453.2 426.8
[[2]]
[1] 233.398 219.802 206.998
[[3]]
[1] 120.200 113.198 106.604 100.394
[[4]]
[1] 61.90298 58.29699 54.90104 51.70293 48.69110
Really, what you have is a starting point
start <- c(61.90298, 58.29699, 54.90104, 51.70293, 48.69110)
a function you want to apply (I made this one up which adds 1 everywhere and deletes the last element)
myFunction <- function(x) head(x + 1, -1L)
and the number of times you want to apply the function (recursively):
n <- 3L
So I would write a function to apply the function n times recursively, then reverse the output list:
apply.n.times <- function(fun, n, x)
if (n == 0L) list(x) else c(list(x), Recall(fun, n - 1L, fun(x)))
rev(apply.n.times(myFunction, n, start))
# [[1]]
# [1] 64.90298 61.29699
#
# [[2]]
# [1] 63.90298 60.29699 56.90104
#
# [[3]]
# [1] 62.90298 59.29699 55.90104 52.70293
#
# [[4]]
# [1] 61.90298 58.29699 54.90104 51.70293 48.69110
Here is a one-line solution (if myFunction can be replaced with something like sum, or in this case rowSums):
Reduce( function(x,y) rowSums( embed(y,2) ), fs, right=TRUE, accumulate=TRUE )
If myFunction needs to accept 2 values and do something with them then this can be expanded a bit to:
Reduce( function(x,y) apply( embed(y,2), 1, function(z) myFunction(z[1],z[2]) ),
fs, right=TRUE, accumulate=TRUE )
As part of a function, I want to output a list of all the arguments and their values, including the default values. For example, a function with these arguments:
foo <- function(x=NULL,y=NULL,z=2) {
#formals()
#as.list(match.call())[-1]
#some other function?....
}
To give output as such:
> foo(x=4)
$x
[1] 4
$y
NULL
$z
[1] 2
formals does not update to give the values argument values when the function is called. match.call does, but does not provide the defaults of the arguments. Is there another function out there that will provide the output as I want?
Hopefully, this doesn't lead to dragons.
foo <- function(x=NULL,y=NULL,z=2) {
mget(names(formals()),sys.frame(sys.nframe()))
}
foo(x=4)
$x
[1] 4
$y
NULL
$z
[1] 2
print(foo(x=4))
$x
[1] 4
$y
NULL
$z
[1] 2
you can use a mix of the 2 , match.call and formals
foo <- function(x=NULL,y=NULL,z=2)
{
ll <- as.list(match.call())[-1] ##
myfor <- formals(foo) ## formals with default arguments
for ( v in names(myfor)){
if (!(v %in% names(ll)))
ll <- append(ll,myfor[v]) ## if arg is missing I add it
}
ll
}
For example :
foo(y=2)
$y
[1] 2
$x
NULL
$z
[1] 2
> foo(y=2,x=1)
$x
[1] 1
$y
[1] 2
$z
[1] 2
Here is an attempt to wrap this logic in a reusable function to drop in instead of match.call:
match.call.defaults <- function(...) {
call <- evalq(match.call(expand.dots = FALSE), parent.frame(1))
formals <- evalq(formals(), parent.frame(1))
for(i in setdiff(names(formals), names(call)))
call[i] <- list( formals[[i]] )
match.call(sys.function(sys.parent()), call)
}
It looks like it works:
foo <- function(x=NULL,y=NULL,z=2,...) {
match.call.defaults()
}
> foo(nugan='hand', x=4)
foo(x = 4, y = NULL, z = 2, ... = pairlist(nugan = "hand"))
foo <- function(x=NULL,y=NULL,z=2) {
X <- list(x,y,z); names(X) <- names(formals()); X
}
z <- foo(4)
z
#------
$x
[1] 4
$y
NULL
$z
[1] 4