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.