Ursus Frost
Ursus Frost

Reputation: 405

How to test if an R object is a named numeric vector?

I'd like to know if there is a simple and robust way to test if an object is a named numeric vector. Here is an example:

data <- c(2.3, 3.5, 5.7)
typeof(data)
#[1] "double"
mode(data)
#[1] "numeric"
str(data)
# num [1:3] 2.3 3.5 5.7
is.vector(data)
#[1] TRUE
is.numeric(data)
#[1] TRUE

So as you can see from the above, I have created a numeric vector. Now I assign names to the elements.

named_vec <- structure(data, names = c('a', 'b', 'c'))
named_vec <- structure(data, names = c('a', 'b', 'c'))
str(named_vec)
# Named num [1:3] 2.3 3.5 5.7
# - attr(*, "names")= chr [1:3] "a" "b" "c"
names(named_vec)
#[1] "a" "b" "c"

I could use a few compound conditions such as:

if(is.vector(named_vec) & is.numeric(named_vec) & !is.null(names(named_vec)))           {
   "named_vec is a named numeric vector"
 } else {
   "named_vec is not a named numeric vector"
 }
#[1] "named_vec is a named numeric vector"

Or something like this, but it feels like it could fall prey to corner cases:

length(names(named_vec)) == length(named_vec)
#[1] TRUE
names(data)
#NULL

I'm looking for something that is concise and robust.

Upvotes: 4

Views: 2644

Answers (3)

GegznaV
GegznaV

Reputation: 5580

For this kind of tests, I use package checkmate. It is fast and easy to use.

For named numeric vectors, check functions test_numeric(), check_numeric(), and assert_numeric() with parameter names = "named" (for other options, see type under "Arguments" section). The functions differ in output so you should decide, which is the most suitable for you.

Returns logical:

checkmate::test_numeric(1, names = "named")
#> [1] FALSE
checkmate::test_numeric(c(a = 1), names = "named")
#> [1] TRUE
checkmate::test_numeric(c(a = "A"), names = "named")
#> [1] FALSE

Returns string:

checkmate::check_numeric("1", names = "named")
#> [1] "Must be of type 'numeric', not 'character'"
checkmate::check_numeric(1, names = "named")
#> [1] "Vector must be named"

Returns error message:

checkmate::assert_numeric(1, names = "named")
#> Error in withCallingHandlers({: Assertion on '1' failed: Vector must be named.

Upvotes: 1

Ursus Frost
Ursus Frost

Reputation: 405

My answer simply combines the comments of @nicola and @Gregor along with the answer provided by @droubi:

Create a new function IsNamedVector. Below is example:

Create Example Data Set

> data <- c(2.3, 3.5, 5.7)
> typeof(data)
[1] "double"
> mode(data)
[1] "numeric"
> str(data)
 num [1:3] 2.3 3.5 5.7
> is.numeric(data)
[1] TRUE
> is.vector(data)
[1] TRUE
> named_vec <- structure(data, names = c('a', 'b', 'c'))
> str(named_vec)
 Named num [1:3] 2.3 3.5 5.7
 - attr(*, "names")= chr [1:3] "a" "b" "c"
> names(named_vec)
[1] "a" "b" "c"

Create Custom Function

> IsNamedVector <- function(VECTOR) {
+   is.vector(VECTOR) & is.numeric(VECTOR) & !is.null(names(VECTOR)) & 
+      !any(is.na(names(VECTOR)))
+ }

Test Function

> length(names(named_vec)) == length(named_vec)
[1] TRUE
> names(data)
NULL
> !all(is.na(names(named_vec)))
[1] TRUE
> missing_names_vec <- structure(data, names = c('a', 'b'))
> str(missing_names_vec)
 Named num [1:3] 2.3 3.5 5.7
 - attr(*, "names")= chr [1:3] "a" "b" NA
> IsNamedVector(named_vec)
[1] TRUE
> IsNamedVector(missing_names_vec)
[1] FALSE

Thanks for the help.

Upvotes: 2

droubi
droubi

Reputation: 103

The only problem I see in your firt solution (the if clause) is that the names of the vector could be incomplete, and I do not know if thats acceptable in your case.

In the second solution, a non-numeric named vector would pass the verification, right? And it seems to me that this is not what you desire.

If you could provide more details about what you want exactly to do with this verification, I could help you a little more.

It is also easier to do

is.vector(f, mode = "numeric")

Thus you verifie both conditions (vector and numeric). Read is.vector help.

Upvotes: 2

Related Questions