Greifen Sie auf Lapply-Indexnamen in FUN zu

162

Gibt es eine Möglichkeit, den Listenindexnamen in meiner Funktion lapply () abzurufen?

n = names(mylist)
lapply(mylist, function(list.elem) { cat("What is the name of this list element?\n" })

Ich habe zuvor gefragt, ob es möglich ist, die Indexnamen in der von lapply () zurückgegebenen Liste beizubehalten , aber ich weiß immer noch nicht, ob es eine einfache Möglichkeit gibt, jeden Elementnamen innerhalb der benutzerdefinierten Funktion abzurufen. Ich möchte vermeiden, lapply für die Namen selbst aufzurufen, ich möchte den Namen lieber in den Funktionsparametern erhalten.

Robert Kubrick
quelle
Es gibt noch einen Trick mit Attributen. Siehe hier: stackoverflow.com/questions/4164960/… , was dem von DWin ähnlich ist, aber anders. :)
Roman Luštrik

Antworten:

160

Leider erhalten Sie lapplynur die Elemente des Vektors, den Sie übergeben. Die übliche Umgehung besteht darin, die Namen oder Indizes des Vektors anstelle des Vektors selbst zu übergeben.

Beachten Sie jedoch, dass Sie der Funktion immer zusätzliche Argumente übergeben können, sodass Folgendes funktioniert:

x <- list(a=11,b=12,c=13) # Changed to list to address concerns in commments
lapply(seq_along(x), function(y, n, i) { paste(n[[i]], y[[i]]) }, y=x, n=names(x))

Hier verwende ich lapplyüber die Indizes von x, übergebe aber auch xund die Namen von x. Wie Sie sehen können, kann die Reihenfolge der Funktionsargumente beliebig sein - lapplywird im "Element" (hier der Index) an das erste Argument übergeben, das nicht unter den zusätzlichen Argumenten angegeben ist. In diesem Fall gebe ich yund an n, also gibt es nuri noch ...

Welches erzeugt das folgende:

[[1]]
[1] "a 11"

[[2]]
[1] "b 12"

[[3]]
[1] "c 13"

UPDATE Einfacheres Beispiel, gleiches Ergebnis:

lapply(seq_along(x), function(i) paste(names(x)[[i]], x[[i]]))

Hier verwendet die Funktion die Variable "global" xund extrahiert die Namen in jedem Aufruf.

Tommy
quelle
Wie wird der Parameter 'i' in der benutzerdefinierten Funktion initialisiert?
Robert Kubrick
Verstanden, also gilt lapply () wirklich für die von seq_along zurückgegebenen Elemente. Ich war verwirrt, weil die benutzerdefinierten Funktionsparameter neu angeordnet wurden. Normalerweise ist das iterierte Listenelement der erste Parameter.
Robert Kubrick
Aktualisiert Antwort und geändert erste Funktion zu verwenden , ystatt , xso dass es (hoffentlich) deutlicher , dass die Funktionsargumente es ist etwas aufrufen können. Auch die Vektorwerte wurden in geändert 11,12,13.
Tommy
@RobertKubrick - Ja, ich habe wahrscheinlich versucht, zu viele Dinge gleichzeitig zu zeigen ... Sie können die Argumente beliebig benennen und in beliebiger Reihenfolge haben.
Tommy
@ DWin - Ich denke es ist richtig (und gilt auch für Listen) ;-) ... Aber bitte beweise mir das Gegenteil!
Tommy
48

Dies verwendet im Grunde die gleiche Problemumgehung wie Tommy, aber mit Map()müssen Sie nicht auf globale Variablen zugreifen, in denen die Namen von Listenkomponenten gespeichert sind.

> x <- list(a=11, b=12, c=13)
> Map(function(x, i) paste(i, x), x, names(x))
$a
[1] "a 11"

$b
[1] "b 12"

$c
[1] "c 13

