Як я можу видалити один елемент із масиву за значенням


343

У мене є масив елементів у Ruby

[2,4,6,3,8]

Мені потрібно видалити елементи зі значенням, 3наприклад

Як це зробити?


мені цікаво, чому delete array.delete(3)не працює в рубіні на рейкових контролерах
ImranNaqvi

2
можливо завдяки active recordметодуdelete
ImranNaqvi

Відповіді:


481

Я думаю, я це зрозумів:

a = [3, 2, 4, 6, 3, 8]
a.delete(3)
#=> 3
a
#=> [2, 4, 6, 8]

189
Мені особисто подобається, до [1, 2, 3, 4, 5] - [3]яких результатів => [1, 2, 4, 5]приходить irb.
Тревіс

24
Що робити, якщо є кілька записів з 3, і ми хотіли видалити лише один з них? (це пов’язано, тому запитання про це тут може бути найкращим)
Навнеет

113
Просто заголовки вгору, що .delete () поверне видалене значення, а не модифікований масив із вилученим значенням.
Джошуа Пінтер

23
Іншим наслідком, який слід врахувати, є те, що він deleteмутує базовий масив, тоді як -створює новий масив (який повертається вам) без видаленого значення. Залежно від конкретного випадку використання будь-який підхід може мати сенс.
srt32

2
@ user3721428, delete (3) не посилається на елемент у позиції 3, але замість цього видаляє будь-який елемент, що відповідає цілому числу 3. Він видалить усі входження 3 і не має нічого спільного з індексом або положенням масивів.
bkunzi01

226

Позичивши Тревіс у коментарях, це краща відповідь:

Мені особисто подобається, до [1, 2, 7, 4, 5] - [7]яких результатів => [1, 2, 4, 5]приходитьirb

Я змінив його відповідь, побачивши, що 3 є третім елементом у його прикладі. Це може призвести до певної плутанини для тих, хто не усвідомлює, що 3 знаходиться в положенні 2 в масиві.


21
Як зазначає srt32 у відповіді, існує важливе розмежування, яке слід використовувати між використанням .deleteта -. .deleteповерне значення, яке було видалено з масиву, якщо воно є; -не буде. Так [ 1, 2, 3 ] - [ 2 ]повернеться [ 1, 3 ], поки [ 1, 2, 3 ].delete( 2 )повернеться 2.
Аргус9

5
array - subArrayне працюватиме для масиву масивів , але array.delete(subArray)зробить.
Сачин

21
Дуже важлива відмінність [1,2,3] - [2]і [1,2,3].delete(2)полягає в тому, що deleteметод модифікує вихідний масив , [1,2,3] - [3]створюючи новий масив .
Тимофій Ковальов

Знову підряди (@ коментар Сачіна вище) "Звичайно, це потрібно", вам просто потрібно правильно позначити: [1,2,[2],2,3,4] - [2]дає [1, [2], 3, 4], але [1,2,[2],2,3,4] - [[2]]дає вам [1, 2, 2, 3, 4]. :-)
Том

69

Ще один варіант:

a = [2,4,6,3,8]

a -= [3]

що призводить до

=> [2, 4, 6, 8] 

50

Я не впевнений, чи хтось це заявив, але Array.delete () і - = значення видалить кожен екземпляр передаваного йому значення в межах масиву. Для того, щоб видалити перший екземпляр конкретного елемента, ви можете зробити щось подібне

arr = [1,3,2,44,5]
arr.delete_at(arr.index(44))

#=> [1,3,2,5]

Тут може бути і простіший спосіб. Я не кажу, що це найкраща практика, але це щось, що слід визнати.


1
Я шукав спосіб це зробити і видалити лише один екземпляр елемента в разі дублікатів, і це чудово працює!
xeroshogun

Я думаю, що ця відповідь помилкова, просто тому, що arr.index () може пітиnil
windmaomao

32

Припускаючи, що ви хочете видалити 3 за значенням у кількох місцях масиву, я думаю, що способом рубіну для виконання цієї задачі було б використання методу delete_if:

[2,4,6,3,8,3].delete_if {|x| x == 3 } 

Ви також можете використовувати delete_if для видалення елементів у сценарії "масив масивів".

Сподіваюся, це вирішить ваш запит


25

Мені подобається -=[4]спосіб, зазначений в інших відповідях, для видалення елементів, значення яких дорівнює 4.

Але є такий спосіб:

irb(main):419:0> [2,4,6,3,8,6].delete_if{|i|i==6}
=> [2, 4, 3, 8]
irb(main):420:0>

згадується десь у " Основних операціях масиву ", після цього він згадує про mapфункцію.


Але не можна просто скористатися.delete(6)
Зак

@Zac, звичайно , але ця відповідь уже згадувалося (як має дуже короткий -=спосіб a-=[4]є a=a-[4]. [3,4]-[4], Які я сказав , мені сподобалося), але я хотів би відзначити ще один можливий шлях.
барлоп

Цей метод також має перевагу повернення масиву замість видаленого елемента.
F.Webber



15

Ось деякі орієнтири:

require 'fruity'


class Array          
  def rodrigo_except(*values)
    self - values
  end    

  def niels_except value
    value = value.kind_of?(Array) ? value : [value]
    self - value
  end
end

ARY = [2,4,6,3,8]

compare do
  soziev  { a = ARY.dup; a.delete(3);               a }
  steve   { a = ARY.dup; a -= [3];                  a }
  barlop  { a = ARY.dup; a.delete_if{ |i| i == 3 }; a }
  rodrigo { a = ARY.dup; a.rodrigo_except(3);         }
  niels   { a = ARY.dup; a.niels_except(3);           }
end

