Xóa các phần tử trùng lặp khỏi mảng trong Ruby


325

Tôi có một mảng Ruby chứa các phần tử trùng lặp.

array = [1,2,2,1,4,4,5,6,7,8,5,6]

Làm cách nào tôi có thể xóa tất cả các phần tử trùng lặp khỏi mảng này trong khi vẫn giữ lại tất cả các phần tử duy nhất mà không cần sử dụng vòng lặp for và vòng lặp?

Câu trả lời:


722
array = array.uniq

uniq loại bỏ tất cả các phần tử trùng lặp và giữ lại tất cả các phần tử duy nhất trong mảng.

Đây là một trong nhiều người đẹp của ngôn ngữ Ruby.


50
không, uniq! phương thức sẽ trả về nil nếu mảng đã là duy nhất Ex: a = [1,2,3,4] a.uniq -> [1,2,3,4] nhưng a.uniq! -> nil
duykhoa

15
tôi thực sự sẽ không coi đây là một vẻ đẹp của ngôn ngữ ruby ​​... nó chỉ là vẻ đẹp của thư viện tiêu chuẩn ruby? đừng hiểu lầm tôi, có rất nhiều điều hay về ngôn ngữ.
Justin L.

7
viết tương tự trong Objective-C, Javascript và PHP. Sau đó, nói với chúng tôi rằng Ruby không phải là một ngôn ngữ đẹp!
Adam Chờ đợi

3
Điều này cũng hoạt động cho các loại phức tạp: [{how: "are"}, {u:"doing"}, {how: "are"}].uniq => [{:how=>"are"}, {:u=>"doing"}]
Blaskovicz

5
về những gì @duykhoa nói, uniq! phương thức trả về con số không, nhưng bạn thường không quan tâm đến sự trở lại của phương thức .uniq!mà nó thực hiện trên chính đối tượng
Carpinchizardio

82

Bạn có thể trả lại giao lộ.

a = [1,1,2,3]
a & a

Điều này cũng sẽ xóa các bản sao.


12
Về mặt chức năng, câu trả lời này là chính xác, nhưng tôi nghĩ rằng điều này rõ ràng là dễ đọc hơn là chỉ sử dụng uniq.
Fiona T

21
Tôi chỉ đặt nó ở đây vì vậy bất cứ ai truy cập trang này cũng sẽ thấy những cách khác để làm điều đó, tôi đã không cố gắng nói nó tốt hơn bằng mọi cách.
jaredsmith

3
Lý do điều này hoạt động là vì khi sử dụng các thao tác tập hợp, mảng kết quả được coi là một tập hợp, đó là một cấu trúc dữ liệu thường không có giá trị lặp lại. Sử dụng a | a(union) sẽ làm cùng một thủ thuật.
Cezar

47

Bạn có thể xóa các phần tử trùng lặp bằng phương thức uniq:

array.uniq  # => [1, 2, 4, 5, 6, 7, 8]

Điều cũng có thể hữu ích để biết là uniqmất một khối, vì vậy nếu bạn có một mảng các phím:

["bucket1:file1", "bucket2:file1", "bucket3:file2", "bucket4:file2"]

và bạn muốn biết các tệp duy nhất là gì, bạn có thể tìm ra nó với:

a.uniq { |f| f[/\d+$/] }.map { |p| p.split(':').last }

5
Tôi hơi bối rối vì điều này. Khối được sử dụng nếu bạn cần chức năng so sánh của riêng mình - trong ví dụ của bạn, gửi uniqđến mảng đó mà không có khối sẽ trả về cùng giá trị như với khối của bạn.
hdgarrood

18

Chỉ là một sự thay thế khác nếu có ai quan tâm.

Bạn cũng có thể sử dụng to_setphương thức của một mảng chuyển đổi Mảng thành Tập hợp và theo định nghĩa, các phần tử tập hợp là duy nhất.

[1,2,3,4,5,5,5,6].to_set => [1,2,3,4,5,6]

4
Nếu bạn quan tâm đến bộ nhớ, to_setsẽ phân bổ 4 đối tượng, trong khi uniqphân bổ một đối tượng .
Jan Klimo

18

Nếu ai đó đang tìm cách loại bỏ tất cả các phiên bản của các giá trị lặp lại, hãy xem " Làm cách nào tôi có thể trích xuất hiệu quả các phần tử lặp lại trong một mảng Ruby? ".

a = [1, 2, 2, 3]
counts = Hash.new(0)
a.each { |v| counts[v] += 1 }
p counts.select { |v, count| count == 1 }.keys # [1, 3]

3
Hoặc đơn giản có thể làm a = [1, 2, 2, 3] a.find_all { |x| a.count(x) == 1 } # [1, 3]
Tim Wright

Câu hỏi liên kết không giống nhau; Đó là hỏi làm thế nào để tìm các giá trị trùng lặp và trả lại chúng. OP muốn loại bỏ trùng lặp.
Tin Man

