Zip oder Aufzählung in R?

83

Was sind die R-Äquivalente für diese Python-Listenverständnisse:

[(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

Beispiel mit Ausgabe

>>> [(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)]

Ich habe dieses Problem früher mit einem Trick in R gelöst, kann mich aber nicht mehr erinnern. Die erste Idee war itertools -pkg, aber ich hoffe, eine idiomatischere Art zu finden, Dinge zu tun.

hhh
quelle
2
Wenn Sie ein kleines Beispiel für diejenigen von uns geben könnten, die mit Python nicht vertraut sind, könnte dies die Anzahl der potenziellen Antwortenden erhöhen. Ich vermute, dass der letzte istexpand.grid(i=10:20,j=10:20)
Ben Bolker
@ BenBolker: Ausgabe hinzugefügt - jetzt klar? Es könnte schwieriger sein, aber die Logik ist wichtig ...
hhh
1
Ich stimme @DWin zu. Es ist nicht zumutbar, eine Eins-zu-Eins-Zuordnung zwischen Datenstrukturen in R und Python zu erwarten. Wenn Sie gute Antworten wünschen, sollten Sie angeben, wie das Ergebnis in R und nicht in Python aussehen soll .
Joran
Übrigens, hier ist eine nette Möglichkeit, die beiden Listen zu as.vector(rbind(1:10, 11:20))
komprimieren

Antworten:

45

Antwort für Python enumerate:

In R ist eine Liste geordnet (siehe diese Antwort ). Sie müssen also nur entweder Schlüssel (using names()[i]) oder Werte (using [[i]]) indizieren .

Verwenden seq_along(alternativ kann 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"

Antwort für Python zip:

Sehen Sie sich eine der obigen Antworten an, um die Liste der Tupel nachzuahmen. Ich bevorzuge einen Datenrahmen, wie in der Antwort von BondedDust gezeigt:

> x <- 1:3
> y <- 4:6
> data.frame(x=x, y=y)
  x y
1 1 4
2 2 5
3 3 6
Theja
quelle
1
Um Ihr erstes Beispiel in das zweite fortzusetzen,data.frame(names=labels(mylist),values=unlist(mylist),row.names = 1:length(mylist))
Josiah Yoder
42

Es gab einige Diskussionen über das Listenverständnis für R, z . B. hier oder da . Das Hash- Paket bietet sogar eine wörterbuchartige Struktur. Wie andere sagten, ist es jedoch schwierig zu versuchen, eine Spracheinrichtung einer anderen zuzuordnen (selbst wenn dies der Vergleich von Programmiersprachen tatsächlich bietet), ohne ein klares Verständnis dafür zu haben, woran es gewöhnt sein soll. Zum Beispiel kann ich Python zip()in R wie folgt nachahmen :

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)]

R.

> 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 

Wie zu sehen ist, hängt dies wirklich davon ab, was Sie anschließend mit dem Ergebnis machen möchten.

chl
quelle
1
Ich denke, die Frage ist, was Sie verwenden, wenn Sie zip in Python verwenden würden. Die typische Verwendung besteht darin, ein Listenverständnis mit mehreren Argumenten zu erstellen, sodass dies direkt zugeordnet wird.
Seanv507
6
Das mapplywollen wir für das direkte Analog.
StephenBoesch
@javadba mapplybehandelt den häufigsten Anwendungsfall: zip, dann map.
Josiah Yoder
8

Eine weitere Option, mit der eine Liste von Vektoren erstellt wird, ist die Verwendung der Map-Funktion, wie sie hier von @peterhurford angezeigt wird: 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
quelle
In Python wird Zip hauptsächlich über mehrere Vektoren / Listen iteriert : for xi, yi in zip(x, y): .... +1 für die eleganteste Lösung, die ich bisher gesehen habe, um dies in R:for (xi.yi in Map(c, x, y)) { xi <- xi.yi[1]; yi <- xi.yi[2]; ... }
sgrubsmyon
6

Wenn dies die Python-Druckdarstellung einer Matrix ist, dann dieser Code:

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

Sie lassen diejenigen von uns, die keine Python-Benutzer sind, immer noch im Dunkeln, was die Struktur Ihrer gewünschten Ausgabe betrifft. Sie verwenden den Begriff "Liste", aber die Ausgabe schlägt einen geordneten Satz von Tupeln vor.

In Anbetracht der Anleitung von @ chi könnten wir auch vorschlagen, die sehr R-zentrierte 'Datenrahmen'-Struktur zu verwenden

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

... die die Flexibilität einer Liste in Bezug auf Spaltentypen und die Zugriffsfunktionen einer Matrix in Bezug auf die Zeilen- und Spaltenindizierung aufweist. Oder man könnte die Anfrage von hhh verwenden und die implizit indizierten Werte des j-Vektors erstellen 10:20, wobei der rownamesVektor verwendet wird, der standardmäßig bei "1" beginnt, der jedoch geändert werden kann, um ein Zeichenvektor zu werden, der bei "0" beginnt.

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

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

Leider wird der Unvorsichtige feststellen, dass dfrm [0,] kein glücklicher Aufruf ist und einen Vektor der Länge 0 zurückgibt.

IRTFM
quelle
+1 für eine elegante Lösung. (Nein, das sind keine Python-Matrizen, aber wie Sie bereits erraten haben, Liste der Tupel .)
Chl
4

Um Listenverständnisse im Python-Stil mit Aufzählungen wie Aufzählungslisten zu verwenden, besteht eine Möglichkeit darin, das Listenverständnispaket LC(entwickelt 2018) und das itertools-Paket (entwickelt 2015) zu installieren .

Listenverständnisse in R.

Das LCPaket finden Sie hier .

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

Beispiel

> 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"

wo die Programmiersyntax noch nicht so sauber und poliert ist wie in Python, aber funktional funktioniert und ihre Hilfe beschreibt:

"Die Syntax lautet wie folgt: lc (Ausdruck, Listen, Prädikate) wobei Ausdruck ein Ausdruck ist, der für alle Elemente in den Listen ausgewertet werden soll, wobei Listen eine oder mehrere benannte Listen sind, wobei diese durch einen Namen und einen Ausdrucksnamen angegeben werden = list_expr, und wobei Prädikate Ausdrücke sind, die zu einem booleschen Wert ausgewertet werden sollten. Um beispielsweise eine Liste aller geraden Zahlen im Quadrat aus einer Liste x zu erhalten, können wir lc (x ** 2, x = x, x%) schreiben % 2 == 0). Das Ergebnis eines Aufrufs von lc ist eine Liste, die aus den Ausdrücken in Ausdruck für alle Elemente in den Eingabelisten erstellt wurde, bei denen die Prädikate als wahr ausgewertet werden. "

Beachten Sie, dass Sie die Prädikate beispielsweise im obigen Beispiel leer lassen können.

Itertools und Aufzählungen im Python-Stil

Sie können R itertools verwenden, die Pythons itertools sehr ähnlich ist, weiter in Cran hier

library(itertools)

wo beschrieben

"Verschiedene Tools zum Erstellen von Iteratoren, viele nach Funktionen im Python itertools-Modul und andere nach Funktionen im 'snow'-Paket."

Beispiel. Aufzählung

> 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"

Beispiel. Aufzählung mit 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"
hhh
quelle
3

zipund enumeratesind in R nicht besonders schwer zu implementieren:

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

Aufzählen ist einfach zu definieren in Bezug auf zip:

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

Da es sich um ordnungsgemäße Funktionen handelt, können wir sie verwenden ..., um sie ziemlich flexibel und knapp zu gestalten und das Verhalten von Mapply zu nutzen, z. B. das Recycling von Eingaben und die korrekte Benennung von Ausgaben.

Neal Fultz
quelle
1
Diese wurden dem stackoverflowPaket fwiw hinzugefügt.
Neal Fultz
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
    })
}
Blatt
quelle
Bitte geben Sie eine Beschreibung der Funktionsweise dieses Codeblocks an.
Keivan Esbati
Diese Funktion macht genau das Gleiche mit "mapply (list, x, y, SIMPLIFY = F)", auf das @chl zeigte
ibilgen
0

Dies kann mit zwei Einfügeanweisungen erreicht werden:

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

Die Ausgabe wird wie folgt aussehen:

'(1,10), (2,11), (3,12), (4,13), (5,14), (6,15), (7,16), (8,17), (9,18), (10,19), (11,20)'
Kravi
quelle
0

Für Python sollte das Äquivalent 'aufzählen' in R. Das Speichern der Vektoren in der Liste und das Durchlaufen mit einem Index sollte funktionieren.

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))
}

Ausgabe:

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

R 'list' ist eine nette Bank, um die Vektoren einzuzahlen und mit einem Index zu behalten.

Surya
quelle