2016-04-17 7 views
1

Ich bin ein Anfänger arbeiten durch einige Übungen. Ich versuche, ein 2-dimensionales Array derart zu manipulieren, dass, wenn ein Element eine 1 ist, dann werden die umgebenden nicht-diagonalen Elemente in 1 geändert werden soll:Ändern der umgebenden Elemente eines Array-Elements

[[0,0,0,0], 
[0,0,1,0], 
[0,0,0,0], 
[0,0,0,0]] 

zurück

[[0,0,1,0], 
[0,1,1,1], 
[0,0,1,0], 
[0,0,0,0]] 

I sollte Ich stoße auf Probleme mit verschachtelten each_with_index: Nachdem ich die anfänglichen Änderungen für die linke und die rechte Umgebung angepasst habe, nimmt die Methode bei der Iteration eine frühere Anpassung vor und führt zu einer unerwünschten Änderung. Darüber hinaus, die die Linie sollte die „unten“ Element ändern wirft einen Fehler:

a = [[0,0,0,0], 
    [0,0,1,0], 
    [0,0,0,0], 
    [0,0,0,0] 
    ] 

a.each_with_index do |m, n| # n == index of main array 
    m.each_with_index do |x, y| # y == index of subarray 
     if x == 1 
      a[n][y+1] = 1 unless (a[n][y+1]).nil? #right 
      a[n][y-1] = 1 unless (a[n][y-1]).nil? #left 
      a[n-1][y] = 1 unless (a[n-1][y]).nil? #top 
      a[n+1][y] = 1 unless (a[n+1][y]).nil? #bottom--currently giving an error 
     end 
    end 
end 

Irgendwelche Vorschläge, wie ich über die Lösung dieser beiden Aspekte gehen können, werden gut aufgenommen werden.

+0

Welche unerwünschte Änderung? Arbeite darüber. Welcher Fehler? – sawa

Antwort

1

Ich schlage vor, Sie verwenden die Matrix Klasse.

require 'matrix' 

m = Matrix[*a] 
    #=> Matrix[[0, 0, 0, 0], 
    #   [0, 0, 1, 0], 
    #   [0, 0, 0, 0], 
    #   [0, 0, 0, 0]] 
row, col = m.index(1) 
    #=> [1, 2] 
Matrix.build(m.row_size, m.column_size) { |r,c| 
    (c-col).abs + (r-row).abs <= 1 ? 1 : 0 }.to_a 
    #=> [[0, 0, 1, 0], 
    # [0, 1, 1, 1], 
    # [0, 0, 1, 0], 
    # [0, 0, 0, 0]] 

Die nicht-Matrix Version davon (die die Verfahren verwendet Array#index, Fixnum#divmod, Array::new, Enumerable#each_slice und einige andere) wie folgt ist.

nrows, ncols = a.size, a.first.size 
    #=> [4, 4] 
row, col = a.flatten.index(1).divmod(ncols) 
    #=> [1, 2] 
Array.new(nrows*ncols) do |i| 
    r, c = i.divmod(ncols) 
    (c-col).abs + (r-row).abs <= 1 ? 1 : 0 
end.each_slice(ncols).to_a 
    #=> [[0, 0, 1, 0], 
    # [0, 1, 1, 1], 
    # [0, 0, 1, 0], 
    # [0, 0, 0, 0]] 

Ich finde die Methode, um die Matrix-Klasse zu sein, leichter zu verstehen, wenn es nicht so effizient sein kann.

3

Um Interferenz mit einem vorherigen Schritt zu vermeiden, können Sie das Array entweder (tief) duplizieren und das Referenzarray von dem ändernden Array trennen oder alle relevanten Indizes extrahieren, bevor Sie das Array ändern. Letzteres ist besser. Außerdem ist die Verwendung eines flachen Arrays viel einfacher als die Handhabung eines verschachtelten Arrays. Daher werde ich a in ein und von einem flacheren Array b konvertieren und innerhalb von b arbeiten.

b = a.flatten 

b 
.each_index.select{|i| b[i] == 1} 
.each do 
    |i| 
    b[i - 1] = 1 if b[i - 1] and i - 1 >= 0 
    b[i + 1] = 1 if b[i + 1] 
    b[i - 4] = 1 if b[i - 4] and i - 4 >= 0 
    b[i + 4] = 1 if b[i + 4] 
end 

a = b.each_slice(4).to_a 
# => [[0, 0, 1, 0], [0, 1, 1, 1], [0, 0, 1, 0], [0, 0, 0, 0]] 
+1

Die Überprüfungen von b [i-1] und b [i-4] werden nur vom ersten/vierten Ende des Arrays zurückgegeben, was ich nicht glaube. –

+0

@ FrederickCheung Das war mein Fehler. Danke für das Aufzeigen. – sawa