I have a vector like below
tmp <- c(a=1, b=2, c=3)
a b c
1 2 3
I want to flatten this vector to get only 1, 2, 3.
I tried unlist(tmp) but it still gives me the same result.
How to achieve that efficiently?
You just want to remove the names attribute from tmp. There are a number of ways to do that.
You can unname it.
unname(tmp)
# [1] 1 2 3
Or use a very common method for removing names, by setting them to NULL.
names(tmp) <- NULL
Or strip the attributes with as.vector.
as.vector(tmp)
# [1] 1 2 3
Or re-concatenate it without the names.
c(tmp, use.names=FALSE)
# [1] 1 2 3
Or use setNames.
setNames(tmp, NULL)
# [1] 1 2 3
There is a use case that the above does not cover:
tmp <- c(1,2,3)
names(tmp) <- c("a","b","c")
In this case you need to use both:
unlist(unname(tmp))
Related
I have a vector a with values (1,2,3,4) and another vector b with values (1,1,0,1). Using the elements in b as a flag, I want to remove the vector elements from A at the same positions where 0 is found in element b.
a <- c(1,2,3,4)
b <- c(1,1,0,1)
for(i in 1:length(b))
{
if(b[i] == 0)
{
a <- a[-i]
}
}
I get the desired output
a
[1] 1 2 4
But using ifelse, I do not get the output as required.
a <- c(1,2,3,4)
b <- c(1,1,0,1)
for(i in 1:length(b))
{
a <- ifelse(b[i] == 0,a[-i],a)
}
Output:
a
[1] 1
How to use ifelse in such situations?
I think ifelse isn't the correct function here since ifelse gives output of same length as input and we want to subset values here. You don't need a loop as well. You can directly do
a[b != 0]
#[1] 1 2 4
data
a <- 1:4
b <- c(1, 1, 0, 1)
Another option could be:
a[as.logical(b)]
[1] 1 2 4
If you want to use ifelse, you can use the following code
na.omit(ifelse(b==0,NA,a))
such that
> na.omit(ifelse(b==0,NA,a))
[1] 1 2 4
attr(,"na.action")
[1] 3
attr(,"class")
[1] "omit"
We can also use double negation
a[!!b]
#[1] 1 2 4
data
a <- 1:4
b <- c(1, 1, 0, 1)
I have a vector like this.
filenames <- c("kisyu2_mst.csv", "kisyu3_mst.csv", "kisyu2_mst.csv",
"kisyu3_mst.csv", "kisyu3_mst.csv")
I need to get indices from filenames vector for each unique value.output look like this
for "kisyu2_mst.csv" indices vector c(1,3)
for "kisyu3_mst.csv" indices vector c(2,4,5)
Finally, I need to insert it to a list like this:
final <- list("kisyu2_mst.csv" = c(1,3), "kisyu3_mst.csv"=c(2,4,5))
How to get the indices of unique value from the vector?
We can use split
split(seq_along(filenames), filenames)
#$kisyu2_mst.csv
#[1] 1 3
#$kisyu3_mst.csv
#[1] 2 4 5
We could try which:
sapply(unique(filenames), function(i) which(filenames %in% i))
# $kisyu2_mst.csv
# [1] 1 3
#
# $kisyu3_mst.csv
# [1] 2 4 5
We can use tapply
tapply(seq_along(filenames), filenames, FUN = I)
#$kisyu2_mst.csv
#[1] 1 3
#$kisyu3_mst.csv
#[1] 2 4 5
I need to create named lists dynamically in R as follows.
Suppose there is an array of names.
name_arr<-c("a","b")
And that there is an array of values.
value_arr<-c(1,2,3,4,5,6)
What I want to do is something like this:
list(name_arr[1]=value_arr[1:3])
But R throws an error when I try to do this. Any suggestions as to how to get around this problem?
you can use [[...]] to assign values to keys given by strings:
my.list <- list()
my.list[[name_arr[1]]] <- value_arr[1:3]
You could use setNames. Examples:
setNames(list(value_arr[1:3]), name_arr[1])
#$a
#[1] 1 2 3
setNames(list(value_arr[1:3], value_arr[4:6]), name_arr)
#$a
#[1] 1 2 3
#
#$b
#[1] 4 5 6
Or without setNames:
mylist <- list(value_arr[1:3])
names(mylist) <- name_arr[1]
mylist
#$a
#[1] 1 2 3
mylist <- list(value_arr[1:3], value_arr[4:6])
names(mylist) <- name_arr
mylist
#$a
#[1] 1 2 3
#
#$b
#[1] 4 5 6
Your code will throw a error. Because in list(A = B), A must be a name instead of an object.
You could convert a object to a name by function eval. Here is the example.
eval(parse(text = sprintf('list(%s = value_arr[1:3])',name_arr[1])))
I don't find the help page for the replace function from the base package to be very helpful. Worst part, it has no examples which could help understand how it works.
Could you please explain how to use it? An example or two would be great.
If you look at the function (by typing it's name at the console) you will see that it is just a simple functionalized version of the [<- function which is described at ?"[". [ is a rather basic function to R so you would be well-advised to look at that page for further details. Especially important is learning that the index argument (the second argument in replace can be logical, numeric or character classed values. Recycling will occur when there are differing lengths of the second and third arguments:
You should "read" the function call as" "within the first argument, use the second argument as an index for placing the values of the third argument into the first":
> replace( 1:20, 10:15, 1:2)
[1] 1 2 3 4 5 6 7 8 9 1 2 1 2 1 2 16 17 18 19 20
Character indexing for a named vector:
> replace(c(a=1, b=2, c=3, d=4), "b", 10)
a b c d
1 10 3 4
Logical indexing:
> replace(x <- c(a=1, b=2, c=3, d=4), x>2, 10)
a b c d
1 2 10 10
You can also use logical tests
x <- data.frame(a = c(0,1,2,NA), b = c(0,NA,1,2), c = c(NA, 0, 1, 2))
x
x$a <- replace(x$a, is.na(x$a), 0)
x
x$b <- replace(x$b, x$b==2, 333)
Here's two simple examples
> x <- letters[1:4]
> replace(x, 3, 'Z') #replacing 'c' by 'Z'
[1] "a" "b" "Z" "d"
>
> y <- 1:10
> replace(y, c(4,5), c(20,30)) # replacing 4th and 5th elements by 20 and 30
[1] 1 2 3 20 30 6 7 8 9 10
Be aware that the third parameter (value) in the examples given above: the value is a constant (e.g. 'Z' or c(20,30)).
Defining the third parameter using values from the data frame itself can lead to confusion.
E.g. with a simple data frame such as this (using dplyr::data_frame):
tmp <- data_frame(a=1:10, b=sample(LETTERS[24:26], 10, replace=T))
This will create somthing like this:
a b
(int) (chr)
1 1 X
2 2 Y
3 3 Y
4 4 X
5 5 Z
..etc
Now suppose you want wanted to do, was to multiply the values in column 'a' by 2, but only where column 'b' is "X". My immediate thought would be something like this:
with(tmp, replace(a, b=="X", a*2))
That will not provide the desired outcome, however. The a*2 will defined as a fixed vector rather than a reference to the 'a' column. The vector 'a*2' will thus be
[1] 2 4 6 8 10 12 14 16 18 20
at the start of the 'replace' operation. Thus, the first row where 'b' equals "X", the value in 'a' will be placed by 2. The second time, it will be replaced by 4, etc ... it will not be replaced by two-times-the-value-of-a in that particular row.
Here's an example where I found the replace( ) function helpful for giving me insight. The problem required a long integer vector be changed into a character vector and with its integers replaced by given character values.
## figuring out replace( )
(test <- c(rep(1,3),rep(2,2),rep(3,1)))
which looks like
[1] 1 1 1 2 2 3
and I want to replace every 1 with an A and 2 with a B and 3 with a C
letts <- c("A","B","C")
so in my own secret little "dirty-verse" I used a loop
for(i in 1:3)
{test <- replace(test,test==i,letts[i])}
which did what I wanted
test
[1] "A" "A" "A" "B" "B" "C"
In the first sentence I purposefully left out that the real objective was to make the big vector of integers a factor vector and assign the integer values (levels) some names (labels).
So another way of doing the replace( ) application here would be
(test <- factor(test,labels=letts))
[1] A A A B B C
Levels: A B C
Quick question. Why does the following work in R (correctly assigning the variable value "Hello" to the first element of the vector):
> a <- "Hello"
> b <- c(a, "There")
> b
[1] "Hello" "There"
And this works:
> c <- c("Hello"=1, "There"=2)
> c
Hello There
1 2
But this does not (making the vector element name equal to "a" rather than "Hello"):
> c <- c(a=1, "There"=2)
> c
a There
1 2
Is it possible to make R recognize that I want to use the value of a in the statement c <- c(a=1, "There"=2)?
I am not sure how c() internally creates the names attribute from the named objects. Perhaps it is along the lines of list() and unlist()? Anyway, you can assign the values of the vector first, and the names attribute later, as in the following.
a <- "Hello"
b <- c(1, 2)
names(b) = c(a, "There")
b
# Hello There
# 1 2
Then to access the named elements later:
b[a] <- 3
b
# Hello There
# 3 2
b["Hello"] <- 4
b
# Hello There
# 4 2
b[1] <- 5
b
# Hello There
# 5 2
Edit
If you really wanted to do it all in one line, the following works:
eval(parse(text = paste0("c(",a," = 1, 'there' = 2)")))
# Hello there
# 1 2
However, I think you'll prefer assigning values and names separately to the eval(parse()) approach.
Assign the values in a named list. Then unlist it. e.g.
lR<-list("a" = 1, "There" = 2 )
v = unlist(lR)
this gives a named vector v
v
a There
1 2