Oder wenn Sie es vorziehen mapply()

> mapply(function(x, i) paste(i, x), x, names(x))
     a      b      c 
"a 11" "b 12" "c 13"
Karakal
quelle
Dies ist definitiv die beste Lösung.
EmilBeBri
Beachten Sie bei der Verwendung mapply()die SIMPLIFYOption, die standardmäßig true ist. In meinem Fall machte das Ganze zu einer großen Matrix, als ich nur eine einfache Liste anwenden wollte. Wenn Sie es auf F(innerhalb von mapply()) einstellen, wird es wie beabsichtigt ausgeführt.
JJ für Transparenz und Monica
39

UPDATE für R Version 3.2

Haftungsausschluss: Dies ist ein hackiger Trick und funktioniert möglicherweise in den nächsten Versionen nicht mehr.

Sie können den Index folgendermaßen abrufen:

> lapply(list(a=10,b=20), function(x){parent.frame()$i[]})
$a
[1] 1

$b
[1] 2

Hinweis: []Dies ist erforderlich, damit dies funktioniert, da R zu der Annahme verleitet wird, dass das Symbol i(das sich im Bewertungsrahmen von befindet lapply) möglicherweise mehr Referenzen enthält, wodurch die verzögerte Vervielfältigung aktiviert wird. Ohne sie wird R keine getrennten Kopien von i:

> lapply(list(a=10,b=20), function(x){parent.frame()$i})
$a
[1] 2

$b
[1] 2

Andere exotische Tricks können verwendet werden, wie function(x){parent.frame()$i+0}oder function(x){--parent.frame()$i}.

Auswirkungen auf die Leistung

Wird die erzwungene Vervielfältigung zu Leistungseinbußen führen? Ja! Hier sind die Benchmarks:

> x <- as.list(seq_len(1e6))

> system.time( y <- lapply(x, function(x){parent.frame()$i[]}) )
user system elapsed
2.38 0.00 2.37
> system.time( y <- lapply(x, function(x){parent.frame()$i[]}) )
user system elapsed
2.45 0.00 2.45
> system.time( y <- lapply(x, function(x){parent.frame()$i[]}) )
user system elapsed
2.41 0.00 2.41
> y[[2]]
[1] 2

> system.time( y <- lapply(x, function(x){parent.frame()$i}) )
user system elapsed
1.92 0.00 1.93
> system.time( y <- lapply(x, function(x){parent.frame()$i}) )
user system elapsed
2.07 0.00 2.09
> system.time( y <- lapply(x, function(x){parent.frame()$i}) )
user system elapsed
1.89 0.00 1.89
> y[[2]]
[1] 1000000

Fazit

Diese Antwort zeigt nur, dass Sie dies NICHT verwenden sollten ... Nicht nur Ihr Code ist besser lesbar, wenn Sie eine andere Lösung wie die oben beschriebene von Tommy finden und mit zukünftigen Versionen kompatibler sind. Sie riskieren auch, die Optimierungen zu verlieren, an denen das Kernteam hart gearbeitet hat sich entwickeln!


Tricks alter Versionen, die nicht mehr funktionieren:

> lapply(list(a=10,b=10,c=10), function(x)substitute(x)[[3]])

Ergebnis:

$a
[1] 1

$b
[1] 2

$c
[1] 3

