Làm thế nào tôi có thể xóa một phần tử từ một mảng theo giá trị


343

Tôi có một loạt các yếu tố trong Ruby

[2,4,6,3,8]

Tôi cần loại bỏ các yếu tố có giá trị 3chẳng hạn

Làm thế nào để làm điều đó?


tôi tự hỏi tại sao delete array.delete(3)không hoạt động trong bộ điều khiển ruby ​​trên đường ray
ImranNaqvi

2
có thể là do active recordphương phápdelete
ImranNaqvi

Câu trả lời:


481

Tôi nghĩ rằng tôi đã tìm ra nó:

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

189
Cá nhân tôi thích [1, 2, 3, 4, 5] - [3]kết quả => [1, 2, 4, 5]từ irb.
Travis

24
Điều gì xảy ra nếu có nhiều mục trong 3 và chúng tôi chỉ muốn xóa một trong số chúng? (điều này có liên quan vì vậy yêu cầu điều này ở đây có thể là tốt nhất)
Navneet

113
Chỉ cần một cái đầu lên là .delete () sẽ trả về giá trị đã xóa, chứ không phải mảng đã sửa đổi với giá trị bị xóa.
Joshua Pinter

23
Hậu quả khác cần xem xét là làm thay deleteđổi mảng bên dưới trong khi -tạo ra một mảng mới (được trả về cho bạn) mà không có giá trị bị xóa. Tùy thuộc vào trường hợp sử dụng của bạn, một trong hai cách tiếp cận có thể có ý nghĩa.
srt32

2
@ user3721428, xóa (3) không đề cập đến phần tử ở vị trí 3 mà thay vào đó xóa bất kỳ phần tử nào khớp với số nguyên 3. Nó sẽ xóa tất cả các lần xuất hiện của 3 và không liên quan gì đến chỉ số hoặc vị trí của mảng.
bkunzi01

226

Mượn từ Travis trong các bình luận, đây là một câu trả lời tốt hơn:

Cá nhân tôi thích [1, 2, 7, 4, 5] - [7] kết quả => [1, 2, 4, 5]từirb

Tôi đã sửa đổi câu trả lời của anh ấy khi thấy rằng 3 là phần tử thứ ba trong mảng mẫu của anh ấy. Điều này có thể dẫn đến một số nhầm lẫn cho những người không nhận ra rằng 3 ở vị trí 2 trong mảng.


21
Như srt32 chỉ ra trong câu trả lời, có một sự khác biệt quan trọng để thực hiện giữa việc sử dụng .delete-. .deletesẽ trả về giá trị đã bị xóa khỏi Array, nếu có; -sẽ không. Như vậy [ 1, 2, 3 ] - [ 2 ]sẽ trở lại [ 1, 3 ], trong khi [ 1, 2, 3 ].delete( 2 )sẽ trở lại 2.
Argus9

5
array - subArraysẽ không hoạt động cho Mảng mảng , nhưng array.delete(subArray)sẽ làm được.
Sachin

20
Sự khác biệt rất quan trọng giữa [1,2,3] - [2][1,2,3].delete(2)deletephương thức đó sửa đổi mảng ban đầu , trong khi [1,2,3] - [3]tạo ra một mảng mới .
Timothy Kovalev

Đăng ký lại (nhận xét của @ Sachin ở trên) "Chắc chắn là như vậy", bạn chỉ cần có ký hiệu đúng: [1,2,[2],2,3,4] - [2]cung cấp cho bạn [1, [2], 3, 4], nhưng [1,2,[2],2,3,4] - [[2]]cung cấp cho bạn [1, 2, 2, 3, 4]. :-)
Tom Hundt

69

Một lựa chọn khác:

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

a -= [3]

kết quả là

=> [2, 4, 6, 8] 

50

Tôi không chắc có ai đã tuyên bố điều này chưa, nhưng Array.delete () và - = value sẽ xóa mọi phiên bản của giá trị được truyền cho nó trong Array. Để xóa phiên bản đầu tiên của phần tử cụ thể, bạn có thể làm một cái gì đó như

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

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

Có thể có một cách đơn giản hơn. Tôi không nói rằng đây là cách thực hành tốt nhất, nhưng nó là thứ cần được công nhận.


