如何检查一对单词是否只有1个字母不同?

时间:2013-06-11 17:52:48

标签: ruby string methods

在编写比较2个单词的方法时,如何检查单词是否只有1个字母不同?我假设单词长度相同,字母顺序无关紧要(参见“眼镜蛇”,“bravo”)。

def one_letter_apart?(word1, word2)

我期待以下结果:

one_letter_apart?("abra","abro") == true
one_letter_apart?("cobra","bravo") == true
one_letter_apart?("bravo","tabby") == false
one_letter_apart?("abc","cab") == false

我尝试了一些操作它们的方法(拆分,排序,然后设置相等并添加到新数组,然后计数),但到目前为止都没有。非常感谢任何想法。

4 个答案:

答案 0 :(得分:5)

这个使用了String#sub仅替换它找到的第一件事的事实。

def one_different_char?(str, other)
  other_str = other.dup
  str.chars{|char| other_str.sub!(char, '')} #sub! just replaces just one occurence of char
  other_str.size == 1
end


test_set = [["abra","abro"],["cobra","bravo"],["bravo","tabby"],["abc","cab"]]
test_set.each{|first, second| puts one_different_char?(first, second) }

#true
#true
#false
#false

答案 1 :(得分:4)

检查Levenshtein距离

你想要Levenstein distance。例如,使用text gem

require 'text'

def one_letter_apart? string1, string2
  Text::Levenshtein.distance(string1, string2).eql? 1
end

one_letter_apart? "abra", "abro"
# => true 
one_letter_apart? "cobra", "bravo"
# => false 

答案 2 :(得分:1)

def one_letter_apart?(s1, s2)
  return false if s1.length != s2.length

  a2 = s2.chars.to_a
  s1.chars.each do |c|
    if i = a2.index(c)
      a2.delete_at(i)
    end
  end

  a2.length == 1
end

one_letter_apart?("abra","abro") == true
# => true
one_letter_apart?("cobra","bravo") == true
# => true
one_letter_apart?("bravo","tabby") == false
# => true
one_letter_apart?("abc","cab") == false
# => true

更新:回答你的工作原理问题:这是与steenslag完全相同的通用算​​法,但我没有考虑使用String#sub!进行删除,所以我转换为数组并使用indexdelete_at的组合来删除给定字符的第一个匹配项。天真的方法是a2.delete_at(a2.index(c)),但如果c中不存在字符a2,则index会返回nil,这是{的无效输入{1}}。解决方法是仅在delete_at返回非delete_at的内容时才调用index,这就是我所做的。声明nil并将其设置为i,并且a2.index(c)评估该作业的值。它与:

相同
if

我更喜欢steenslag的方法,如果我想到i = a2.index(c) if i # ... ,我会做同样的事情。

答案 3 :(得分:-1)

如果两个字符串具有相同的长度且只有一个不同的字母,而所有其他字母位于相同的位置,则此函数返回true:

def one_letter_apart? string1, string2
  return false if string1.size != string2.size
  found = false
  (0...string1.size).each do |i|
    next if string1[i] == string1[i]
    return false if found  # if found is already true, and we found another difference, then result is false.
    found = true  # We found the first difference.
  end
  found  # True if only one difference was found.
end

此功能处理错误位置的字母(如“cobra”和“bravo”):

def one_letter_apart? string1, string2
  letters1 = string1.chars.each_with_object(Hash.new(0)) { |c, h| h[c] += 1 }
  letters2 = string2.chars.each_with_object(Hash.new(0)) { |c, h| h[c] -= 1 }
  diff = letters1.merge(letters2) { |key, count1, count2| count1 + count2 }
  return diff.values.select { |v| v != 0 } .sort == [-1, 1]
end