0

Chỉ để cung cấp một số cái nhìn sâu sắc:

require 'fruity'
require 'set'

array = [1,2,2,1,4,4,5,6,7,8,5,6] * 1_000

def mithun_sasidharan(ary)
  ary.uniq
end

def jaredsmith(ary)
  ary & ary
end

def lri(ary)
  counts = Hash.new(0)
  ary.each { |v| counts[v] += 1 }
  counts.select { |v, count| count == 1 }.keys 
end

def finks(ary)
  ary.to_set
end

def santosh_mohanty(ary)
    result = ary.reject.with_index do |ele,index|
      res = (ary[index+1] ^ ele)
      res == 0
    end
end

SHORT_ARRAY = [1,1,2,2,3,1]
mithun_sasidharan(SHORT_ARRAY) # => [1, 2, 3]
jaredsmith(SHORT_ARRAY) # => [1, 2, 3]
lri(SHORT_ARRAY) # => [3]
finks(SHORT_ARRAY) # => #<Set: {1, 2, 3}>
santosh_mohanty(SHORT_ARRAY) # => [1, 2, 3, 1]

puts 'Ruby v%s' % RUBY_VERSION

compare do
  _mithun_sasidharan { mithun_sasidharan(array) }
  _jaredsmith { jaredsmith(array) }
  _lri { lri(array) }
  _finks { finks(array) }
  _santosh_mohanty { santosh_mohanty(array) }
end

Mà, khi chạy, kết quả là:

# >> Ruby v2.7.1
# >> Running each test 16 times. Test will take about 2 seconds.
# >> _mithun_sasidharan is faster than _jaredsmith by 2x ± 0.1
# >> _jaredsmith is faster than _santosh_mohanty by 4x ± 0.1 (results differ: [1, 2, 4, 5, 6, 7, 8] vs [1, 2, 1, 4, 5, 6, 7, 8, 5, 6, 1, 2, 1, 4, 5, 6, 7, 8, 5, 6, 1, 2, 1, 4, 5, 6, 7, 8, 5, 6, 1, 2, 1, 4, 5, 6, 7, 8, 5, 6, 1, 2, 1, 4, 5, 6, 7, 8, 5, 6, 1, 2, 1, 4, 5, 6, 7, 8, 5, 6, 1, 2, 1, 4, 5, 6, 7, 8, 5, 6, 1, 2, 1, 4, 5, 6, 7, 8, 5, 6, 1, 2, 1, 4, 5, 6, 7, 8, 5, 6, 1, 2, 1, 4, 5, 6, 7, 8, 5, 6, 1, 2, 1, 4, 5, 6, 7, 8, 5, 6, 1, 2, 1, 4, 5, 6, 7, 8, 5, 6, 1, 2, 1, 4, 5, 6, 7, 8, 5, 6, 1, ...
# >> _santosh_mohanty is similar to _lri (results differ: [1, 2, 1, 4, 5, 6, 7, 8, 5, 6, 1, 2, 1, 4, 5, 6, 7, 8, 5, 6, 1, 2, 1, 4, 5, 6, 7, 8, 5, 6, 1, 2, 1, 4, 5, 6, 7, 8, 5, 6, 1, 2, 1, 4, 5, 6, 7, 8, 5, 6, 1, 2, 1, 4, 5, 6, 7, 8, 5, 6, 1, 2, 1, 4, 5, 6, 7, 8, 5, 6, 1, 2, 1, 4, 5, 6, 7, 8, 5, 6, 1, 2, 1, 4, 5, 6, 7, 8, 5, 6, 1, 2, 1, 4, 5, 6, 7, 8, 5, 6, 1, 2, 1, 4, 5, 6, 7, 8, 5, 6, 1, 2, 1, 4, 5, 6, 7, 8, 5, 6, 1, 2, 1, 4, 5, 6, 7, 8, 5, 6, 1, 2, 1, 4, 5, 6, 7, 8, 5, 6, 1, 2, 1, 4, 5, 6, ...
# >> _lri is similar to _finks (results differ: [] vs #<Set: {1, 2, 4, 5, 6, 7, 8}>)

Lưu ý: những kết quả trả về xấu này:

  • lri(SHORT_ARRAY) # => [3]
  • finks(SHORT_ARRAY) # => #<Set: {1, 2, 3}>
  • santosh_mohanty(SHORT_ARRAY) # => [1, 2, 3, 1]

-4

Hãy thử sử dụng toán tử XOR mà không sử dụng các hàm tích hợp:

a = [3,2,3,2,3,5,6,7].sort!

result = a.reject.with_index do |ele,index|
  res = (a[index+1] ^ ele)
  res == 0
end

print result

Với các chức năng tích hợp:

a = [3,2,3,2,3,5,6,7]

a.uniq

2
Tôi đã không được đánh giá thấp và tôi không biết gì về Ruby, nhưng đó .sort!cũng không phải là một chức năng sẵn có?
Carolus
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.