user297400
user297400

Reputation: 1365

How Can I vectorize this function to return an index vector?

I'm new to R and am trying to get a handle on the apply family of functions. Specifically, I am trying to write a higher-order function that will accept 2 character vectors, "host", and "guest" (which do not need to be the same length) and return me an index vector the same length as "host", with the resulting elements corresponding to their indices in guest (NA if not there).

host <- c("A","B","C","D")
guest <- c("D","C","A","F")

matchIndices <- function(x,y)
{
  return(match(x,y))
}

This code returns 3 as expected:

matchIndices(host[1],guest)

This is the loop I'd like to be able to replace with a succinct apply function (sapply?)

for (i in 1:length(host)) 
{ idx <- matchIndices(host[i],guest); 
  cat(paste(idx,host[i],"\n",sep=";"))
}

This code "works" in that it produces the output below, but I really want the result to be a vector, and I have a hunch that one of the apply functions will do the trick. I'm just stuck on how to write it. Any help would be most appreciated. Thanks.

3;A; NA;B; 2;C; 1;D;

Upvotes: 5

Views: 2780

Answers (3)

IRTFM
IRTFM

Reputation: 263301

sapply(host , function(x) which(guest==x))
$A
[1] 3

$B
integer(0)

$C
[1] 2

$D
[1] 1


unlist(sapply(host , function(x) which(guest==x)))

    A C D 
    3 2 1 

paste(host, sapply(host , function(x) which(guest==x)), sep=":", collapse=" ")
[1] "A:3 B:integer(0) C:2 D:1"

Upvotes: 2

Gavin Simpson
Gavin Simpson

Reputation: 174778

host <- c("A","B","C","D")
guest <- c("D","C","A","F")

matchIndices <- function(x,y) {
    return(match(x,y))
}

One (inefficient) way is to sapply over the host vector, passing in guest as an argument (note you could just simplify this to sapply(host, match, guest) but this illustrates a general way of approaching this sort of thing):

> sapply(host, matchIndices, guest)
 A  B  C  D 
 3 NA  2  1

However, this can be done directly using match as it accepts a vector first argument:

> match(host, guest)
[1]  3 NA  2  1

If you want a named vector as output,

> matched <- match(host, guest)
> names(matched) <- host
> matched
 A  B  C  D 
 3 NA  2  1

which could be wrapped into a function

matchIndices2 <- function(x, y) {
    matched <- match(x, y)
    names(matched) <- x
    return(matched)
}

returning

> matchIndices2(host, guest)
 A  B  C  D 
 3 NA  2  1

If you really want the names and the matches stuck together into a vector of strings, then:

> paste(match(host, guest), host, sep = ";")
[1] "3;A"  "NA;B" "2;C"  "1;D"

Upvotes: 8

Prasad Chalasani
Prasad Chalasani

Reputation: 20282

if you want the output vector in the host;guestNum format you would use do.call, paste, match as follows:

> do.call(paste, list(host, sapply(host, match, guest), sep = ';'))                                                                                     
[1] "A;3"  "B;NA" "C;2"  "D;1" 

Upvotes: 3

Related Questions