1

I have a list similar to the following:

> x <- list(
    j = "first",
    k = "second",
    l = "third",
    m = c("first", "second"),
    n = c("first", "second", "third"),
    o = c("first", "third"),
    p = c("second", "third"),
    q = "first",
    r = "third")

I need to create index of the string components based on their value. I can easily do this with which for components containing elements of single strings:

> which(x == "third")
l r
3 9

Or even for multiple components that contain elements of single strings:

> which(x == "first" | x == "second" | x == "third")
j k l q r
1 2 3 8 9

The returned value shows me the number of the components in the list and its name. However, sometimes I would need to obtain an index of components that contain character vectors that have more than one element such as m (c("first", "second")) or n (c("first", "second", "third")). That is, the length of the character vector in the components would be larger than 1. I thought the following would work:

which(x == c("first", "second"))

I was wrong, the output was:

j k
1 2
Warning message:
In x == c("first", "second") :
  longer object length is not a multiple of shorter object length

It is the same when I try with more than one condition:

> which(x == "first" | x == c("first", "second"))
j k q
1 2 8
Warning message:
In x == c("first", "second") :
  longer object length is not a multiple of shorter object length

The desired output from which(x == c("first", "second")) is:

m
4

The desired output from which(x == "first" | x == c("first", "second")) is:

j m q
1 4 8

How this could be done? Not necessary to use which, thou...

10 Rep
  • 2,217
  • 7
  • 19
  • 33
panman
  • 1,179
  • 1
  • 13
  • 33
  • 1
    Use `%in%` instead of `==` if you want compare against a set of values. P.S. you can't downgrade a post on SO, maybe downvote. – David Arenburg Nov 22 '15 at 13:20
  • It is not a duplicate! This question is about doing this element-wise in a list.... – Arthur Nov 22 '15 at 13:21
  • @panman use sapply to apply a function (like `function(v) 'first' %in% v`) element-wise in a list. At the end, it should look like: `which(sapply(x, function(v) 'first' %in% v))`. – Arthur Nov 22 '15 at 13:24
  • What is your desired output for `which(x == c("first", "second"))`? – David Arenburg Nov 22 '15 at 13:26
  • @ David Arenburg: Not really what I want. With `which(x %in% c("first", "second"))` it returns 1, 2, and 8 which is quite different than what I am looking for. Yes, downvote, not downgrade. I understand you find my question a duplicate, can you please provide a link? – panman Nov 22 '15 at 13:28
  • Can you explain what is your desired output for `which(x == c("first", "second"))` then? You only showed what you don't want to achieve rather what you want to achieve. – David Arenburg Nov 22 '15 at 13:30
  • For example this : `grep("first, second", lapply(x, toString))` or maybe this `which("first, second" == lapply(x, toString))`? – David Arenburg Nov 22 '15 at 13:36
  • @ David Arenburg: `which("first, second" == lapply(x, toString))` works and returns `m` (4). But what about the case `which(x == "first" | x == c("first", "second"))` where I need `j` and `m`? (see the updated quastion) – panman Nov 22 '15 at 13:41
  • 1
    You could probably do something like ```which(sapply(lapply(x, toString), `%in%`, c("first", "first, second")))```. What about `q` btw, why isn't it included in your desired output? It's the same as `j`, no? – David Arenburg Nov 22 '15 at 13:44
  • @ David Arenburg: returns an error `Error: unexpected SPECIAL in "which(sapply(lapply(x, toString), %in%"`. You are right about `q`, was my mistake, sorry about this. I edited the question, now is correct. – panman Nov 22 '15 at 13:50
  • Don't know. Works perfectly fine for me with your data set. See Alexis answer, it's probably better. – David Arenburg Nov 22 '15 at 14:00
  • @ David Arenburg: Will try it later again. Thank you very much for your efforts David. – panman Nov 22 '15 at 14:10

1 Answers1

3

By using "list" == "character" the "list" is converted to "character" as as.character(x) which, I assume, is unwanted. You could use match to compare between "list"s corresponding elements:

ff = function(x, table) which(setNames(table %in% x, names(table)))
ff(list("third"), x)
#l r 
#3 9 
ff(list("first", "second", "third"), x) # your "|"
#j k l q r 
#1 2 3 8 9 
ff(list(c("first", "second")), x)
#m 
#4 
ff(list("first", c("first", "second")), x) # your "|"
#j m q 
#1 4 8 
alexis_laz
  • 12,884
  • 4
  • 27
  • 37
  • That's a nice approach as always. Wouldn't have to convert this to a `list`. – David Arenburg Nov 22 '15 at 14:03
  • Perfect! Exactly what needed. Works flawlessly, I tried it with other combinations and adding even more elements I would like to include. Works like charm. Thank you very much Alexis! – panman Nov 22 '15 at 14:09