Toujours en train d'entrer dans la logique R ... quelle est la "meilleure" façon de décompresser (sur LHS) les résultats d'une fonction renvoyant plusieurs valeurs?
Je ne peux pas faire ça apparemment:
R> functionReturningTwoValues <- function() { return(c(1, 2)) }
R> functionReturningTwoValues()
[1] 1 2
R> a, b <- functionReturningTwoValues()
Error: unexpected ',' in "a,"
R> c(a, b) <- functionReturningTwoValues()
Error in c(a, b) <- functionReturningTwoValues() : object 'a' not found
dois-je vraiment faire ce qui suit?
R> r <- functionReturningTwoValues()
R> a <- r[1]; b <- r[2]
ou le programmeur R écrirait-il quelque chose de plus comme ceci:
R> functionReturningTwoValues <- function() {return(list(first=1, second=2))}
R> r <- functionReturningTwoValues()
R> r$first
[1] 1
R> r$second
[1] 2
--- modifié pour répondre aux questions de Shane ---
Je n'ai pas vraiment besoin de donner de noms aux parties de valeur de résultat. J'applique une fonction d'agrégation au premier composant et une autre au deuxième composant ( min
et max
si c'était la même fonction pour les deux composants, je n'aurais pas besoin de les diviser).
attr
sur votre valeur de retour.Réponses:
(1) list [...] <- Je l'avais posté il y a plus d'une décennie sur r-help . Depuis lors, il a été ajouté au package gsubfn. Il ne nécessite pas d'opérateur spécial mais nécessite que le côté gauche soit écrit en utilisant
list[...]
comme ceci:Si vous n'avez besoin que du premier ou du deuxième composant, tous fonctionnent également:
(Bien sûr, si vous n'aviez besoin que d'une seule valeur, alors
functionReturningTwoValues()[[1]]
oufunctionReturningTwoValues()[[2]]
serait suffisant.)Voir le fil r-help cité pour plus d'exemples.
(2) avec Si l'intention est simplement de combiner les valeurs multiples par la suite et que les valeurs de retour sont nommées, une alternative simple consiste à utiliser
with
:(3) attacher Une autre alternative est attacher:
AJOUTÉ:
with
etattach
la source
list
et[<-.result
comme indiqué ici?J'ai en quelque sorte trébuché sur ce hack intelligent sur Internet ... Je ne sais pas si c'est méchant ou beau, mais cela vous permet de créer un opérateur "magique" qui vous permet de décompresser plusieurs valeurs de retour dans leur propre variable. La
:=
fonction est définie ici et incluse ci-dessous pour la postérité:Avec cela en main, vous pouvez faire ce que vous recherchez:
Je ne sais pas ce que je ressens à ce sujet. Peut-être le trouverez-vous utile dans votre espace de travail interactif. L'utiliser pour construire des bibliothèques (réutilisables) (pour la consommation de masse) n'est peut-être pas la meilleure idée, mais je suppose que cela dépend de vous.
... vous savez ce qu'ils disent sur la responsabilité et le pouvoir ...
la source
:=
beaucoup l' opérateur de manière beaucoup plus pratique :-)Habituellement, j'emballe la sortie dans une liste, qui est très flexible (vous pouvez avoir n'importe quelle combinaison de nombres, chaînes, vecteurs, matrices, tableaux, listes, objets dans la sortie)
donc comme:
la source
Je pense que cela fonctionne.
la source
J'ai mis en place un package R zeallot pour résoudre ce problème. zeallot comprend une affectation multiple ou opérateur d'affectation décompactage,
%<-%
. Le LHS de l'opérateur est un nombre quelconque de variables à affecter, construit à l'aide d'appels àc()
. Le RHS de l'opérateur est un vecteur, une liste, un bloc de données, un objet de date ou tout autre objet personnalisé avec unedestructure
méthode implémentée (voir?zeallot::destructure
).Voici quelques exemples basés sur le message d'origine,
Consultez la vignette du package pour plus d'informations et d'exemples.
la source
Il n'y a pas de bonne réponse à cette question. Je dépend vraiment de ce que vous faites avec les données. Dans l'exemple simple ci-dessus, je suggère fortement:
Est-il important que les valeurs 1 et 2 ci-dessus aient des noms? En d'autres termes, pourquoi est-il important dans cet exemple que 1 et 2 soient nommés a et b, plutôt que simplement r [1] et r [2]? Une chose importante à comprendre dans ce contexte est que a et b sont également des vecteurs de longueur 1. Donc, vous ne changez vraiment rien dans le processus de cette affectation, à part avoir 2 nouveaux vecteurs qui n'ont pas besoin d'indices pour être référencé:
Vous pouvez également attribuer les noms au vecteur d'origine si vous préférez référencer la lettre que l'index:
[Modifier] Étant donné que vous appliquerez les valeurs min et max à chaque vecteur séparément, je suggérerais d'utiliser soit une matrice (si a et b auront la même longueur et le même type de données) ou un cadre de données (si a et b seront la même longueur mais peuvent être de types de données différents) ou bien utilisez une liste comme dans votre dernier exemple (si elles peuvent être de longueurs et de types de données différents).
la source
r[1]
peut aider à rendre les choses plus claires (d'accord, pas si des noms commea
viennent à leur place).Les listes semblent parfaites à cet effet. Par exemple, dans la fonction que vous auriez
programme principal
la source
Oui à vos deuxième et troisième questions - c'est ce que vous devez faire car vous ne pouvez pas avoir plusieurs «valeurs» à gauche d'une affectation.
la source
Que diriez-vous d'utiliser assign?
Vous pouvez transmettre les noms de la variable que vous souhaitez transmettre par référence.
Si vous devez accéder aux valeurs existantes, l'inverse de
assign
estget
.la source
r <- function() { return(list(first=1, second=2)) }
et référencez les résultats en utilisantr$first
etr$second
.Si vous souhaitez renvoyer la sortie de votre fonction dans l'environnement global, vous pouvez utiliser
list2env
, comme dans cet exemple:Cette fonction créera trois objets dans votre environnement global:
la source
[A] Si chacun de foo et bar est un nombre unique, alors il n'y a rien de mal avec c (foo, bar); et vous pouvez également nommer les composants: c (Foo = foo, Bar = bar). Ainsi, vous pouvez accéder aux composants du résultat «res» en tant que res [1], res [2]; ou, dans le cas indiqué, comme res ["Foo"], res ["BAR"].
[B] Si foo et bar sont des vecteurs du même type et de la même longueur, alors là encore, il n'y a rien de mal à retourner cbind (foo, bar) ou rbind (foo, bar); également nommable. Dans le cas 'cbind', vous accéderez à foo et bar en tant que res [, 1], res [, 2] ou res [, "Foo"], res [, "Bar"]. Vous pouvez également préférer renvoyer une trame de données plutôt qu'une matrice:
et accédez-y en tant que res $ Foo, res $ Bar. Cela fonctionnerait aussi bien si foo et bar étaient de la même longueur mais pas du même type (par exemple foo est un vecteur de nombres, bar un vecteur de chaînes de caractères).
[C] Si foo et bar sont suffisamment différents pour ne pas se combiner comme ci-dessus, alors vous devriez certainement retourner une liste.
Par exemple, votre fonction peut s'adapter à un modèle linéaire et également calculer des valeurs prédites, vous pouvez donc avoir
et ensuite vous
return list(Foo=foo,Bar=bar)
accéderiez au résumé en tant que res $ Foo, les valeurs prédites en tant que res $ Barsource: http://r.789695.n4.nabble.com/How-to-return-multiple-values-in-a-function-td858528.html
la source
Pour obtenir plusieurs sorties d'une fonction et les conserver dans le format souhaité, vous pouvez enregistrer les sorties sur votre disque dur (dans le répertoire de travail) depuis la fonction, puis les charger depuis l'extérieur de la fonction:
la source
Avec R 3.6.1, je peux faire ce qui suit
la source