# >> Running each test 4096 times. Test will take about 2 seconds.
# >> soziev is similar to barlop
# >> barlop is faster than steve by 2x ± 1.0
# >> steve is faster than rodrigo by 4x ± 1.0
# >> rodrigo is similar to niels

І знову з більшим масивом, що містить безліч дублікатів:

class Array          
  def rodrigo_except(*values)
    self - values
  end    

  def niels_except value
    value = value.kind_of?(Array) ? value : [value]
    self - value
  end
end

ARY = [2,4,6,3,8] * 1000

compare do
  soziev  { a = ARY.dup; a.delete(3);               a }
  steve   { a = ARY.dup; a -= [3];                  a }
  barlop  { a = ARY.dup; a.delete_if{ |i| i == 3 }; a }
  rodrigo { a = ARY.dup; a.rodrigo_except(3);         }
  niels   { a = ARY.dup; a.niels_except(3);           }
end

# >> Running each test 16 times. Test will take about 1 second.
# >> steve is faster than soziev by 30.000000000000004% ± 10.0%
# >> soziev is faster than barlop by 50.0% ± 10.0%
# >> barlop is faster than rodrigo by 3x ± 0.1
# >> rodrigo is similar to niels

А ще більше - більше копій:

class Array          
  def rodrigo_except(*values)
    self - values
  end    

  def niels_except value
    value = value.kind_of?(Array) ? value : [value]
    self - value
  end
end

ARY = [2,4,6,3,8] * 100_000

compare do
  soziev  { a = ARY.dup; a.delete(3);               a }
  steve   { a = ARY.dup; a -= [3];                  a }
  barlop  { a = ARY.dup; a.delete_if{ |i| i == 3 }; a }
  rodrigo { a = ARY.dup; a.rodrigo_except(3);         }
  niels   { a = ARY.dup; a.niels_except(3);           }
end

# >> Running each test once. Test will take about 6 seconds.
# >> steve is similar to soziev
# >> soziev is faster than barlop by 2x ± 0.1
# >> barlop is faster than niels by 3x ± 1.0
# >> niels is similar to rodrigo

7
Отже, що найкраще? :)
Кірбі

8

Я вдосконалив рішення Нільса

class Array          
  def except(*values)
    self - values
  end    
end

Тепер ви можете використовувати

[1, 2, 3, 4].except(3, 4) # return [1, 2]
[1, 2, 3, 4].except(4)    # return [1, 2, 3]

Ваше рішення не працює на irbконсолі 2.2.1 :007 > [1, 2, 3, 4].except(3, 4) NoMethodError: undefined method except for [1, 2, 3, 4]:Array from (irb):7 from /usr/share/rvm/rubies/ruby-2.2.1/bin/irb:11:in <main>
hgsongra

1
Щоб заявити в IRB, вам потрібно додати метод до масиву class Array; def except(*values); self - values; end; end.
Mark Swardstrom

3

Ви також можете наклеїти його мавпочки. Я ніколи не розумів, чому у Рубі є exceptметод, Hashа не для Array:

class Array
  def except value
    value = value.kind_of(Array) ? value : [value]
    self - value
  end
end

Тепер ви можете зробити:

[1,3,7,"436",354,nil].except(354) #=> [1,3,7,"436",nil]

Або:

[1,3,7,"436",354,nil].except([354, 1]) #=> [3,7,"436",nil]

1
value.kind_of(Array)Тест вам не потрібен . Просто використовуйте self - Array(value).
Сасгоріла

3

Тож, коли у вас є кілька випадків 3 і ви хочете лише видалити перше виникнення 3, ви можете просто зробити щось, як показано нижче.

arr = [2, 4, 6, 3, 8, 10, 3, 12]

arr.delete_at arr.index 3

#This will modify arr as [2, 4, 6, 8, 10, 3, 12] where first occurrence of 3 is deleted. Returns the element deleted. In this case => 3.

3

Неруйнівне видалення першого явища:

a = [2, 4, 6, 3, 8]
n = a.index 3
a.take(n)+a.drop(n+1)

2

Якщо ви також хочете зробити цю операцію видалення дозволеною, щоб ви могли видалити деякий елемент і продовжувати ланцюгові операції на отриманому масиві, використовуйте tap:

[2, 4, 6, 3, 8].tap { |ary| ary.delete(3) }.count #=> 4

1

Складання всіх різних параметрів для видалення в рубіні

delete - Видаляє відповідні елементи за значенням. Якщо збігається більше ніж одне значення, воно видалить усі. Якщо вам не байдуже кількість випадків або ви впевнені в одному випадку, використовуйте цей метод.

a = [2, 6, 3, 5, 3, 7]
a.delete(3)  # returns 3
puts a       # return [2, 6, 5, 7]

delete_at - Видаляє елемент із заданого індексу. Якщо ви знаєте індекс, використовуйте цей метод.

# continuing from the above example
a.delete_at(2) # returns 5
puts a         # returns [2, 6, 7]

delete_if - видаляє кожен елемент, для якого є істинним блоком. Це дозволить змінити масив. Масив змінюється миттєво під час виклику блоку.

b = [1, 2, 5, 4, 9, 10, 11]
b.delete_if {|n| n >= 10}.  # returns [1, 2, 5, 4, 9]

відхилити - Це поверне новий масив з елементами, для яких даний блок помилковий. Упорядкованість підтримується при цьому.

c = [1, 2, 5, 4, 9, 10, 11]
c.reject {|n| n >= 10}.  # returns [1, 2, 5, 4, 9]

відхилити! - те саме, що delete_if . Масив може не змінюватися миттєво, коли викликається блок.

Якщо ви хочете видалити декілька значень з масиву, найкращим варіантом є наступний.

a = [2, 3, 7, 4, 6, 21, 13]
b = [7, 21]
a = a - b    # a - [2, 3, 4, 6, 13]
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.