1
Tôi đã tìm kiếm một cách để làm điều này và chỉ xóa một ví dụ của phần tử bao gồm các bản sao và điều này hoạt động rất tốt!
xeroshogun

Tôi nghĩ rằng câu trả lời này là sai, đơn giản là vì Array.index () có thể đinil
Windmaomao

32

Giả sử bạn muốn xóa 3 theo giá trị tại nhiều vị trí trong một mảng, tôi nghĩ cách thức ruby ​​để thực hiện tác vụ này sẽ là sử dụng phương thức xóa_if:

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

Bạn cũng có thể sử dụng remove_if trong việc xóa các phần tử trong kịch bản 'mảng của mảng'.

Hy vọng điều này giải quyết truy vấn của bạn


25

Tôi thích -=[4]cách được đề cập trong các câu trả lời khác để xóa các yếu tố có giá trị là 4.

Nhưng có cách này:

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

đã đề cập ở đâu đó trong " Các hoạt động mảng cơ bản ", sau khi nó đề cập đến mapchức năng.


Nhưng bạn không thể sử dụng.delete(6)
Zac

@Zac tất nhiên nhưng mà câu trả lời đã được đề cập (như có rất súc tích -=cách a-=[4]ví dụ a=a-[4]. [3,4]-[4], Mà tôi nói tôi thích), nhưng tôi muốn đề cập đến một cách khác có thể.
barlop

Phương pháp này cũng có lợi thế là trả về mảng thay vì phần tử bị xóa.
F.Webber 8/2/19



15

Dưới đây là một số điểm chuẩn:

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

Và một lần nữa với một mảng lớn hơn chứa nhiều bản sao:

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

Và thậm chí lớn hơn với nhiều bản sao hơn:

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
Vì vậy, tốt nhất là gì? :)
Kirby

8

Tôi đã cải thiện giải pháp của Niels

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

Bây giờ bạn có thể sử dụng

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

Giải pháp của bạn không hoạt động trên irbbảng điều khiển 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>
hssongra

1
Để khai báo trong IRB, bạn cần thêm phương thức vào Mảng class Array; def except(*values); self - values; end; end.
Mark Swardstrom

3

Bạn cũng có thể khỉ vá nó. Tôi không bao giờ hiểu tại sao Ruby có một exceptphương thức cho Hashnhưng không phải cho Array:

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

Bây giờ bạn có thể làm:

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

Hoặc là:

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

1
Bạn không cần value.kind_of(Array)kiểm tra. Chỉ cần sử dụng self - Array(value).
Sasgorilla

3

Vì vậy, khi bạn có nhiều lần xuất hiện của 3 và bạn chỉ muốn xóa lần xuất hiện đầu tiên của 3, bạn chỉ cần làm một số việc như dưới đây.

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

Loại bỏ không phá hủy sự xuất hiện đầu tiên:

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

2

Nếu bạn cũng muốn thực hiện thao tác xóa này thành chuỗi, vì vậy bạn có thể xóa một số mục và tiếp tục thao tác chuỗi trên mảng kết quả, sử dụng tap:

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

1

Tổng hợp tất cả các tùy chọn khác nhau để xóa trong ruby

xóa - Xóa các yếu tố phù hợp theo giá trị. Nếu nhiều hơn một giá trị khớp với nó sẽ loại bỏ tất cả. Nếu bạn không quan tâm đến số lần xuất hiện hoặc chắc chắn về sự xuất hiện đơn lẻ, hãy sử dụng phương pháp này.

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

xóa_at - Xóa phần tử tại chỉ mục đã cho. Nếu bạn biết chỉ số sử dụng phương pháp này.

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

xóa_if - Xóa mọi phần tử cho khối nào là đúng. Điều này sẽ sửa đổi các mảng. Mảng thay đổi ngay lập tức khi khối được gọi.

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

từ chối - Điều này sẽ trả về mảng mới với các phần tử mà khối đã cho là sai. Việc đặt hàng được duy trì với điều này.

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

Từ chối! - giống như xóa_if . Mảng có thể không thay đổi ngay lập tức khi khối được gọi.

Nếu bạn muốn xóa nhiều giá trị khỏi mảng, tùy chọn tốt nhất là dưới đây.

a = [2, 3, 7, 4, 6, 21, 13]
b = [7, 21]
a = a - b    # a - [2, 3, 4, 6, 13]
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.