-1

If I have a symmetric binary operator that I want to apply over the pairs of elements from a list, is there an easy way I can do this in R? I tried:

A <- list(1,2,3)
mapply(function(x,y) x+y, A,A)

but this only gives x[n]+y[n] for all n=1..N but I want x[n]+y[m] for all m=1..n, n=1..N returned as a list. outer(..) does that for m=1..N, n=1..N which involves redundant computation so I want to discount that.

Notice I don't want solution to this simple example. I need a general solution that works for non-numeric input as well. The thing I'm trying to do is like:

mapply(function(set_1, set_2) setequal(intersect(set_1, set_2),  set_3), list_of_sets, list_of_sets)

In both cases addition and intersection are symmetric. In the first example, I expect list(3,4,5) from list(1+2,1+3,2+3). For the second case me input list_of_sets is:

> list_of_sets
[[1]]
numeric(0)

[[2]]
[1] 1

[[3]]
[1] 2

[[4]]
[1] 1 2

[[5]]
[1] 3

[[6]]
[1] 1 3

[[7]]
[1] 2 3

[[8]]
[1] 1 2 3

and set_3 being c(1,2) as a simple example.

monotonic
  • 394
  • 4
  • 20

2 Answers2

5

You may use outer -

values <- c(1, 2, 3)
outer(values, values, `+`)

#     [,1] [,2] [,3]
#[1,]    2    3    4
#[2,]    3    4    5
#[3,]    4    5    6

outer also works for non-numeric input. If the function that you want to apply is not vectorised you can use Vectorize. Since OP did not provide an example I have created one of my own.

list_of_sets_1 <- list(c('a', 'b', 'c'), c('a'))
list_of_sets_2 <- list(c('a', 'c'), c('a', 'b'))

fun <- function(x, y) intersect(x, y)
result <- outer(list_of_sets_1, list_of_sets_2, Vectorize(fun))
result
Ronak Shah
  • 377,200
  • 20
  • 156
  • 213
1

We need combn to do pairwise computation without redundancy

combn(A, 2, FUN = function(x) x[[1]] + x[[2]], simplify = FALSE)

-output

[[1]]
[1] 3

[[2]]
[1] 4

[[3]]
[1] 5

This will also work with non-numeric elements

list_of_sets <- list(c('a', 'b', 'c'), "a", c("a", "c"))
combn(list_of_sets, 2, FUN = function(x) Reduce(intersect, x), simplify = FALSE)

-output

[[1]]
[1] "a"

[[2]]
[1] "a" "c"

[[3]]
[1] "a"

We may also do

combn(list_of_sets, 2, FUN = function(x) 
   setequal(intersect(x[[1]], x[[2]]), set_3), simplify = FALSE)
akrun
  • 874,273
  • 37
  • 540
  • 662
  • Hi, I updated the question a little bit. Is it possible to do this without 'Reduce'? – monotonic Oct 27 '21 at 21:41
  • @monotonic did you meant `combn(list_of_sets, 2, FUN = function(x) intersect(x[[1]], x[[2]]), simplify = FALSE)` – akrun Oct 27 '21 at 21:42
  • @monotonic is it possible for you to show the expected output for the `list_of_sets` along with the input data so that it is easier to test – akrun Oct 27 '21 at 21:44
  • Sure. An example: `> set_1 [[1]] numeric(0) [[2]] [1] 1 [[3]] [1] 2 [[4]] [1] 1 2 [[5]] [1] 3 [[6]] [1] 1 3 [[7]] [1] 2 3 [[8]] [1] 1 2 3` – monotonic Oct 27 '21 at 21:45
  • @monotonic please update your post with a small reprodcuible example and expected output. From the comments, it is difficult to read – akrun Oct 27 '21 at 21:46
  • @montonic do you want `combn(list_of_sets, 2, FUN = function(x) setequal(intersect(x[[1]], x[[2]]), set_3), simplify = FALSE)` – akrun Oct 27 '21 at 21:54