0

A - I have a list containing igraph graph objects:

goodgg

[[1]]
IGRAPH UN-- 3 3 -- 
+ attr: name (v/c), color (v/c), value (e/n), sourceID (e/n), targetID (e/n)
+ edges (vertex names):
[1] 89315--89316 89315--89928 89316--89928

[[2]]
IGRAPH UN-- 3 2 -- 
+ attr: name (v/c), color (v/c), value (e/n), sourceID (e/n), targetID (e/n)
+ edges (vertex names):
[1] 106277--106278 106278--106279

I can combine these into a single object using [union][1]:

combine = graph.union(goodgg[[1]], goodgg[[2]], byname=T)

combine
IGRAPH UN-- 6 5 -- 
+ attr: color_1 (v/c), color_2 (v/c), name (v/c)
+ edges (vertex names):

From this, I can extract particular attributes e.g. a color, which lines up with the order of the original objects (1 - 2):

as.list(get.vertex.attribute(combine))
$color_1
[1] "red"    "red"    "orange" NA       NA       NA      

$color_2
[1] NA    NA    NA    "red" "red" "red"

$name
[1] "89315"  "89316"  "89928"  "106277" "106278" "106279"

How can I extract the non NA values in $color_1 and $color_2 and merge them into a new list when I have an arbitrary number of color_n entries? (E.g. I have n entries)?

To get:

[1] "red"    "red"    "orange" "red"    "red"    "red"

What I tried (which does not work for n color_ variables:

In this simple case I can do what this answer did here:

V(combine)$color <- ifelse(is.na(get.vertex.attribute(combine)$color_1), get.vertex.attribute(combine)$color_2,get.vertex.attribute(combine)$color_1)

get.vertex.attribute(combine)$color
[1] "red"    "red"    "orange" "red"    "red"    "red" 

However, in reality my list could have n elements. How can I adjust this to account for n elements?

I considered using multiple nested IFELSE statements such as here and here a la:

V(combine)$color <- ifelse(is.na(get.vertex.attribute(combine)$color_1), ifelse(is.na(get.vertex.attribute(combine)$color_2), ifelse(get.vertex.attribute(combine)$color_3)......))

This does not work for unknown n attributes and does not solve the issue of having an unknown number n of attributes to work with.

Many thanks for your help.

Chuck
  • 3,664
  • 7
  • 42
  • 76

1 Answers1

1

You can use Reduce to "cumulatively" apply a function over a vector:

set.seed(125)

color_choices <- c("red", "orange", NA)

color_samples <- replicate(
  4,
  sample(color_choices, 5, replace = TRUE),
  simplify = FALSE
)
color_samples
# [[1]]
# [1] NA       "red"    "red"    "orange" NA
# 
# [[2]]
# [1] NA       "orange" "red"    "orange" "orange"
# 
# [[3]]
# [1] "red"    NA       "orange" "red"    "orange"
# 
# [[4]]
# [1] "orange" "orange" NA       NA       NA

Reduce(
  f = function(a, b) ifelse(is.na(a), b, a),
  x = color_samples
)
# [1] [1] "red"    "red"    "red"    "orange" "orange"

In this case, Reduce applied the function to the first and second elements, then to that result and the third element, then to that result and the fourth element. If the list were longer, it would've kept going on that way.

Edit for your specific situation: save the list of attributes, find which have names like color_n, and then use the Reduce solution on those.

combine_attributes <- as.list(get.vertex.attribute(combine))

Because I don't have your data, let's just say combine_attributes looks like the color_samples created above with an extra element:

combine_attributes
# $color_1
# [1] NA       "red"    "red"    "orange" NA      
# 
# $color_2
# [1] NA       "orange" "red"    "orange" "orange"
# 
# $color_3
# [1] "red"    NA       "orange" "red"    "orange"
# 
# $color_4
# [1] "orange" "orange" NA       NA       NA      
# 
# $name
# [1] "89315"  "89316"  "89928"  "106277" "106278"

color_attributes <- grep(
  "^color_\\d+$",
  names(combine_attributes),
  value = TRUE
)

color_attributes
# [1] "color_1" "color_2" "color_3" "color_4"

Reduce(
  f = function(a, b) ifelse(is.na(a), b, a),
  x = combine_attributes[color_attributes]
)
# [1] "red"    "red"    "red"    "orange" "orange"
Nathan Werth
  • 5,093
  • 18
  • 25
  • In my case, I don't have `a` and `b` predefined or allocated. Instead, I can only get the colours from `get.vertex.attribute(combine)` which gives the structure in the question. – Chuck Dec 04 '17 at 16:33
  • Hi Nathan, thanks for your answer. I edited my question to try and be more clear on my needs. Many thanks for your answer. It's close to what I need. – Chuck Dec 04 '17 at 16:42