Застегивать или перечислять в R?

84

Каковы эквиваленты R для этих пониманий списков Python:

[(i,j) for i,j in zip(index, Values)]
[(i,j) for i,j in enumerate(Values)]
[(i,j) for i,j in enumerate(range(10,20))]   %MWE, indexing or enumerating to 
                                            %keep up with the index, there may 
                                            %be some parameter to look this up

Пример с выводом

>>> [(i,j) for i,j in enumerate(range(10,20))]
[(0, 10), (1, 11), (2, 12), (3, 13), (4, 14), (5, 15), (6, 16), (7, 17), (8, 18), (9, 19)]

Я решил эту проблему ранее с помощью некоторого трюка в R, но больше не могу вспомнить, первой идеей было itertools -pkg, но я надеюсь найти более идиоматический способ сделать что-то.

ххх
источник
2
Если бы вы могли привести небольшой рабочий пример для тех из нас, кто не знаком с Python, это могло бы увеличить количество потенциальных ответчиков. Я предполагаю, что последнийexpand.grid(i=10:20,j=10:20)
Бен Болкер,
@BenBolker: добавлен вывод - теперь понятно? Это могло быть посложнее, но логика важна ...
чч
1
Я согласен с @DWin. Неразумно ожидать однозначного сопоставления между структурами данных в R и Python. Если вам нужны хорошие ответы, вы должны указать, как вы хотите, чтобы результат выглядел в R, а не в Python.
joran
as.vector(rbind(1:10, 11:20))
Между

Ответы:

47

Ответ для питона enumerate:

В R список упорядочен (см. Этот ответ ). Таким образом, все, что вам нужно, это проиндексировать либо ключи (используя names()[i]), либо значения (используя [[i]]).

Использование seq_along(в качестве альтернативы можно сделать for(i in 1:length(mylist)){...}):

> mylist <- list('a'=10,'b'=20,'c'=30)
> for (i in seq_along(mylist)){
+   print(paste(i,names(mylist)[i],mylist[[i]]))
+ }
[1] "1 a 10"
[1] "2 b 20"
[1] "3 c 30"

Ответ для питона zip:

См. Один из приведенных выше ответов, чтобы имитировать список кортежей. Я предпочитаю фрейм данных, как показано в ответе BondedDust:

> x <- 1:3
> y <- 4:6
> data.frame(x=x, y=y)
  x y
1 1 4
2 2 5
3 3 6
Тежа Тулабандхула
источник
1
Продолжая ваш первый пример во втором,data.frame(names=labels(mylist),values=unlist(mylist),row.names = 1:length(mylist))
Джозия Йодер,
вопрос о производительности: вызов имен (mylist) [i] должен выполнять свою работу каждый раз или это тривиальная операция? Мне интересно, не лучше ли назначить его name_list перед циклом
markgalassi
42

Были некоторые дискуссии по поводу понимания списков для R, например, здесь или там . Хэш - пакет даже предлагает словарь структуры. Однако, как говорили другие, трудно попытаться сопоставить возможности одного языка с другим (даже если это то, что на самом деле предлагает Сравнение языков программирования ) без четкого понимания того, для чего он должен использоваться. Например, я могу имитировать Python zip()в R следующим образом:

Python

In [1]: x = [1,2,3]
In [2]: y = [4,5,6]
In [3]: zip(x, y)
Out[3]: [(1, 4), (2, 5), (3, 6)]

р

> x <- 1:3
> y <- 4:6
> list(x, y)                     # gives a simple list
> as.list(paste(x, y))           # three tuples, as a list of characters
> mapply(list, x, y, SIMPLIFY=F) # gives a list of 3 tuples
> rbind(x, y)                    # gives a 2x3 matrix 

Как видно, это действительно зависит от того, что вы хотите делать с результатом впоследствии.

chl
источник
1
Я думаю, вопрос в том, что вы используете, когда используете zip в Python. обычно используется для понимания списка с несколькими аргументами, поэтому mapply обрабатывает это напрямую.
seanv507 06
6
Это mapplyто, что мы хотим от прямого аналога.
StephenBoesch
@javadba mapplyохватывает наиболее распространенный вариант использования: zip, затем map.
Josiah Yoder
8

Другой вариант, который создаст список векторов, - использовать функцию Map, как показано здесь @peterhurford: https://rdrr.io/github/peterhurford/funtools/src/R/zippers.R

> x <- 1:3
> y <- 4:6
> z <- 7:9
> Map(c, x, y, z)
[[1]]
[1] 1 4 7

[[2]]
[1] 2 5 8

[[3]]
[1] 3 6 9
Wphampton
источник
В Python, первичное использование почтового индекса является итерация по несколько векторов / списков: for xi, yi in zip(x, y): .... +1 за самое элегантное решение, которое я видел до сих пор, чтобы сделать это в R:for (xi.yi in Map(c, x, y)) { xi <- xi.yi[1]; yi <- xi.yi[2]; ... }
sgrubsmyon 01
6

Если это печатное представление матрицы Python, то этот код:

j <- 10:20
matrix(c(seq_along(j), j), ncol=2)
#------------
      [,1] [,2]
 [1,]    1   10
 [2,]    2   11
 [3,]    3   12
 [4,]    4   13
 [5,]    5   14
 [6,]    6   15
 [7,]    7   16
 [8,]    8   17
 [9,]    9   18
[10,]   10   19
[11,]   11   20

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

Учитывая руководство @ chi, мы также можем предложить использовать очень R-центрическую структуру dataframe.

x <- 1:3
y <- 4:6
dfrm <- data.frame(x=x, y=y)

