Noya Ran
Noya Ran

Reputation: 13

How to build a function with factor and vector

I need to build a function which will receive a vector and a factor and will return a list containing the division of the vector by factor levels. Meaning it should take the levels from the factor, and for each level, create an item, or element, in the list containing the subset of the vector that is equivalent to the level in the factor. The level name should be used to name the list item. It is a vector and a factor in a data frame.

Right now this is what I have but it only returns list on NA:

mk_factor_list <- function(x,f) {

 {
   {if (length(x) == length(f) ) 
   {print(":)")}
     else { stop(print("f and x don't have the same length"))}
  listf <- rep (NA, length(levels(f)))  
    for (i in levels (f)) 
  listf[i] <-x[i] 


 }}
  return (listf)
}

Upvotes: 0

Views: 31

Answers (1)

Gregor Thomas
Gregor Thomas

Reputation: 145895

A few comments on your attempt:

  • (a) your print(':)') can be nice for debugging, but if you intend to leave it in the function when you're done, use message not print so users can disable it if they want.
  • (b) You don't need print() inside stop(). Just use stop("f and x ...").
  • (c) listf is a vector, not a list when you define it as listf <- rep (NA, length(levels(f))). Make it a list by using listf = list() instead.
  • (d) Let's say your factor has levels 'a' and 'b'. When you do for (i in levels (f)), that means i will first be 'a' and then it will be 'b'. TSo when you assign listf[i] <- x[i] what R sees is listf['a'] <- x['a']. listf['a'] is bad only because you should be using double brackets for a single list item: listf[['a']] <- ... is needed. x['a'] doesn't make any sense. You want the elements of x corresponding to which elements of f are 'a', so use x[which(f == i)].

Putting those together, you should be able to get a working answer. But if you want to see a really pro way of doing this, type split.default into your console and see R core version.


Based on your comment, here's a working version. Most of what I did to get from your comment was delete lines (why all the extra { at the beginning?) and replace with code from my bullets above.

mk_factor_list <- function(x, f) {
  if (length(x) != length(f)) {
    stop("f and x don't have the same length")
  }
  listf = list()
  for (i in levels (f)) {
    listf[[i]] <- x[which(f == i)]
  }
  return(listf)
}

mk_factor_list(x = 1:5, f = factor(c('a', 'b', 'a', 'b', 'c'))
# $a
# [1] 1 3
# 
# $b
# [1] 2 4
# 
# $c
# [1] 5

Upvotes: 1

Related Questions