Erläuterung: lapplyschafft Anrufe von der Form FUN(X[[1L]], ...), FUN(X[[2L]], ...)etc. Also das Argument es passiert ist , X[[i]]wo ider aktuelle Index in der Schleife ist. Wenn wir dies erhalten, bevor es ausgewertet wird (dh wenn wir es verwenden substitute), erhalten wir den nicht bewerteten Ausdruck X[[i]]. Dies ist ein [[Funktionsaufruf mit Argumenten X(ein Symbol) und i(eine Ganzzahl). Sosubstitute(x)[[3]] kehrt gerade diese ganze Zahl ist .

Mit dem Index können Sie trivial auf die Namen zugreifen, wenn Sie ihn zuerst wie folgt speichern:

L <- list(a=10,b=10,c=10)
n <- names(L)
lapply(L, function(x)n[substitute(x)[[3]]])

Ergebnis:

$a
[1] "a"

$b
[1] "b"

$c
[1] "c"

Oder mit diesem zweiten Trick ::-)

lapply(list(a=10,b=10,c=10), function(x)names(eval(sys.call(1)[[2]]))[substitute(x)[[3]]])

(Ergebnis ist das gleiche).

Erläuterung 2: sys.call(1)Gibt zurück lapply(...), sodass dies sys.call(1)[[2]]der Ausdruck ist, für den das Listenargument verwendet wird lapply. Wenn Sie dies an übergeben, evalwird ein legitimes Objekt erstellt, dasnames kann. Tricky, aber es funktioniert.

Bonus: ein zweiter Weg, um die Namen zu bekommen:

lapply(list(a=10,b=10,c=10), function(x)eval.parent(quote(names(X)))[substitute(x)[[3]]])

Beachten Sie, dass dies Xein gültiges Objekt im übergeordneten Frame von FUNist und auf das Listenargument von verweist lapply, damit wir mit darauf zugreifen können eval.parent.

Ferdinand.kraft
quelle
2
Der Code lapply(list(a=10,b=10,c=10), function(x)substitute(x)[[3]])gibt alle auf 3 zurück. Würden Sie erklären, wie diese 3 ausgewählt wurde? und Grund für die Diskrepanz? Entspricht es in diesem Fall der Länge der Liste? 3. Entschuldigung, wenn dies eine grundlegende Frage ist, Sie aber gerne wissen möchten, wie Sie dies in einem allgemeinen Fall anwenden können.
Anusha
@ Anusha, in der Tat, dieses Formular funktioniert nicht mehr ... Aber die lapply(list(a=10,b=10,c=10), function(x)eval.parent(quote(names(X)))[substitute(x)[[3]]])Werke ... Ich werde überprüfen, was los ist.
Ferdinand.kraft
@ Ferdinand.kraft, lapply(list(a=10,b=10,c=10), function(x)eval.parent(quote(names(X)))[substitute(x)[[3]]])funktioniert nicht mehr und gibt einen Fehler aus, Error in eval.parent(quote(names(X)))[substitute(x)[[3]]] : invalid subscript type 'symbol'gibt es eine einfache Möglichkeit, dies zu beheben?
Prognostiker
Vielen Dank @ Ferdinand.kraft
Prognostiker
18

Ich hatte oft das gleiche Problem ... Ich habe angefangen, einen anderen Weg zu verwenden ... Anstatt zu benutzen lapply, habe ich angefangen zu benutzenmapply

n = names(mylist)
mapply(function(list.elem, names) { }, list.elem = mylist, names = n)
Ana Vitória Baraldi
quelle
2
Ich bevorzuge dies auch, aber diese Antwort ist ein Duplikat einer vorherigen .
Merv
13

Sie könnten versuchen, imap()aus purrrPaket zu verwenden.

Aus der Dokumentation:

imap (x, ...) ist eine Abkürzung für map2 (x, names (x), ...), wenn x Namen hat, oder map2 (x, seq_along (x), ...), wenn dies nicht der Fall ist.

Sie können es also folgendermaßen verwenden:

library(purrr)
myList <- list(a=11,b=12,c=13) 
imap(myList, function(x, y) paste(x, y))

Welches gibt Ihnen das folgende Ergebnis:

$a
[1] "11 a"

$b
[1] "12 b"

$c
[1] "13 c"
Kevin Zarca
quelle
10

Schleifen Sie einfach die Namen ein.

sapply(names(mylist), function(n) { 
    doSomething(mylist[[n]])
    cat(n, '\n')
}
incitatus451
quelle
Dies ist sicherlich die einfachste Lösung.
fliegt
1
@flies: Ja, außer es ist eine schlechte Praxis, Variablen mylistinnerhalb der Funktion fest zu codieren . Besser noch zu tunfunction(mylist, nm) ...
smci
5

Tommys Antwort gilt für benannte Vektoren, aber ich hatte die Idee, dass Sie an Listen interessiert waren. Und es scheint, als würde er ein End-Around machen, weil er "x" aus der aufrufenden Umgebung referenzierte. Diese Funktion verwendet nur die Parameter, die an die Funktion übergeben wurden, und macht daher keine Annahmen über den Namen der übergebenen Objekte:

x <- list(a=11,b=12,c=13)
lapply(x, function(z) { attributes(deparse(substitute(z)))$names  } )
#--------
$a
NULL

$b
NULL

$c
NULL
#--------
 names( lapply(x, function(z) { attributes(deparse(substitute(z)))$names  } ))
#[1] "a" "b" "c"
 what_is_my_name <- function(ZZZ) return(deparse(substitute(ZZZ)))
 what_is_my_name(X)
#[1] "X"
what_is_my_name(ZZZ=this)
#[1] "this"
 exists("this")
#[1] FALSE
IRTFM
quelle
Ihre Funktion kehrt nur zurück NULL?! Also lapply(x, function(x) NULL)gibt die gleiche Antwort ...
Tommy
Beachten Sie, dass danach lapplyimmer die Namen von xzum Ergebnis hinzugefügt werden .
Tommy
Ja. Stimmen Sie zu, dass dies die Lehre aus dieser Übung ist.
IRTFM
4

Meine Antwort geht in die gleiche Richtung wie die von Tommy und Caracals, aber ich muss die Liste nicht als zusätzliches Objekt speichern.

lapply(seq(3), function(i, y=list(a=14,b=15,c=16)) { paste(names(y)[[i]], y[[i]]) })

Ergebnis:

[[1]]
[1] "a 14"

[[2]]
[1] "b 15"

[[3]]
[1] "c 16"

Dies gibt die Liste als benanntes Argument an FUN (statt an lapply). lapply muss nur über die Elemente der Liste iterieren (achten Sie darauf, dieses erste Argument in lapply zu ändern, wenn Sie die Länge der Liste ändern).

Hinweis: Wenn Sie die Liste als zusätzliches Argument direkt an lapply übergeben, funktioniert dies auch:

lapply(seq(3), function(i, y) { paste(names(y)[[i]], y[[i]]) }, y=list(a=14,b=15,c=16))
julianisch
quelle
3

Sowohl @caracals als auch @Tommy sind gute Lösungen und dies ist ein Beispiel, einschließlich list´s und data.frame´s.
rist ein listvon list´s und data.frame´s (dput(r[[1]] am Ende).

names(r)
[1] "todos"  "random"
r[[1]][1]
$F0
$F0$rst1
   algo  rst  prec  rorac prPo pos
1  Mean 56.4 0.450 25.872 91.2 239
6  gbm1 41.8 0.438 22.595 77.4 239
4  GAM2 37.2 0.512 43.256 50.0 172
7  gbm2 36.8 0.422 18.039 85.4 239
11 ran2 35.0 0.442 23.810 61.5 239
2  nai1 29.8 0.544 52.281 33.1 172
5  GAM3 28.8 0.403 12.743 94.6 239
3  GAM1 21.8 0.405 13.374 68.2 239
10 ran1 19.4 0.406 13.566 59.8 239
9  svm2 14.0 0.385  7.692 76.2 239
8  svm1  0.8 0.359  0.471 71.1 239

$F0$rst5
   algo  rst  prec  rorac prPo pos
1  Mean 52.4 0.441 23.604 92.9 239
7  gbm2 46.4 0.440 23.200 83.7 239
6  gbm1 31.2 0.416 16.421 79.5 239
5  GAM3 28.8 0.403 12.743 94.6 239
4  GAM2 28.2 0.481 34.815 47.1 172
11 ran2 26.6 0.422 18.095 61.5 239
2  nai1 23.6 0.519 45.385 30.2 172
3  GAM1 20.6 0.398 11.381 75.7 239
9  svm2 14.4 0.386  8.182 73.6 239
10 ran1 14.0 0.390  9.091 64.4 239
8  svm1  6.2 0.370  3.584 72.4 239

Das Ziel besteht darin, unlistalle Listen zu erstellen und die Reihenfolge der listNamen als Spalten zu setzen, um den Fall zu identifizieren.

r=unlist(unlist(r,F),F)
names(r)
[1] "todos.F0.rst1"  "todos.F0.rst5"  "todos.T0.rst1"  "todos.T0.rst5"  "random.F0.rst1" "random.F0.rst5"
[7] "random.T0.rst1" "random.T0.rst5"

Liste auflisten, aber nicht die data.frame.

ra=Reduce(rbind,Map(function(x,y) cbind(case=x,y),names(r),r))

MapSetzt die Namensfolge als Spalte. Reducemach mit bei allen data.frame.

head(ra)
            case algo  rst  prec  rorac prPo pos
1  todos.F0.rst1 Mean 56.4 0.450 25.872 91.2 239
6  todos.F0.rst1 gbm1 41.8 0.438 22.595 77.4 239
4  todos.F0.rst1 GAM2 37.2 0.512 43.256 50.0 172
7  todos.F0.rst1 gbm2 36.8 0.422 18.039 85.4 239
11 todos.F0.rst1 ran2 35.0 0.442 23.810 61.5 239
2  todos.F0.rst1 nai1 29.8 0.544 52.281 33.1 172

PS r[[1]]:

    structure(list(F0 = structure(list(rst1 = structure(list(algo = c("Mean", 
    "gbm1", "GAM2", "gbm2", "ran2", "nai1", "GAM3", "GAM1", "ran1", 
    "svm2", "svm1"), rst = c(56.4, 41.8, 37.2, 36.8, 35, 29.8, 28.8, 
    21.8, 19.4, 14, 0.8), prec = c(0.45, 0.438, 0.512, 0.422, 0.442, 
    0.544, 0.403, 0.405, 0.406, 0.385, 0.359), rorac = c(25.872, 
    22.595, 43.256, 18.039, 23.81, 52.281, 12.743, 13.374, 13.566, 
    7.692, 0.471), prPo = c(91.2, 77.4, 50, 85.4, 61.5, 33.1, 94.6, 
    68.2, 59.8, 76.2, 71.1), pos = c(239L, 239L, 172L, 239L, 239L, 
    172L, 239L, 239L, 239L, 239L, 239L)), .Names = c("algo", "rst", 
    "prec", "rorac", "prPo", "pos"), row.names = c(1L, 6L, 4L, 7L, 
    11L, 2L, 5L, 3L, 10L, 9L, 8L), class = "data.frame"), rst5 = structure(list(
        algo = c("Mean", "gbm2", "gbm1", "GAM3", "GAM2", "ran2", 
        "nai1", "GAM1", "svm2", "ran1", "svm1"), rst = c(52.4, 46.4, 
        31.2, 28.8, 28.2, 26.6, 23.6, 20.6, 14.4, 14, 6.2), prec = c(0.441, 
        0.44, 0.416, 0.403, 0.481, 0.422, 0.519, 0.398, 0.386, 0.39, 
        0.37), rorac = c(23.604, 23.2, 16.421, 12.743, 34.815, 18.095, 
        45.385, 11.381, 8.182, 9.091, 3.584), prPo = c(92.9, 83.7, 
        79.5, 94.6, 47.1, 61.5, 30.2, 75.7, 73.6, 64.4, 72.4), pos = c(239L, 
        239L, 239L, 239L, 172L, 239L, 172L, 239L, 239L, 239L, 239L
        )), .Names = c("algo", "rst", "prec", "rorac", "prPo", "pos"
    ), row.names = c(1L, 7L, 6L, 5L, 4L, 11L, 2L, 3L, 9L, 10L, 8L
    ), class = "data.frame")), .Names = c("rst1", "rst5")), T0 = structure(list(
        rst1 = structure(list(algo = c("Mean", "ran1", "GAM1", "GAM2", 
        "gbm1", "svm1", "nai1", "gbm2", "svm2", "ran2"), rst = c(22.6, 
        19.4, 13.6, 10.2, 9.6, 8, 5.6, 3.4, -0.4, -0.6), prec = c(0.478, 
        0.452, 0.5, 0.421, 0.423, 0.833, 0.429, 0.373, 0.355, 0.356
        ), rorac = c(33.731, 26.575, 40, 17.895, 18.462, 133.333, 
        20, 4.533, -0.526, -0.368), prPo = c(34.4, 52.1, 24.3, 40.7, 
        37.1, 3.1, 14.4, 53.6, 54.3, 116.4), pos = c(195L, 140L, 
        140L, 140L, 140L, 195L, 195L, 140L, 140L, 140L)), .Names = c("algo", 
        "rst", "prec", "rorac", "prPo", "pos"), row.names = c(1L, 
        9L, 3L, 4L, 5L, 7L, 2L, 6L, 8L, 10L), class = "data.frame"), 
        rst5 = structure(list(algo = c("gbm1", "ran1", "Mean", "GAM1", 
        "GAM2", "svm1", "nai1", "svm2", "gbm2", "ran2"), rst = c(17.6, 
        16.4, 15, 12.8, 9, 6.2, 5.8, -2.6, -3, -9.2), prec = c(0.466, 
        0.434, 0.435, 0.5, 0.41, 0.8, 0.44, 0.346, 0.345, 0.337), 
            rorac = c(30.345, 21.579, 21.739, 40, 14.754, 124, 23.2, 
            -3.21, -3.448, -5.542), prPo = c(41.4, 54.3, 35.4, 22.9, 
            43.6, 2.6, 12.8, 57.9, 62.1, 118.6), pos = c(140L, 140L, 
            195L, 140L, 140L, 195L, 195L, 140L, 140L, 140L)), .Names = c("algo", 
        "rst", "prec", "rorac", "prPo", "pos"), row.names = c(5L, 
        9L, 1L, 3L, 4L, 7L, 2L, 8L, 6L, 10L), class = "data.frame")), .Names = c("rst1", 
    "rst5"))), .Names = c("F0", "T0"))
xm1
quelle
0

Angenommen, wir möchten die Länge jedes Elements berechnen.

mylist <- list(a=1:4,b=2:9,c=10:20)
mylist

$a
[1] 1 2 3 4

$b
[1] 2 3 4 5 6 7 8 9

$c
 [1] 10 11 12 13 14 15 16 17 18 19 20

Wenn das Ziel darin besteht, nur die resultierenden Elemente zu lapply(mylist,length)kennzeichnen, funktioniert dies oder darunter.

sapply(mylist,length,USE.NAMES=T)

 a  b  c 
 4  8 11 

Wenn das Ziel darin besteht, die Beschriftung innerhalb der Funktion zu verwenden, mapply()ist es nützlich, zwei Objekte zu durchlaufen. die Listenelemente und Listennamen.

fun <- function(x,y) paste0(length(x),"_",y)
mapply(fun,mylist,names(mylist))

     a      b      c 
 "4_a"  "8_b" "11_c" 
rmf
quelle
0

@ ferdinand-kraft hat uns einen tollen Trick gegeben und uns dann gesagt, wir sollten ihn nicht verwenden, weil er nicht dokumentiert ist und wegen des Leistungsaufwands.

Ich kann mit dem ersten Punkt nicht viel streiten, aber ich möchte darauf hinweisen, dass der Overhead selten ein Problem sein sollte.

Definieren wir aktive Funktionen, damit wir den komplexen Ausdruck nicht aufrufen müssen, parent.frame()$i[]sondern nur .i(). Wir erstellen auch, .n()um auf den Namen zuzugreifen, der sowohl für Basis- als auch für Purrr- Funktionen (und wahrscheinlich auch für die meisten anderen) funktionieren sollte.

.i <- function() parent.frame(2)$i[]
# looks for X OR .x to handle base and purrr functionals
.n <- function() {
  env <- parent.frame(2)
  names(c(env$X,env$.x))[env$i[]]
}

sapply(cars, function(x) paste(.n(), .i()))
#>     speed      dist 
#> "speed 1"  "dist 2"

Lassen Sie uns nun eine einfache Funktion vergleichen, die die Elemente eines Vektors mit verschiedenen Ansätzen in ihren Index einfügt (diese Operationen können natürlich mit vektorisiert werden paste(vec, seq_along(vec)) aber das ist hier nicht der Punkt).

Wir definieren eine Benchmarking-Funktion und eine Plotfunktion und zeichnen die folgenden Ergebnisse auf:

library(purrr)
library(ggplot2)
benchmark_fun <- function(n){
  vec <- sample(letters,n, replace = TRUE)
  mb <- microbenchmark::microbenchmark(unit="ms",
                                      lapply(vec, function(x)  paste(x, .i())),
                                      map(vec, function(x) paste(x, .i())),
                                      lapply(seq_along(vec), function(x)  paste(vec[[x]], x)),
                                      mapply(function(x,y) paste(x, y), vec, seq_along(vec), SIMPLIFY = FALSE),
                                      imap(vec, function(x,y)  paste(x, y)))
  cbind(summary(mb)[c("expr","mean")], n = n)
}

benchmark_plot <- function(data, title){
  ggplot(data, aes(n, mean, col = expr)) + 
    geom_line() +
    ylab("mean time in ms") +
    ggtitle(title) +
    theme(legend.position = "bottom",legend.direction = "vertical")
}

plot_data <- map_dfr(2^(0:15), benchmark_fun)
benchmark_plot(plot_data[plot_data$n <= 100,], "simplest call for low n")

benchmark_plot(plot_data,"simplest call for higher n")

Erstellt am 15.11.2019 durch das reprex-Paket (v0.3.0)

Der Abfall am Anfang des ersten Diagramms ist ein Zufall, bitte ignorieren Sie ihn.

Wir sehen, dass die gewählte Antwort tatsächlich schneller ist, und für eine anständige Anzahl von Iterationen sind unsere .i()Lösungen tatsächlich langsamer. Der Overhead im Vergleich zur gewählten Antwort beträgt etwa das Dreifache des Overheads für die Verwendung von purrr::imap()und beträgt ungefähr 25 ms für 30.000 Iterationen. Ich verliere also ungefähr 1 ms pro 1000 Iterationen, 1 Sekunde pro Million. Das ist meiner Meinung nach ein kleiner Kostenfaktor.

Moody_Mudskipper
quelle
-1

Schreiben Sie einfach Ihre eigene benutzerdefinierte lapplyFunktion

lapply2 <- function(X, FUN){
  if( length(formals(FUN)) == 1 ){
    # No index passed - use normal lapply
    R = lapply(X, FUN)
  }else{
    # Index passed
    R = lapply(seq_along(X), FUN=function(i){
      FUN(X[[i]], i)
    })
  }

  # Set names
  names(R) = names(X)
  return(R)
}

Dann verwenden Sie wie folgt:

lapply2(letters, function(x, i) paste(x, i))
by0
quelle
Dies ist überhaupt nicht robust, mit Vorsicht verwenden
Moody_Mudskipper