... который обладает гибкостью списка с точки зрения типов столбцов и функциями доступа матрицы с точки зрения индексации строк и столбцов. Или можно использовать запрос hhh и создать неявно проиндексированные значения j-вектора, 10:20используя rownamesвектор, который по умолчанию начинается с «1», но который может быть изменен, чтобы стать вектором символов, начинающимся с «0»

dfrm <- data.frame(j=10:20)
dfrm[3, ]
#[1] 12

 rownames(dfrm) <- 0:10
 dfrm["0",]
# [1] 10

К сожалению, неосторожные люди обнаружат, что dfrm [0,] не является удачным вызовом, возвращающим вектор длины 0.

IRTFM
источник
+1 за элегантное решение. (Нет, это не матрицы Python, а, как вы уже догадались, список кортежей .)
chl
4

Чтобы использовать понимание списков в стиле Python с перечислениями, такими как нумерованные списки, одним из способов является установка пакета List- LCcomplationion (разработан в 2018 г.) и пакета itertools (разработан в 2015 г.).

Составить список в R

Вы можете найти LCпакет здесь .

install.packages("devtools")
devtools::install_github("mailund/lc")

пример

> library(itertools); library(lc)
> lc(paste(x$index, x$value), x=as.list(enumerate(rnorm(5))), )
[[1]]
[1] "1 -0.715651978438808"

[[2]]
[1] "2 -1.35430822605807"

[[3]]
[1] "3 -0.162872340884235"

[[4]]
[1] "4 1.42909760816254"

[[5]]
[1] "5 -0.880755983937781"

где синтаксис программирования еще не так чист и отполирован, как в Python, но функционально работает, и его справочная информация:

"Синтаксис следующий: lc (expr, lists, predicates), где expr - это какое-то выражение, которое нужно оценить для всех элементов в списках, где списки - это один или несколько именованных списков, где они определяются именем и именем выражения. = list_expr, а где предикаты - это выражения, которые должны оцениваться как логическое значение. Например, чтобы получить список всех четных чисел в квадрате из списка x, мы можем написать lc (x ** 2, x = x, x% % 2 == 0). Результатом вызова lc является список, составленный из выражений в expr, для всех элементов во входных списках, в которых предикаты оцениваются как истинные. "

где обратите внимание, что вы можете оставить предикаты пустыми, например, в приведенном выше примере.

Инструменты itertools и перечисления в стиле Python

Вы можете использовать itertools R, который очень похож на itertools Python, далее в Cran здесь

library(itertools)

где описано

«Различные инструменты для создания итераторов, многие из которых созданы по образцу функций в модуле Python itertools, а другие - по образцу функций в пакете 'snow'».

Пример. перечисление

> for (a in as.list(enumerate(rnorm(5)))) { print(paste(a$index, "index:", a$value))}
[1] "1 index: 1.63314811372568"
[1] "2 index: -0.983865948988314"
[1] "3 index: -1.27096072277818"
[1] "4 index: 0.313193212706331"
[1] "5 index: 1.25226639725357"

Пример. перечисление с помощью ZIP

> for (h in as.list(izip(a=1:5, b=letters[1:5]))) { print(paste(h$a, "index:", h$b))}
[1] "1 index: a"
[1] "2 index: b"
[1] "3 index: c"
[1] "4 index: d"
[1] "5 index: e"
ххх
источник
4

zipи enumerateне особо сложно реализовать в R:

#' zip(1:5,1:10)
zip <- function(...) {
  mapply(list, ..., SIMPLIFY = FALSE)
}

Enumerate просто определить с точки зрения zip:

#' enumerate(l=LETTERS)
enumerate <- function(...) {
  zip(ix=seq_along(..1), ...)
}

Поскольку это правильные функции, мы можем использовать их, ...чтобы сделать их довольно гибкими и краткими, а также воспользоваться поведением mapply, например, повторным использованием входных данных и правильным присвоением имен выходным данным.

Нил Фульц
источник
1
Они были добавлены в stackoverflowпакет, fwiw.
Нил Фульц
0
# similar to python. return a list of list. Short sequences get recycled.
zip <- function(...){ 
    all.list <- list(...)
    ele.names <- names(all.list)
    max.length <- max(sapply(all.list, length))
    lapply(0:(max.length - 1), function(i) {
        res <- lapply(all.list, function(l) l[i %% length(l) + 1]) 
        names(res) <- ele.names
        res
    })
}
Лист
источник
Пожалуйста, опишите, что делает этот блок кода.
Кейван Эсбати
эта функция делает то же самое с «mapply (list, x, y, SIMPLIFY = F)», на которое указал
@chl
0

Этого можно добиться с помощью двух операторов вставки:

str1 <- paste(1:11, 10:20, sep=",", collapse='), (')
paste("(", str1, ")", sep = "")

На выходе получится следующее:

'(1,10), (2,11), (3,12), (4,13), (5,14), (6,15), (7,16), (8,17), (9,18), (10,19), (11,20)'
крави
источник
0

Для python эквивалент 'enumerate' в R. Сохранение векторов в списке и итерация по ним с индексом должны работать нормально.

vect1 <- c('A', 'B', 'C')
vect2 <- c('a', 'b', 'c')

# eqiv to zip values:
idx_list <- list(vect1, vect2)
idx_vect <- c(1:length(idx_list[[1]]))

for(i in idx_vect){
    x <- idx_list[[1]][i]
    j <- idx_list[[2]][i]
    print(c(i, x, j))
}

Вывод:

[1] "1" "A" "a"
[1] "2" "B" "b"
[1] "3" "C" "c"

R 'list' - хороший банк для хранения векторов и индексации.

Сурья
источник