Étant donné un tableau, un seul élément ou nil, obtenez un tableau - les deux derniers étant respectivement un tableau d'élément unique et un tableau vide.
J'ai pensé à tort que Ruby fonctionnerait de cette façon:
[1,2,3].to_a #= [1,2,3] # Already an array, so no change
1.to_a #= [1] # Creates an array and adds element
nil.to_a #= [] # Creates empty array
Mais ce que vous obtenez vraiment, c'est:
[1,2,3].to_a #= [1,2,3] # Hooray
1.to_a #= NoMethodError # Do not want
nil.to_a #= [] # Hooray
Donc, pour résoudre cela, je dois soit utiliser une autre méthode, soit je pourrais utiliser un méta-programme en modifiant la méthode to_a de toutes les classes que j'ai l'intention d'utiliser - ce qui n'est pas une option pour moi.
Donc une méthode c'est:
result = nums.class == "Array".constantize ? nums : (nums.class == "NilClass".constantize ? [] : ([]<<nums))
Le problème est que c'est un peu le bordel. Y a-t-il une manière élégante de faire cela? (Je serais étonné si c'est la façon rubis de résoudre ce problème)
Quelles applications cela a-t-il? Pourquoi même convertir en un tableau?
Dans ActiveRecord de Rails, appeler par exemple user.posts
renverra un tableau de messages, un seul article ou nil. Lors de l'écriture de méthodes qui fonctionnent sur les résultats de ceci, il est plus facile de supposer que la méthode prendra un tableau, qui peut avoir zéro, un ou plusieurs éléments. Exemple de méthode:
current_user.posts.inject(true) {|result, element| result and (element.some_boolean_condition)}
user.posts
ne devrait jamais renvoyer un seul message. Au moins, je ne l'ai jamais vu.==
au lieu de=
, non?[1,2,3].to_a
ne revient pas[[1,2,3]]
! Il revient[1,2,3]
.Réponses:
[*foo]
ouArray(foo)
fonctionnera la plupart du temps, mais dans certains cas, comme un hachage, cela le gâche.La seule façon dont je peux penser que cela fonctionne même pour un hachage est de définir une méthode.
la source
ensure_array
, prolongerto_a
to_a
. Par exemple,{a: 1, b: 2}.each ...
cela fonctionnerait différemment.Avec ActiveSupport (Rails):
Array.wrap
Si vous n'utilisez pas de rails, vous pouvez définir votre propre méthode similaire à la source des rails .
la source
class Array; singleton_class.send(:alias_method, :hug, :wrap); end
pour plus de gentillesse.La solution la plus simple est d'utiliser
[foo].flatten(1)
. Contrairement aux autres solutions proposées, cela fonctionnera bien pour les tableaux (imbriqués), les hachages etnil
:la source
Kernel#Array
c'est-àArray()
- dire le plus rapide de tous. Comparaison Ruby 2.5.1: Array (): 7936825.7 i / s. Array.wrap: 4199036.2 i / s - 1.89x plus lent. wrap: 644030.4 i / s - 12.32x plus lentArray(whatever)
devrait faire l'affairela source
ActiveSupport (rails)
ActiveSupport a une méthode assez intéressante pour cela. Il est chargé de Rails, donc la meilleure façon de le faire:
Splat (Ruby 1.9+)
L'opérateur splat (
*
) annule le tableau d'un tableau, s'il le peut:Bien sûr, sans tableau, il fait des choses bizarres, et les objets que vous "splatez" doivent être placés dans des tableaux. C'est un peu bizarre, mais cela signifie:
Si vous ne disposez pas d'ActiveSupport, vous pouvez définir la méthode:
Bien que, si vous prévoyez d'avoir de grands tableaux et moins de choses non-tableau, vous voudrez peut-être le changer - la méthode ci-dessus est lente avec de grands tableaux et peut même provoquer un débordement de votre pile (omg so meta). Quoi qu'il en soit, vous voudrez peut-être faire ceci à la place:
J'ai aussi quelques benchmarks avec et sans l'opérateur teneray.
la source
SystemStackError: stack level too deep
pour les éléments 1M (rubis 2.2.3).Hash#values_at
avec 1M d'arguments (en utilisantsplat
), et cela génère la même erreur.object.is_a? Array ? object : [*object]
?Array.wrap(nil)
retourne[]
pasnil
: /Que diriez-vous
la source
[].push(anything).flatten(1)
travaillerait! Il n'aplatit pas les tableaux imbriqués!Avec le risque de déclarer l'évidence, et sachant que ce n'est pas le sucre syntaxique le plus savoureux jamais vu sur la planète et les régions environnantes, ce code semble faire exactement ce que vous décrivez:
la source
vous pouvez écraser la méthode de tableau de Object
tout hérite de Object, donc to_a sera maintenant défini pour tout sous le soleil
la source
J'ai parcouru toutes les réponses et la plupart du temps ne fonctionne pas dans ruby 2+
Mais elado a la solution la plus élégante à savoir
Malheureusement, mais cela ne fonctionne pas non plus pour ruby 2+ car vous obtiendrez une erreur
Donc, pour résoudre ce problème, vous devez exiger.
la source
Puisque la méthode
#to_a
existe déjà pour les deux principales classes problématiques (Nil
etHash
), définissez simplement une méthode pour le reste en étendantObject
:et vous pouvez facilement appeler cette méthode sur n'importe quel objet:
la source