Нужна помощь в фильтрации массива? - PullRequest
0 голосов
/ 13 сентября 2018

Я пытаюсь удалить нечетные числа из массива.

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 голосов
/ 13 сентября 2018

В 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. 

или использовать .выберите! для изменения на месте:

> 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
0 голосов
/ 13 сентября 2018

Здравствуйте, Practical1 просто чтобы уточнить, почему вы хотите уничтожать объекты и массив?

Если вы хотите отфильтровать массив и выбрать только числа 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

Integer # даже? https://ruby -doc.org / ядро-1.8.7 / Integer.html

0 голосов
/ 13 сентября 2018

TL; DR: не изменять массив при его итерации.


Давайте посмотрим, что происходит, напечатав текущее значение x и arr внутри цикла:

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 соответствуют ожидаемым: 1 и 2. Но затем он переходит к 4, пропуская 3. Также пропускаются 5, 7 и 10. Но почему?

Это потому, что вы модифицируете массив, итерируя его. Думайте о цикле 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 становится истинным, а 2 удаляется из массива:

1 3 4 5 6 7 8 10
  ^

for не знает об этом изменении и просто переходит к следующему элементу:

1 3 4 5 6 7 8 10
    ^

, поэтому мы непреднамеренно пропустили 3. То же самое происходит для 5 и 7.

Когда for наконец достигает 8:

1 3 5 7 8 10
        ^

он удаляется:

1 3 5 7 10
        ^

и for прекращают цикл, потому что кажется, что он достиг конца массива.

0 голосов
/ 13 сентября 2018

Вы хотите удалить нечетные числа, но ваша программа удаляет четные числа (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?: лямбда-функция, передающая объект в метод odd?, который возвращает true, если объект является нечетным числом.Дальнейшие объяснения можно найти Какова функциональность оператора "&:" в ruby?

Обратите внимание, что метод 1 фактически изменяет исходный массив.Чтобы создать новый массив нечетных чисел, есть ...

МЕТОД 2:

non_odds = arr.select{|i| not i.odd?}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...