Реальный алгоритм Ruby

Я хочу написать решатель типа анаграммы в Ruby, но он будет работать против списка слов, например.

Список слов:

the
these
one
owner

Я бы позволил пользователю ввести несколько букв, например noe, и он будет искать список слов для слов, которые он может сделать, используя буквы, которые пользователь вводит, и вернет one, и если они войдут в "eth", или даже "это" оно вернет the. Я пытался подумать об эффективном способе сделать это, но я зацикливал каждое слово, сопоставлял букву в слове, проверяя слово для каждой буквы и обе длины совпадали. Может ли кто-нибудь дать совет о более эффективном и эффективном способе сделать это?

Ответы

Ответ 1

Большая идея состоит в том, что все анаграммы идентичны при сортировке. Поэтому, если вы создаете хэш (не знаете, что Ruby называет этим) списков, где ключи сортируются словами, а значение представляет собой список слов, которые сортируются по заданному ключу, то вы можете быстро найти анаграммы, сортируя слово и поиск в вашем хеше.

Ответ 2

rrenaud answer is great, и вот пример того, как построить такой хэш в ruby, учитывая массив с именем "words", который содержит все слова в вашем словаре:

@words_hash = words.each_with_object(Hash.new []) do |word, hash|
  hash[word.chars.sort] += [word]
end

Приведенный выше код предполагает ruby ​​1.9.2. Если вы используете более старую версию, то chars не существует, но вы можете использовать .split('').sort.

Объект по умолчанию хеша установлен как пустой массив, что упрощает кодирование в некоторых случаях, потому что вам не нужно беспокоиться о том, что хэш дает вам нуль.

Источник: https://github.com/DavidEGrayson/anagram/blob/master/david.rb

Ответ 3

Одним из решений может быть:

def combine_anagrams(words)
  output_array = Array.new(0)
  words.each do |w1|
    temp_array = []
    words.each do |w2|
      if (w2.downcase.split(//).sort == w1.downcase.split(//).sort)
        temp_array.push(w2)
      end
    end
    output_array.push(temp_array)
  end
  return output_array.uniq
end

Ответ 4

Я не мог удержаться от решения этой рубиновой викторины:)

class String

  def permutation(&block)
    arr = split(//)
    arr.permutation { |i| yield i.join }
  end
end


wordlist = ["one", "two"]

"noe".permutation do |i|
  puts "match found: #{i}" if wordlist.include?(i)
end

Основная идея заключается в том, что он создает и создает массив и использует его функцию перестановок, чтобы придумать результат. Это может быть неэффективно, но я нахожу его изящным.: D

Ответ 6

def combine_anagrams(words)
  cp = 0
  hash = Hash.new []
  words.each do |word|
    cp += 1
    (cp..words.count).each do |i|
      hash[word.to_s.chars.sort.join] += [word]
    end
    hash[word.to_s.chars.sort.join] = hash[word.to_s.chars.sort.join].uniq
  end
  return hash
end

Ответ 7

Здесь очень похоже. Чтение из файла словаря и сравнение отсортированных символов в виде массива. Сортировка выполняется по предварительно выбранным кандидатам.

def anagrams(n)
  text = File.open('dict.txt').read

  candidates = []
  text.each_line do |line|
    if (line.length - 1) == n.length
      candidates << line.gsub("\n",'')
    end
  end

  result = []

  candidates.each do |word|
    if word.chars.sort == n.chars.sort
      result << word
    end
  end

  result

end