2016-11-09 61 views
0

對於以下代碼段。
我想從數組中刪除等於3的元素。 但代碼只刪除了第一個元素。當我調試代碼,
我發現迭代器只循環一次而不是兩次數組。
我不確定是什麼導致了這個問題。任何幫助將不勝感激。Ruby無法刪除陣列中的元素

nums = [3,3] 
def remove_element(nums, val) 
    nums.each_with_index do |num,index| 
     if num == val 
      nums.slice!(index) 
     end 
    end 
    nums.length 
end 

remove_element(nums,3) 
+6

千萬不要嘗試在迭代它來修改陣列。調查員瘋了。 – mudasobwa

+2

不要修改您正在迭代的相同數組。 –

+0

@mudasobwa謝謝,能否讓我知道原因 –

回答

3

正如您所評論的那樣,您在迭代數組的同時修改了數組,從而刪除了第一個元素,並結束了迭代。如果您在nums.each_with_index循環內放置打印語句,您將看到它只打印一次。

一種更好的方式來刪除一個元素,可以使用拒絕像下面的方法:

nums.reject!{|item| item == 3} 
+0

謝謝,請你讓我知道爲什麼迭代器在刪除第一個元素後停止 –

+0

@MarcoSong,我認爲在內部迭代器繼續尋找下一個項目來迭代,當你刪除第一個元素,並且迭代器在第二個元素上,但它沒有找到任何東西,然後返回。在這裏檢查:http://apidock.com/ruby/Enumerator – 2016-11-09 08:20:48

3

由於@steenslag已經指出的那樣,delete方法做你想要什麼:

n = [1,2,3,3,4,5,6,3,4,5,3,2,1,8] 
n.delete(3) 
n 

回報:[1, 2, 4, 5, 6, 4, 5, 2, 1, 8]

這是值得看的這個替代代碼:

nums = [3,3] 
def remove_element(nums, val) 
    nums.each_with_index do |num,index| 
     nums_before_slice = nums.clone 
     if num == val 
      sliced = nums.slice!(index) 
     end 
     puts "nums: #{nums_before_slice}, index: #{index}, sliced: #{sliced.inspect}" 
    end 
end 

remove_element(nums,3) 

puts "Result: #{nums.inspect}" 

輸出結果爲:

​​

正如您所看到的,迭代只發生一次,因爲第二個元素在進行第二次迭代之前已被刪除。

這個結果比較這個版本的代碼:

nums = [3,3] 
def remove_element(nums, val) 
    nums.clone.each_with_index do |num,index| 
     nums_before_slice = nums.clone 
     if num == val 
      sliced = nums.slice!(index) 
     end 
     puts "nums: #{nums_before_slice}, index: #{index}, sliced: #{sliced.inspect}" 
    end 
end 

remove_element(nums,3) 

puts "Result: #{nums.inspect}" 

導致:

nums: [3, 3], index: 0, sliced: 3 
nums: [3], index: 1, sliced: nil 
Result: [3] 

這就是現在運行在原有nums副本的迭代,但結果是與第二次迭代相同 - 沒有第二個要移除的元素。

+0

感謝您的幫助。很容易理解。 –

+0

'n.delete(3)'。 – steenslag

+0

@steenslag是的 - 刪除是另一個(也許更好)選項。 – ReggieB

2

什麼方法delete

nums = [3,3] 
def remove_element(nums, val) 
    nums.delete(val) 
    nums.length 
end 
remove_element(nums, 3) 
#=> 0 

delete_if

nums = [3,3] 
def remove_element(nums, val) 
    nums.delete_if { |element| element == val } 
    nums.length 
end 
remove_element(nums, 3) 
#=> 0 

UPD

require 'benchmark' 

array = Array.new(100000) { rand(5) } 

Benchmark.bm do |x| 
    x.report("delete: ") { array.delete(5) } 
    x.report("delete_if: ") { array.delete_if { |e| e == 5 } } 
    x.report("reject: ") { array.reject! { |e| e == 5 } } 
end 

#   user  system  total  real 
# delete: 0.000000 0.000000 0.000000 ( 0.004230) 
# delete_if: 0.010000 0.000000 0.010000 ( 0.006387) 
# reject: 0.010000 0.000000 0.010000 ( 0.007543) 
+0

是的,我從leetcode看到這個解決方案。它非常強大和乾淨。但代碼運行速度非常快,我認爲刪除方法的工作方式可能不是很有效 –

+0

@MarcoSong你可以檢查更新:) –

+0

真棒,根本不慢 –