Возвращение похожих элементов массива в Ruby

Скажем, у меня такой массив:

arr = ['footballs_jumba_10', 'footballs_jumba_11', 'footballs_jumba_12',
       'footballs_jumba_14', 'alpha_romeo_11', 'alpha_romeo_12',
       'alpha_juliet_10', 'alpha_juliet_11']

Если бы я хотел вернуть дубликаты (если любая из этих строк в массиве была абсолютно одинаковой, я бы просто

return arr.detect{ |a| arr.count(a) > 1 }

но что, если бы я хотел получить только дубликаты первых 10 символов каждого элемента массива, не зная об изменениях заранее? Вот так:

['footballs_', 'alpha_rome', 'alpha_juli']

Ответ 1

Это довольно просто с методом Arry#difference, который я предложил в своем ответе здесь:

arr << "Let add a string that appears just once"
  #=> ["footballs_jumba_10", "footballs_jumba_11", "footballs_jumba_12",
  #    "footballs_jumba_14", "alpha_romeo_11", "alpha_romeo_12",
  #    "alpha_juliet_10", "alpha_juliet_11", "Let add a string that appears just once"]

a = arr.map { |s| s[0,10] }
  #=> ["footballs_", "footballs_", "footballs_", "footballs_", "alpha_rome",
  #    "alpha_rome", "alpha_juli", "alpha_juli", "Let add "] 
b = a.difference(a.uniq)
  #=> ["footballs_", "footballs_", "footballs_", "alpha_rome", "alpha_juli"] 
b.uniq
  #=> ["footballs_", "alpha_rome", "alpha_juli"] 

Ответ 2

Используйте Array#uniq:

arr.map {|e| e[0..9]}.uniq
# => ["footballs_", "alpha_rome", "alpha_juli"]

Ответ 3

Вы можете сделать что-то вроде этого:

def partial_duplicates(elements)
  unique = {}
  duplicates = {}

  elements.each do |e|
    partial = e[0..9]

      # If the element is in the hash, it is a duplicate.
      if first_element = unique[partial]
        duplicates[first_element] = true
        duplicates[e] = true
      else
        # include the element as unique
        unique[partial] = e
      end
  end

  duplicates.keys
end

Это приведет к возврату уникальных дубликатов. Если вы хотите все дубликаты, вы можете просто использовать Array.

Кроме того, это возвращает все полные представления каждого дубликата, поскольку он кажется более полезным и, вероятно, тем, что вы хотите:

partial_duplicates(arr)
=> ["footballs_jumba_10", "footballs_jumba_11", "footballs_jumba_12", "footballs_jumba_14", "alpha_romeo_11", "alpha_romeo_12", "alpha_juliet_10", "alpha_juliet_11"]

Если вы хотите только частичные дубликаты, вы можете изменить условие:

if unique[partial]
  duplicates[partial] = true
else
  unique[partial] = true
end

то

partial_duplicates(arr)
=> ["footballs_", "alpha_rome", "alpha_juli"]