需要过滤数组的帮助吗?

时间:2018-09-13 01:04:46

标签: arrays ruby

我正在尝试从数组中删除奇数。

arr = [1, 2, 3, 4, 5, 6, 7, 8, 10]

def remove_odd_nums(arr)
  for x in arr
    if x % 2 == 0
      arr.delete(x)
    end
  end
end

print remove_odd_nums(arr)
# [1, 3, 5, 7, 10]

我似乎无法使该程序正常工作。该方法适用于除最后一个数字以外的数字。我在做什么错了?

4 个答案:

答案 0 :(得分:5)

您想删除奇数,但是您的程序正在删除偶数(x % 2 == 0检查x是否为偶数)

方法1:

arr = [1, 2, 3, 4, 5, 6, 7, 8, 10]
arr.delete_if &:odd?

print arr

delete_if通过增加arr的索引进行迭代,并在对元素评估块&:odd?之后立即删除该元素。换句话说,它将遍历数组中的每个元素,如果&:odd?为true,则删除该元素。

&:odd?:一个lambda函数,将一个对象传递给odd?方法,如果该对象为奇数,则返回true。可以找到进一步的解释what is the functionality of "&: " operator in ruby?

请注意,方法1实际上是修改原始数组。为了创建一个新的无奇数数组,有...

方法2:

non_odds = arr.select{|i| not i.odd?}

答案 1 :(得分:3)

TL; DR:在迭代数组时不要修改它。


让我们通过在循环内打印xarr的当前值来了解发生了什么:

def remove_odd_nums(arr)
  for x in arr
    p x: x, arr: arr # <- debug output
    if x % 2 == 0
      arr.delete(x)
    end
  end
end

remove_odd_nums([1, 2, 3, 4, 5, 6, 7, 8, 10])

输出:

{:x=>1, :arr=>[1, 2, 3, 4, 5, 6, 7, 8, 10]}
{:x=>2, :arr=>[1, 2, 3, 4, 5, 6, 7, 8, 10]}
{:x=>4, :arr=>[1, 3, 4, 5, 6, 7, 8, 10]}
{:x=>6, :arr=>[1, 3, 5, 6, 7, 8, 10]}
{:x=>8, :arr=>[1, 3, 5, 7, 8, 10]}

前两个x值符合预期:12。但是随后它继续前进到4,跳过了3。它还会跳过5710。但是为什么呢?

这是因为要在迭代时修改数组。将for循环视为某人指向某个特定位置的元素。最初看起来像这样:

1 2 3 4 5 6 7 8 10  <- array
^                   <- element

for然后移至下一个元素:

1 2 3 4 5 6 7 8 10
  ^

此时x % 2 == 0变为true,并且2从数组中删除:

1 3 4 5 6 7 8 10
  ^

for不知道此更改,只是继续前进到下一个元素:

1 3 4 5 6 7 8 10
    ^

这就是为什么我们无意中跳过了357也会发生同样的情况。

for最终到达8时:

1 3 5 7 8 10
        ^

它正在被删除:

1 3 5 7 10
        ^

for停止循环,因为它似乎已经到达数组的末尾。

答案 2 :(得分:2)

您好实用1只是为了阐明您为什么要破坏对象和数组?

如果您想过滤数组并仅选择even个数字,则可以尝试Array#select和Integer#even的组合?方法助手

    arr = arr = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
    # select all even numbers in an array
    arr.select(&:even?) # shorthand for arr.select {|number| number.even? }

将返回偶数

[0] 2,
[1] 4,
[2] 6,
[3] 8,
[4] 10

来源:

Array#select https://apidock.com/ruby/Array/select

整数甚至? https://ruby-doc.org/core-1.8.7/Integer.html

答案 3 :(得分:2)

Ruby具有出色的方法,可以根据块中的逻辑修改数组。

要获得仅包含奇数的数组,可以删除不符合测试的元素,或保留符合测试的数字。您可以返回一个新数组,也可以使用一种就地修改方法。

要删除不需要的值,请对新数组使用.reject或在适当的地方使用.reject!修改现有数组。

由于要删除,我们将在块内使用{|e| e%2!=0}来表示奇数:

> [1,2,3,4,5,6,7,8,9,10].reject {|e| e%2!=0}
=> [2, 4, 6, 8, 10]                            # new array
> arr = [1, 2, 3, 4, 5, 6, 7, 8, 10]
> arr.reject! {|e| e%2!=0}
=> [2, 4, 6, 8, 10]                            # arr modified in place

对于相同的结果,您也可以使用odd?逻辑测试而不是阻止:

> [1,2,3,4,5,6,7,8,9,10].reject &:odd?
=> [2, 4, 6, 8, 10]

或者,您可以保留所需的值,而不保留其他值。您可以在块内使用{|e| e%2==0}来获取偶数。或者,您可以使用&:even?代替该块。

您可以使用.keep_if返回一个新数组:

> arr
=> [1, 2, 3, 4, 5, 6, 7, 8, 10]
> [1,2,3,4,5,6,7,8,9,10].keep_if {|e| e%2==0}
=> [2, 4, 6, 8, 10]                               # new array. 

或使用.select!进行修改:

> arr = [1, 2, 3, 4, 5, 6, 7, 8, 10]
=> [1, 2, 3, 4, 5, 6, 7, 8, 10]
> arr.select! {|e| e%2==0}
=> [2, 4, 6, 8, 10]
> arr
=> [2, 4, 6, 8, 10]                                  # arr modified in place