I want to append data to my list only if it is distinct from previously stored data.
data <- c("A","B","C")
My code so far:
x<- function(...){
data <- ifelse(... %in% data, append(data, ""),append(data, as.character(...)))
return(data)
}
For instance, if I want to append "D," my desired output is:
data
[1] "A" "B" "C" "D"
However, I received this:
data
[1] "A"
x <- c("A","B","C")
y <- c("D", "A")
union(x, y)
# [1] "A" "B" "C" "D"
ifelse function cannot give vector as a result. See ifelse function documentation.
Instead, you should use if - else statement
x<- function(...){
data <- if (... %in% data) {append(data, "")} else {append(data, as.character(...))}
return(data)
}
x("D")
[1] "A" "B" "C" "D"
Here is my solution:
x <- c("A","B","C")
y <- c("D", "A")
unique(c(x, y))
[1] "A" "B" "C" "D"
Related
This is likely a duplicate, yet I appear to be incapable of finding a similar question atm. I have a list of (very long) vectors that are similar in length. Each vector element contains a character. Sometimes multiple vectors contain characters at the same position (sequential numbering from the beginning). Sometimes none contain a character (i.e. all contain NA). There are maybe 10 of these vectors and each has a length of millions of elements. I need to find a quick and memory-efficient way of combining the vectors to a single vector, preferably without using any dependencies (i.e. no data.table or dplyr). The example is simple and short to understand the concept.
I have:
x <- list(A = c(rep("A", 5), rep(NA, 5)), B = c(rep(NA, 4), rep("B", 5), NA))
I need to combine them to:
c(rep("A", 4), "conflict", rep("B", 4), "none")
# "A" "A" "A" "A" "conflict" "B" "B" "B" "B" "none"
Thank you for help. I should know how to do this but somehow it escapes me atm. I do have an apply solution that goes in row by row but that is inefficient. Need to vectorize the solution.
apply(do.call(cbind, x), 1, function(k) {
if(sum(is.na(k)) == length(k)) {
"none"
} else if (sum(!is.na(k)) == 1) {
k[!is.na(k)]
} else {
"conflict"
}
})
This solution uses a vectorized function f and Reduce to apply it to the list. But it assumes that all vectors have the same length. And Reduce is not known for its speed-wise performance.
f <- function(x, y){
na.x <- is.na(x) | x == "none"
na.y <- is.na(y) | y == "none"
x[na.x & na.y] <- "none"
x[!na.x & !na.y & x != y] <- "conflict"
x[!na.x & na.y] <- x[!na.x & na.y]
x[na.x & !na.y] <- y[na.x & !na.y]
x
}
Reduce(f, x)
# [1] "A" "A" "A" "A" "conflict" "B"
# [7] "B" "B" "B" "none"
Reduce(f, list(A=NA, B = NA, C = 'A'))
#[1] "A"
Here's a vectorised version of your code :
dat <- do.call(cbind, x)
#Logical matrix
mat <- !is.na(dat)
#Number of non-NA's in each row
rs <- rowSums(mat)
#First non-NA value
val <- dat[cbind(1:nrow(dat), max.col(mat, ties.method = 'first'))]
#More than 1 non-NA value
val[rs > 1] <- 'conflict'
#Only NA value
val[rs == 0] <- 'none'
val
#[1] "A" "A" "A" "A" "Conflict" "B"
#[7] "B" "B" "B" "none"
EDIT - Updated to include suggestion from #Henrik to avoid nested ifelse which should make the solution faster.
Another one
x <- list(A = c(rep("A", 5), rep(NA, 5)), B = c(rep(NA, 4), rep("B", 5), NA))
y <- apply(do.call('rbind', x), 2, function(x) toString(na.omit(x)))
y[!nzchar(y)] <- 'none'
replace(y, grepl(',', y), 'conflict')
# [1] "A" "A" "A" "A" "conflict" "B" "B" "B" "B" "none"
could anyone help me while results are not getting displayed here below
col_name <- c("A", "B", "C", "D")
i <- 1
while (i < length(col_name)) {
col_name[i]
i = i+1
}
Expected output
"A"
"B"
"C"
It needs a print
while (i < length(col_name)) {
print(col_name[i])
i = i+1
}
#[1] "A"
#[1] "B"
#[1] "C"
If we need to store the output, initialize an object and update
out <- c()
i <- 1
while (i < length(col_name)) { out <- c(out, col_name[i]); i = i+1}
out
#[1] "A" "B" "C"
I am writing a program that (as a part of it) automatically creates dendrograms from an input dataset.
For each node/split I want to extract all the labels that are under that node and the location of that node on the dendrogram plot (for further plotting purposes).
So, let's say my data looks like this:
> Ltrs <- data.frame("A" = c(3,1), "B" = c(1,1), "C" = c(2,4), "D" = c(6,6))
> dend <- as.dendrogram(hclust(dist(t(Ltrs))))
> plot(dend)
The dendrogram
Now I can extract the location of the splits/nodes:
> library(dendextend)
> nodes <- get_nodes_xy(dend)
> nodes <- nodes[nodes[,2] != 0, ]
> nodes
[,1] [,2]
[1,] 1.875 7.071068
[2,] 2.750 3.162278
[3,] 3.500 2.000000
Now I want to get all the labels under a node, for each node (/row from the 'nodes' variable).
This should look something like this:
$`1`
[1] "D" "C" "B" "A"
$`2`
[1] "C" "B" "A"
$`3 `
[1] "B" "A"
Can anybody help me out? Thanks in advance :)
How about something like this?
library(tidyverse)
library(dendextend)
Ltrs <- data.frame("A" = c(3,1), "B" = c(1,1), "C" = c(2,4), "D" = c(6,6))
dend <- as.dendrogram(hclust(dist(t(Ltrs))))
accumulator <- list();
myleaves <- function(anode){
if(!is.list(anode))return(attr(anode,"label"))
accumulator[[length(accumulator)+1]] <<- (reduce(lapply(anode,myleaves),c))
}
myleaves(dend);
ret <- rev(accumulator); #generation was depth first, so root was found last.
Better test this. I am not very trustworthy. In particular, I really hope the list ret is in an order that makes sense, otherwise it's going to be a pain associating the entries with the correct nodes! Good luck.
Function partition_leaves() extracts all leaf labels per each node and makes a list ordered in the same fashion as get_nodes_xy() output. With your example,
Ltrs <- data.frame("A" = c(3,1), "B" = c(1,1), "C" = c(2,4), "D" = c(6,6))
dend <- as.dendrogram(hclust(dist(t(Ltrs))))
plot(dend)
partition_leaves(dend)
yields:
[[1]]
[1] "D" "C" "A" "B"
[[2]]
[1] "D"
[[3]]
[1] "C" "A" "B"
[[4]]
[1] "C"
[[5]]
[1] "A" "B"
[[6]]
[1] "A"
[[7]]
[1] "B"
filtering list by vector length will give output similar to the desired one.
I would like to extract list elements and their indices in R while removing items with 0 length. Let's say I have the following list in R:
l1 <- character(0)
l2 <- c("a","b")
l3 <- c("c","d","e")
list1 <- list(l1, l1, l2, l1, l3)
Then list1 returns the following:
[[1]]
character(0)
[[2]]
character(0)
[[3]]
[1] "a" "b"
[[4]]
character(0)
[[5]]
[1] "c" "d" "e"
I would like to somehow extract an object that displays the index/position for each non-empty element, as well as the contents of that element. So something that looks like this:
[[3]]
[1] "a" "b"
[[5]]
[1] "c" "d" "e"
The closest I've come to doing this is by removing the empty elements, but then I lose the original index/position of the remaining elements:
list2 <- list1[lapply(list1, length) > 0]
list2
[[1]]
[1] "a" "b"
[[2]]
[1] "c" "d" "e"
keep, will keep elements matching a predicate. negate(is_empty) creates a function that returns TRUE if a vector is not empty.
library("purrr")
names(list1) <- seq_along(list1)
keep(list1, negate(is_empty))
#> $`3`
#> [1] "a" "b"
#>
#> $`5`
#> [1] "c" "d" "e"
Overview
Keeping the indices required me to name each element in the list. This answer uses which() to set the condition that I apply to list1 to keep non-zero length elements.
# load data
l1 <- character(0)
l2 <- c("a","b")
l3 <- c("c","d","e")
list1 <- list( l1, l1, l2, l1, l3)
# name each element in the list
names( list1 ) <- as.character( 1:length( list1 ) )
# create a condition that
# keeps only non zero length elements
# from list1
non.zero.length.elements <-
which( lapply( X = list1, FUN = length ) != 0 )
# apply the condition to list1
# to view the non zero length elements
list1[ non.zero.length.elements ]
# $`3`
# [1] "a" "b"
#
# $`5`
# [1] "c" "d" "e"
# end of script #
I'm not sure exactly what 'extract an object that displays' means, but if you just want to print you can use this modified print.
I just slightly edited print.listof (it's not recursive! zero length subelements will be displayed):
print2 <- function (x, ...)
{
nn <- names(x)
ll <- length(x)
if (length(nn) != ll)
nn <- paste0("[[", seq.int(ll),"]]")
for (i in seq_len(ll)[lengths(x)>0]) {
cat(nn[i], "\n")
print(x[[i]], ...)
cat("\n")
}
invisible(x)
}
print2(list1)
[[3]]
[1] "a" "b"
[[5]]
[1] "c" "d" "e"
A very simple solution is to provide names to the elements of your list and then run your function again. There are several ways to name your elements.
l1 <- character(0)
l2 <- c("a","b")
l3 <- c("c","d","e")
list1 <- list(e1=l1, e2=l1, e3=l2, e4=l1, e5=l3)
list1
names(list1)<-paste0("element",seq(length(list1)))
list1[lapply(list1, length) > 0]
In R language, I defined a matrix this way:
data <- matrix(c("A","B","C","D","E","F"), nrow = 2)
This gives me something like this:
"A" | "C" | "E"
"B" | "D" | "F"
now, How do I get a random column of the matrix?
If I do:
sample(x = data, n = 2)
I get random elements from all around the matrix, like "A" and "F". What I want is to get a column like "A" and "B", or "C" and "D" or "E" and "F"
I am new to R so any help is really apreciated
I'd use something like this:
f <- function(mat) {
j <- sample(seq_len(ncol(mat)), size=1)
## (Use `drop=FALSE` to say "don't convert 1-column matrices to vectors")
data[, j, drop=FALSE]
}
## Try it out
f(data)
# [,1]
# [1,] "E"
# [2,] "F"