2011-01-15 3 views

Répondre

685

Si vous utilisez Ruby 1.8.7 ou 1.9, vous pouvez utiliser le fait que les méthodes iterator comme each_with_index, lorsqu'il est appelé sans un bloc, renvoyer un objet Enumerator, que vous pouvez appeler des méthodes Enumerable comme map sur. Alors, vous pouvez:

arr.each_with_index.map { |x,i| [x, i+2] } 

En 1.8.6 vous pouvez faire:

require 'enumerator' 
arr.enum_for(:each_with_index).map { |x,i| [x, i+2] } 
+0

Merci! Pourriez-vous me donner un pointeur vers la documentation pour '.each_with_index.map'? –

+0

Dans ce cas 'map' est une fonction de quoi? –

+1

@Misha: 'map' est une méthode de' Enumerable' comme toujours. 'Each_with_index', lorsqu'il est appelé sans bloc, retourne un objet' Enumerator' (en 1.8.7+), qui se mélange dans 'Enumerable', vous pouvez donc appeler' map', 'select',' reject' etc. sur elle comme sur un tableau, un hachage, une plage, etc. – sepp2k

9

Voici deux options pour 1.8.6 (ou 1.9) sans utiliser recenseur:

# Fun with functional 
arr = ('a'..'g').to_a 
arr.zip((2..(arr.length+2)).to_a) 
#=> [["a", 2], ["b", 3], ["c", 4], ["d", 5], ["e", 6], ["f", 7], ["g", 8]] 

# The simplest 
n = 1 
arr.map{ |c| [c, n+=1 ] } 
#=> [["a", 2], ["b", 3], ["c", 4], ["d", 5], ["e", 6], ["f", 7], ["g", 8]] 
14

Plus haut obscurcissement:

arr = ('a'..'g').to_a 
indexes = arr.each_index.map(&2.method(:+)) 
arr.zip(indexes) 
+7

J'aime celui-là, code obscur est toujours amusant à maintenir. –

+9

Andrew doit avoir une bonne sécurité d'emploi! :) –

203

Ruby> = 1.9.3 a Enumerator#with_index(offset = 0). Pour convertir le tableau à un recenseur, utilisez Object#to_enum ou Array#map, ce qui se sent plus déclarative pour vous:

[:a, :b, :c].map.with_index(2).to_a 
#=> [[:a, 2], [:b, 3], [:c, 4]] 
+7

Ceci est la meilleure réponse jusqu'à présent! –

+3

Solution très élégante, merci! – dolzenko

+8

Je crois que c'est la meilleure réponse, car cela fonctionnera avec la carte! 'foo = ['d'] * 5; foo.map! .with_index {| x, i | x * i}; foo # => ["", "d", "dd", "ddd", "dddd"] ' –

3
a = [1, 2, 3] 
p [a, (2...a.size+2).to_a].transpose 
2
module Enumerable 
    def map_with_index(&block) 
    i = 0 
    self.map { |val| 
     val = block.call(val, i) 
     i += 1 
     val 
    } 
    end 
end 

["foo", "bar"].map_with_index {|item, index| [item, index] } => [["foo", 0], ["bar", 1]] 
+3

OMG! As-tu lu les autres réponses? 'map.with_index' existe déjà dans ruby. Pourquoi suggérer de rouvrir la classe énumérable et ajouter quelque chose qui existe déjà? – nathanvda

+0

Cela pourrait être un moyen plus facile d'aller pour 1.8.6 et 1.8.7 (oui certains d'entre nous l'utilisent encore) au lieu d'avoir à utiliser des trucs bizarres comme 'each_with_index.map' etc et même ceux d'entre nous sur les versions plus récentes pourraient préférez-vous utiliser map.with_index FWIW :) – rogerdpack

1

Je fais souvent ceci:

arr = ["a", "b", "c"] 

(0...arr.length).map do |int| 
    [arr[int], int + 2] 
end 

#=> [["a", 2], ["b", 3], ["c", 4]] 

Au lieu de itérer directement au-dessus les éléments du tableau, vous itérez sur une plage d'entiers et vous les utilisez comme indices pour récupérer les éléments du tableau.

+1

Si vous lisez les autres réponses, j'espère que vous réalisez maintenant qu'il existe de meilleures approches. Donc pas sûr pourquoi vous avez besoin d'ajouter cela. – nathanvda

+0

Si la réponse d'Andrew Grimm mérite dix votes, alors celui-ci en mérite au moins un! –

+0

Je pense que vous devriez jeter une boucle for pour une bonne mesure;) –

0

Un amusement, mais inutile façon de le faire:

az = ('a'..'z').to_a 
azz = az.map{|e| [e, az.index(e)+2]} 
+0

Pourquoi la haine? C'est un moyen efficace de le faire ET je dis même que c'est un moyen stupide d'atteindre les résultats. – Automatico

+0

l'appel à #index signifie que c'est maintenant une boucle O (N^2) aussi pourquoi le +2? :) – rogerdpack

+1

Comme j'écris 'Une manière amusante, mais inutile '. '+ 2' est de créer la sortie que l'OP demande – Automatico

71

En Ruby 1.9.3 il existe une méthode appelée chainable with_index qui peut être enchaînée à la carte.

Par exemple: array.map.with_index { |item, index| ... }

6

J'ai toujours aimé la syntaxe de ce style:

a = [1, 2, 3, 4] 
a.each_with_index.map { |el, index| el + index } 
# => [1, 3, 5, 7] 

Invoquer each_with_index vous obtient un recenseur vous pouvez mapper facilement sur votre index disponible.

+2

comment est cette forme différente [la réponse, donnée presque 5 ans avant la vôtre] (http://stackoverflow.com/a/4697573/1772830)? –

Questions connexes