Как я могу удалить один элемент из массива по значению


343

У меня есть массив элементов в Ruby

[2,4,6,3,8]

Мне нужно удалить элементы со значением, 3например

Как я могу это сделать?


Интересно, почему delete array.delete(3)не работает внутри ruby ​​на контроллере рельсов
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, и мы хотим удалить только одну из них? (это связано с тем, что спрашивать здесь может быть лучше)
Navneet

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

5
array - subArrayне будет работать для Array of Arrays , но array.delete(subArray)будет работать.
Сэчины

21
Очень важное различие между [1,2,3] - [2]и [1,2,3].delete(2)заключается в том, что deleteметод изменяет исходный массив , в то время как [1,2,3] - [3]создает новый массив .
Тимоти Ковалев

Re subarrays (комментарий @ Sachin выше) «Конечно, это будет», вам просто нужно получить правильное обозначение: [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 () и - = value будут удалять каждый экземпляр значения, переданного ему в массиве. Чтобы удалить первый экземпляр определенного элемента, вы можете сделать что-то вроде

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], как я сказал, мне понравился), но я хотел бы упомянуть другой возможный способ.
Бароп

Этот метод также имеет преимущество, заключающееся в возврате массива вместо удаленного элемента.
Ф.Веббер



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, вам нужно добавить метод в Array class Array; def except(*values); self - values; end; end.
Марк Свардстрем

3

Вы также можете обезьяна исправить это. Я никогда не понимал, почему у Ruby есть 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

Компилирование всех различных опций для удаления в ruby

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 - удаляет каждый элемент, для которого блок имеет значение true. Это изменит массив. Массив изменяется мгновенно при вызове блока.

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

reject - это вернет новый массив с элементами, для которых данный блок имеет значение false. Порядок поддерживается с этим.

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.