Comment cartographier avec index en Ruby?


438

Quelle est la façon la plus simple de convertir

[x1, x2, x3, ... , xN]

à

[[x1, 2], [x2, 3], [x3, 4], ... , [xN, N+1]]

Réponses:


835

Si vous utilisez ruby ​​1.8.7 ou 1.9, vous pouvez utiliser le fait que les méthodes d'itérateur comme each_with_index, lorsqu'elles sont appelées sans bloc, retournent un Enumeratorobjet, que vous pouvez appeler des Enumerableméthodes comme mapon. Vous pouvez donc faire:

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

Dans 1.8.6, vous pouvez faire:

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

Merci! Pourriez-vous me donner un pointeur sur la documentation pour .each_with_index.map?
Misha Moroshko

1
@Misha: mapest une méthode Enumerablecomme toujours. each_with_index, Lorsqu'il est appelé sans bloc, retourne un Enumeratorobjet (en 1.8.7+), qui se mélange dans Enumerable, de sorte que vous pouvez appeler map, select, rejectetc. sur elle comme sur un tableau, hachage, etc. gamme
sepp2k

9
IMO c'est plus simple et meilleure lecture dans 1.8.7+:arr.map.with_index{ |o,i| [o,i+2] }
Phrogz

4
@Phrogz: map.with_indexne fonctionne pas en 1.8.7 ( mapretourne un tableau lorsqu'il est appelé sans bloc en 1.8).
sepp2k

2
Important de noter que cela ne fonctionne pas avec .map! si vous souhaitez affecter directement le tableau sur lequel vous bouclez.
Ash Blue


130

Dans ruby ​​1.9.3, il existe une méthode chaînable appelée with_index qui peut être chaînée pour mapper.

Par exemple:

array.map.with_index { |item, index| ... }

18

Sur l'obscurcissement supérieur:

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

12
Andrew doit avoir une grande sécurité d'emploi! :)
David J.19

9

Voici deux autres options pour 1.8.6 (ou 1.9) sans utiliser l'énumérateur:

# 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]]


4

Une façon amusante mais inutile de le faire:

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

Pourquoi la haine? C'est une façon fonctionnelle de le faire ET je dis même que c'est une façon stupide d'atteindre les résultats.
Automatico

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

2
Au moment où j'écris A fun, but useless way. +2est de créer la sortie demandée par l'OP
Automatico


1
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! Avez-vous même lu les autres réponses? map.with_indexexiste déjà en rubis. Pourquoi suggérer de rouvrir la classe énumérable et d'ajouter quelque chose qui existe déjà?
nathanvda

Cela pourrait être un moyen plus facile d'aller pour 1.8.6 et 1.8.7 (oui certains d'entre nous l'utilisent toujours) au lieu d'avoir à utiliser des trucs plus étranges comme each_with_index.mapetc. et même ceux d'entre nous sur les versions plus récentes pourraient préférer avoir à 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 d'itérer directement sur les éléments du tableau, vous parcourez 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. Vous ne savez donc pas pourquoi vous avez besoin d'ajouter cela.
nathanvda

Si la réponse d'Andrew Grimm mérite dix votes, alors celui-ci mérite au moins un!
Camille Goudeseune
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.