Hapus elemen duplikat dari array di Ruby

325

Saya memiliki array Ruby yang berisi elemen duplikat.

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

Bagaimana saya bisa menghapus semua elemen duplikat dari array ini sambil mempertahankan semua elemen unik tanpa menggunakan for-loop dan iterasi?

Mithun Sasidharan
sumber

Jawaban:

722
array = array.uniq

uniq menghapus semua elemen duplikat dan mempertahankan semua elemen unik dalam array.

Ini adalah salah satu dari banyak keindahan bahasa Ruby.

Mithun Sasidharan
sumber
50
tidak, uniq! metode akan mengembalikan nil jika arraynya belum unik Ex: a = [1,2,3,4] a.uniq -> [1,2,3,4] tetapi a.uniq! -> nil
duykhoa
15
saya tidak akan benar-benar melihat ini sebagai keindahan dari bahasa ruby ​​... itu hanya keindahan dari perpustakaan standar ruby? jangan salah paham, ada banyak hal indah tentang bahasa ini.
Justin L.
7
tulis yang sama di Objective-C, Javascript dan PHP. Kalau begitu beri tahu kami bahwa Ruby bukan bahasa yang indah!
Adam Waite
3
Ini juga berfungsi untuk tipe kompleks: [{how: "are"}, {u:"doing"}, {how: "are"}].uniq => [{:how=>"are"}, {:u=>"doing"}]
Blaskovicz
5
tentang apa yang dikatakan @duykhoa, uniq! metode mengembalikan nihil, tetapi Anda biasanya tidak peduli tentang kembalinya .uniq!ia melakukan pekerjaan pada objek itu sendiri
carpinchosaurio
82

Anda dapat mengembalikan persimpangan.

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

Ini juga akan menghapus duplikat.

jaredsmith
sumber
12
Secara fungsional, jawaban ini benar, tetapi saya pikir ini jauh lebih mudah dibaca daripada hanya menggunakan uniq.
Fiona T
21
Saya hanya meletakkannya di sini sehingga siapa pun yang mengunjungi halaman ini akan melihat cara lain untuk melakukannya juga, saya tidak mencoba mengatakan bahwa itu lebih baik.
jaredsmith
3
Alasan ini berhasil adalah karena ketika menggunakan operasi set, array yang dihasilkan diperlakukan sebagai set, yang merupakan struktur data yang biasanya tidak memiliki nilai berulang. Menggunakan a | a(gabungan) akan melakukan trik yang sama.
Cezar
47

Anda dapat menghapus elemen duplikat dengan metode uniq:

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

Apa yang mungkin juga berguna untuk diketahui adalah yang uniqmembutuhkan blok, jadi jika Anda memiliki array kunci:

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

dan Anda ingin tahu apa file unik itu, Anda bisa mengetahuinya dengan:

a.uniq { |f| f[/\d+$/] }.map { |p| p.split(':').last }
Marek Příhoda
sumber
5
Saya agak bingung dengan ini. Blok digunakan jika Anda membutuhkan fungsi perbandingan Anda sendiri - dalam contoh Anda, mengirim uniqke array tanpa blok akan mengembalikan nilai yang sama seperti halnya dengan blok Anda.
hdgarrood
18

Alternatif lain jika ada yang peduli.

Anda juga dapat menggunakan to_setmetode array yang mengubah Array menjadi Set dan menurut definisi, elemen set unik.

[1,2,3,4,5,5,5,6].to_set => [1,2,3,4,5,6]
Finks
sumber
4
Jika Anda peduli dengan memori, to_setakan mengalokasikan 4 objek, sementara uniqmengalokasikan satu.
Jan Klimo
18

Jika seseorang mencari cara untuk menghapus semua contoh nilai berulang, lihat " Bagaimana saya bisa mengekstrak elemen berulang secara efisien dalam array 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]
Lri
sumber
3
Atau cukup dengan melakukannya a = [1, 2, 2, 3] a.find_all { |x| a.count(x) == 1 } # [1, 3]
Tim Wright
Pertanyaan yang ditautkan tidak sama; Ia bertanya bagaimana menemukan nilai duplikat dan mengembalikannya. OP ingin menghapus duplikat.
Manusia Timah
0

Hanya untuk memberikan beberapa wawasan:

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

Yang mana, saat dijalankan, menghasilkan:

# >> 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}>)

Catatan: ini mengembalikan hasil yang buruk:

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

Coba gunakan operator XOR, tanpa menggunakan fungsi bawaan:

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

Dengan fungsi bawaan:

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

a.uniq
Santosh Mohanty
sumber
2
Saya belum menurunkan suara dan saya tidak tahu apa-apa tentang Ruby, tetapi bukankah .sort!juga fungsi bawaan?
Carolus