Как seq_along () два списка с циклом for - PullRequest
1 голос
/ 02 апреля 2020

У меня есть функция, которая должна повторять два ввода списка.

date <- as.list("JANUARY", "FEBRUARY")
type <- as.list("Education", "Government") 

Функция, похожая на clean(date, type)

Так вот код, который я пытался использовать:

for(i in (seq_along(date), seq_along(type)) {
  a <- date[i]
  b <- type[i]
  clean(a, b)
}

Но это не повторяет каждый элемент списка друг против друга, а скорее позиция списка с соответствующей позицией другого списка. Таким образом, вывод выглядит как результаты очистки для

ЯНВАРЬ: Образование, ФЕВРАЛЬ: Правительство, ЯНВАРЬ: Образование, ФЕВРАЛЬ: Правительство

Когда я хочу, чтобы он имел комбинацию

ЯНВАРЬ: Образование, ЯНВАРЬ: Правительство, ФЕВРАЛЬ: Образование, ФЕВРАЛЬ: Правительство

Я надеюсь, что это имеет смысл, и если кто-то может помочь, я был бы очень признателен.

Ответы [ 2 ]

2 голосов
/ 02 апреля 2020

Первая проблема: as.list работает только с первым аргументом, поэтому ваш date выглядит как "JANUARY". Чтобы решить эту проблему, используйте dat <- list(...).

as.list(1,2,3)
# [[1]]
# [1] 1
list(1,2,3)
# [[1]]
# [1] 1
# [[2]]
# [1] 2
# [[3]]
# [1] 3

Во-вторых, это что-то вроде «внешнего соединения», в котором вы хотите, чтобы каждый первый вектор был в паре с каждым из второго вектора. Функция outer делает что-то подобное с двумя свойствами:

  1. Ее возвращаемое значение равно matrix, что не всегда является необходимым. См. outer(1:3, 4:5,*), чтобы увидеть, как это выглядит.

  2. Он предлагает расширение и вызывает функцию один раз , поэтому мы можем видеть, что все выглядит примерно так:

    outer(1:3, 4:5, function(a, b) { browser(); a*b; })
    # Called from: FUN(X, Y, ...)
    debug at #1: a * b
    a
    # [1] 1 2 3 1 2 3
    b
    # [1] 4 4 4 5 5 5
    

    Может быть, проще увидеть пары следующим образом:

    cbind(a,b)
    #      a b
    # [1,] 1 4
    # [2,] 2 4
    # [3,] 3 4
    # [4,] 1 5
    # [5,] 2 5
    # [6,] 3 5
    

    Таким образом, наша операция должна иметь возможность обрабатывать все данные одновременно.

    a*b
    # [1]  4  8 12  5 10 15
    

    Часто функции (вашему clean) требуется одиночный знак в каждом аргументе, поэтому outer не всегда работает хорошо.

Альтернатива это использовать expand.grid.

eg <- expand.grid(date = date, type = type, stringsAsFactors = FALSE)
eg
#       date       type
# 1  JANUARY  Education
# 2 FEBRUARY  Education
# 3  JANUARY Government
# 4 FEBRUARY Government

Отсюда, есть несколько подходов, в зависимости от вашего мастерства и предпочтений элегантности. mapply аналогичен sapply в том, что он пытается вернуть упрощенную структуру, но он принимает функцию с произвольным числом векторов / списков:

mapply(function(a, b) paste(a, b, sep = ","), eg$date, eg$type)
# [1] "JANUARY,Education"   "FEBRUARY,Education"  "JANUARY,Government"  "FEBRUARY,Government"

или Map, вариант, который всегда возвращает list (это мое предпочтение, поскольку мне нравится знать , что возвращается):

Map(function(a, b) paste(a, b, sep = ","), eg$date, eg$type)
# [[1]]
# [1] "JANUARY,Education"
# [[2]]
# [1] "FEBRUARY,Education"
# [[3]]
# [1] "JANUARY,Government"
# [[4]]
# [1] "FEBRUARY,Government"

В вашем случае это может быть просто out <- Map(clean, eg$date, eg$type).

Однако некоторые люди предпочитают петли for, и поэтому эквивалент выглядит примерно так:

for (i in seq_len(nrow(eg))) {
  print(paste(eg$date[i], eg$type[i], sep = ","))
}
# [1] "JANUARY,Education"
# [1] "FEBRUARY,Education"
# [1] "JANUARY,Government"
# [1] "FEBRUARY,Government"

### your equivalent:
for (i in seq_len(nrow(eg))) {
  clean(eg$date[i], eg$type[i])
}

Чтобы увидеть, как Mapmapply ), может быть полезно «развернуть» происходящее. Если я сделаю Map(paste, eg$date, eg$type) (а списки будут длиннее, скажем, длина n), тогда он действительно сделает

paste(eg$date[1], eg$type[1])
paste(eg$date[2], eg$type[2])
...
paste(eg$date[n], eg$type[n])

и обернет каждое возвращаемое значение в list (для Map) или vector (для mapply, если данные одного типа / форма / длина / тусклый /...).

0 голосов
/ 02 апреля 2020

Вот подход, использующий циклы for, если вы действительно хотите использовать один из них:

date <- list("JANUARY", "FEBRUARY")
type <- list("Education", "Government") 

clean <- function (a, b){
  c <- list()
  k <- 1
for (i in seq_along(a)) {
  for (j in seq_along(b)) {
    c[k] <- paste(a[[i]],b[[j]],sep=",")
    k <- k+1
  }
}
  return(c)
}

Выход

> clean(date,type)
[[1]]
[1] "JANUARY,Education"

[[2]]
[1] "JANUARY,Government"

[[3]]
[1] "FEBRUARY,Education"

[[4]]
[1] "FEBRUARY,Government"
...