Wie ordne ich mit Index in Ruby zu?

438

Was ist der einfachste Weg zu konvertieren

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

zu

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

Antworten:

835

Wenn Sie Ruby 1.8.7 oder 1.9 verwenden, können Sie die Tatsache verwenden, dass Iteratormethoden wie each_with_index, wenn sie ohne Block aufgerufen werden, ein EnumeratorObjekt zurückgeben, das Sie EnumerableMethoden wie mapon aufrufen können . So können Sie tun:

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

In 1.8.6 können Sie Folgendes tun:

require 'enumerator'
arr.enum_for(:each_with_index).map { |x,i| [x, i+2] }
sepp2k
quelle
Vielen Dank! Können Sie mir einen Hinweis auf die Dokumentation geben .each_with_index.map?
Mischa Moroshko
1
@ Mischa: mapist eine Methode Enumerablewie immer. each_with_index, Wenn sie ohne einen Block aufgerufen wird , gibt ein EnumeratorObjekt (in 1.8.7+), die Mischungen in Enumerable, so können Sie anrufen map, select, rejectusw. auf sie wie auf einem Array, Hash, Reichweite usw.
sepp2k
9
IMO dies ist einfacher und besser zu lesen in 1.8.7+:arr.map.with_index{ |o,i| [o,i+2] }
Phrogz
4
@Phrogz: map.with_indexfunktioniert in 1.8.7 nicht ( mapgibt ein Array zurück, wenn es in 1.8 ohne Block aufgerufen wird).
sepp2k
2
Es ist wichtig zu beachten, dass dies mit .map nicht funktioniert! Wenn Sie das Array, auf dem Sie sich befinden, direkt beeinflussen möchten.
Ash Blue
258

Ruby hat Enumerator # with_index (offset = 0) . Konvertieren Sie das Array also zuerst mit Object # to_enum oder Array # map in einen Enumerator :

[:a, :b, :c].map.with_index(2).to_a
#=> [[:a, 2], [:b, 3], [:c, 4]]
tokland
quelle
11
Ich glaube, das ist die bessere Antwort, weil es mit Karte funktioniert! foo = ['d'] * 5; foo.map!.with_index { |x,i| x * i }; foo #=> ["", "d", "dd", "ddd", "dddd"]
Connor McKay
130

In Ruby 1.9.3 gibt es eine verkettbare Methode, with_indexdie mit der Karte verkettet werden kann.

Zum Beispiel:

array.map.with_index { |item, index| ... }
fruqi
quelle
17

Übertriebene Verschleierung:

arr = ('a'..'g').to_a
indexes = arr.each_index.map(&2.method(:+))
arr.zip(indexes)
Andrew Grimm
quelle
12
Andrew muss eine gute Arbeitsplatzsicherheit haben! :)
David J.
9

Hier sind zwei weitere Optionen für 1.8.6 (oder 1.9) ohne Verwendung des Enumerators:

# 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]]
Phrogz
quelle
8

Ich habe die Syntax dieses Stils immer genossen:

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

Durch Aufrufen erhalten each_with_indexSie einen Enumerator, den Sie einfach mit Ihrem verfügbaren Index zuordnen können.

yburyug
quelle
4
Wie ist diese andere Form der Antwort, die fast 5 Jahre vor Ihrer gegeben wurde ?
Andrey Deineko
4

Ein lustiger, aber nutzloser Weg, dies zu tun:

az  = ('a'..'z').to_a
azz = az.map{|e| [e, az.index(e)+2]}
Automatico
quelle
Warum der Hass? Es ist ein funktionierender Weg, dies zu tun UND ich sage sogar, dass dies ein dummer Weg ist, um die Ergebnisse zu erzielen.
Automatico
Der Aufruf von #index bedeutet, dass dies jetzt eine O (N ^ 2) -Schleife ist. Warum auch die +2? :)
Rogerdpack
2
Wie ich schreibe A fun, but useless way. +2ist die Ausgabe zu erstellen, die das OP verlangt
Automatico
3
a = [1, 2, 3]
p [a, (2...a.size+2).to_a].transpose
Nikolay Bobrovskiy
quelle
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]]
Mo Wad
quelle
3
OH MEIN GOTT! Hast du überhaupt die anderen Antworten gelesen? map.with_indexexistiert bereits in rubin. Warum sollten Sie vorschlagen, die aufzählbare Klasse erneut zu öffnen und etwas hinzuzufügen, das bereits vorhanden ist?
Nathanvda
Dies könnte ein einfacherer Weg für 1.8.6 und 1.8.7 sein (ja, einige von uns verwenden es immer noch), anstatt seltsamere Dinge wie each_with_index.mapusw. verwenden zu müssen, und selbst diejenigen von uns in neueren Versionen ziehen es möglicherweise vor, es zu verwenden map.with_index FWIW :)
Rogerdpack
1

Ich mache das oft:

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

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

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

Anstatt direkt über die Elemente des Arrays zu iterieren, iterieren Sie über einen Bereich von Ganzzahlen und verwenden sie als Indizes, um die Elemente des Arrays abzurufen.

Grandinero
quelle
1
Wenn Sie die anderen Antworten lesen, hoffe ich, dass Sie jetzt erkennen, dass es bessere Ansätze gibt. Ich bin mir also nicht sicher, warum Sie dies hinzufügen mussten.
Nathanvda
Wenn Andrew Grimms Antwort zehn Stimmen verdient, dann verdient diese mindestens eine!
Camille Goudeseune