web-dev-qa-db-fra.com

Fusionner et entrelacer deux tableaux dans Ruby

J'ai le code suivant:

a = ["Cat", "Dog", "Mouse"]
s = ["and", "&"]

Je veux fusionner le tableau s dans le tableau a qui me donnerait:

["Cat", "and", "Dog", "&", "Mouse"]

En regardant à travers les documents Ruby Array and Enumerable, je ne vois pas de méthode qui y parviendrait.

Est-il possible de le faire sans parcourir chaque tableau?

102
Chris Ledet

Vous pouvez le faire avec:

a.Zip(s).flatten.compact
168
DigitalRoss

Cela ne donnera pas un tableau de résultats dans l'ordre demandé par Chris, mais si l'ordre du tableau résultant n'a pas d'importance, vous pouvez simplement utiliser a |= b. Si vous ne voulez pas muter a, vous pouvez écrire a | b et assignez le résultat à une variable.

Reportez-vous à la documentation relative à l'union pour la classe Array à l'adresse http://www.Ruby-doc.org/core/classes/Array.html#M000275 .

Cette réponse suppose que vous ne voulez pas que des éléments de tableau en double soient dupliqués. Si vous souhaitez autoriser les éléments en double dans votre tableau final, a += b devrait faire l'affaire. Encore une fois, si vous ne voulez pas muter a, utilisez a + b et assignez le résultat à une variable.

En réponse à certains commentaires sur cette page, ces deux solutions fonctionneront avec des tableaux de toute taille.

32
Michael Stalker

Si vous ne voulez pas dupliquer, pourquoi ne pas utiliser simplement l'opérateur nion :

new_array = a | s
28
Douglas

Voici une solution qui permet d’entrelacer plusieurs baies de tailles différentes (solution générale):

arr = [["Cat", "Dog", "Mouse", "boo", "Zoo"],
 ["and", "&"],
 ["hello", "there", "you"]]

first, *rest = *arr; first.Zip(*rest).flatten.compact
=> ["Cat", "and", "hello", "Dog", "&", "there", "Mouse", "you", "boo", "Zoo"]
6
Abdo
s.inject(a, :<<)

s   #=> ["and", "&"]
a   #=> ["Cat", "Dog", "Mouse", "and", "&"]

Cela ne vous donne pas l'ordre que vous avez demandé, mais c'est une bonne façon de fusionner deux tableaux en ajoutant à celui-ci.

6
user131441

Ce n'est pas vraiment élégant, mais cela fonctionne pour les tableaux de toutes tailles:

>> a.map.with_index { |x, i| [x, i == a.size - 2 ? s.last : s.first] }.flatten[0..-2] 
#=> ["Cat", "and", "Dog", "&", "Mouse"]
5
Michael Kohl

Pourquoi pas une solution plus générale qui fonctionne même si le premier tableau n’est pas le plus long et accepte un nombre quelconque de tableaux?

a = [
    ["and", "&"],
    ["Cat", "Dog", "Mouse"]
]

b = a.max_by(&:length)
a -= [b]
b.Zip(*a).flatten.compact

 => ["Cat", "and", "Dog", "&", "Mouse"]
3
Mike

Une façon de faire l'entrelacement et de garantir celui qui est le plus grand tableau pour la méthode Zip consiste à remplir l'un des tableaux avec nil jusqu'à la taille de l'autre. De cette façon, vous garantissez également quel élément de quel tableau sera en première position:

preferred_arr = ["Cat", "Dog", "Mouse"]
other_arr = ["and","&","are","great","friends"]

preferred_arr << nil while preferred_arr.length < other_arr.length
preferred_arr.Zip(other_arr).flatten.compact
#=> ["Cat", "and", "Dog", "&", "Mouse", "are", "great", "friends"]
1
Joao Cunha

Pour gérer la situation où a et s ne sont pas de la même taille:

a.Zip(s).flatten.compact | s
  • .compact _ supprime nil lorsque a est supérieur à s
  • | s ajoutera les éléments restants de s lorsque a sera inférieur à s
0
Shubham Chaudhary