Ruby :比较两个单词并从中提取不常见的字母

ruby : compare two words and extract uncommon letters out of it

提问人:Seby 提问时间:7/8/2023 更新时间:7/9/2023 访问量:101

问:

我必须创建一个程序,该程序接受用户输入两个单词,并从两个单词中提取唯一的字母。

例如:两个词是“外推”和“其中”

删除常用字母表后,无论输入的单词顺序如何,结果都应为“extrpolatimg”。就像,虽然在外推中有两个“a”,但只删除了一个。

到目前为止,我编写的代码如下

puts "Enter the first_word : "

word_1 = gets.chomp.downcase.split('', 0)


puts "Enter second word name: "

word_2 = gets.chomp.downcase.split('', 0)

p word_1

p word_2

differences = word_1- word_2

p differences

#input1 = among
#input2 = extrapolation

# output => ["m","g"] 


该代码忽略了第二个单词中不存在的字母。

是否有任何内置的字符串方法可以处理此问题?

提前感谢您的帮助。

Ruby 字符串 比较

评论

0赞 Cary Swoveland 7/9/2023
在您的示例中,并出现在两个单词中,因此您删除了每个单词中的第一个和第二个。当每个单词中的哪个字符出现多次时,确定要删除哪个字符的规则是什么?如果这些词是 和 呢?'a''o''a''o''Extrapolation''Heathen'
0赞 Seby 7/9/2023
你好。。谢谢你的帮助..没有删除字母的顺序。.只是必须在两个单词中删除一次匹配的字母。..如果中间有一个 o,外推中有两个。只有一個“o”會從 match 上的每個字遊中刪除。第二个“O”将保留。任何订单都可以...
0赞 Cary Swoveland 7/9/2023
您需要在问题中澄清,如果要从字符串中删除字母的一个实例,它可以是该字母的任何实例,或者指定要删除的实例,即第一个或最后一个。对于示例中所需的结果,在不说明给出该结果的规则的情况下删除第一个但最后一个结果是令人困惑的。你没有回答我问题的第二部分,它涉及大写字母。也许您可以通过声明所有字符都是小写来简化。'a''o'

答:

1赞 justice margolis 7/8/2023 #1

对于手头的任务,你可以通过稍微改变你的方法来改变它。Ruby 非常棒,它允许我们使用 chars 方法将字符串转换为字符数组。因此,您可以将 split('', 0) 替换为 chars。

这里的逻辑是首先创建第二个单词字符的副本。然后,遍历第一个单词的字符。如果在第二个单词的副本中找到字符,请将其从第一个单词和第二个单词的副本中删除。这两个词中剩下的都是独特的字符。

让我们把它变成代码:

puts "Enter the first word: "
word_1 = gets.chomp.downcase.chars

puts "Enter the second word: "
word_2 = gets.chomp.downcase.chars

copy_word_2 = word_2.dup # Create a copy of word_2 characters

word_1.each do |char|
  if copy_word_2.include?(char)
    word_1.delete_at(word_1.index(char))
    copy_word_2.delete_at(copy_word_2.index(char))
  end
end

differences = word_1 + copy_word_2 # Combine remaining unique characters from both words

puts "The unique characters are: "
p differences

在这段代码中,我们使用 delete_at 方法删除数组中特定索引处的字符,并使用 index 方法查找该字符第一次出现的索引。包括?方法检查数组是否包含某个字符。

评论

0赞 Seby 7/8/2023
你好。。谢谢你。.我从没想过要复制..快速提问..当我们改变单词的顺序时..先说“其中”,再说“外推”。答案是不同的。字符“n”不会被取消/删除。
0赞 Seby 7/8/2023
word_2需要复制吗?如果是这样,为什么?如果用word_2代替copy_word_2,我会得到相同的结果。
0赞 Cary Swoveland 7/9/2023
对于问题中的示例,结果为 ,而所需的字符串为 。但是,如果你的答案是错误的,我的答案也是错的,因为我们得到了相同的结果。"extrplatiomg""extrpolatimg"
1赞 spickermann 7/9/2023 #2

我会这样做:

puts 'Enter the first_word:'
chars1 = gets.chomp.downcase.chars

puts 'Enter second word name:'
chars2 = gets.chomp.downcase.chars

((chars1 - chars2) + (chars2 - chars1)).join

# with 'extrapolation' and 'amoug'
# => "extrpltimg"

# with 'amoug' and 'extrapolation'
# => "mgextrplti"

评论

0赞 Seby 7/9/2023
你好。。谢谢你。.但答案仍然不匹配..外推有两个“a”,中间有一个“a”。您的解决方案删除了两个“A”。答案必须是“extrpolatimg”,无论我们如何输入“之间”,“外推”这两个词的顺序如何。换句话说,它会检查第二个单词是否存在该字符,如果是,则从两个单词中删除该字符的一个实例。我希望我是清楚的..
1赞 Cary Swoveland 7/9/2023 #3

假设我们得到两个词。

w1 = "extrapolation"
w2 = "among"

步骤 1:将每个字符串转换为字符数组

a1 = w1.chars
  #=> ["e", "x", "t", "r", "a", "p", "o", "l", "a", "t", "i", "o", "n"]
a2 = w2.chars
  #=> ["a", "m", "o", "n", "g"]

步骤 2:为每个数组创建一个哈希值,该哈希值给出数组中每个唯一字符的第一个实例的索引

def first_char_pos(a)
  a.each_with_index.with_object({}) do |(c,i),h|
    h[c] = i unless h.key?(c)
  end
end
h1 = first_char_pos(a1)
  #=> {"e"=>0, "x"=>1, "t"=>2, "r"=>3, "a"=>4,
  #    "p"=>5, "o"=>6, "l"=>7, "i"=>10, "n"=>12}
h2 = first_char_pos(a2)
  #=>{"a"=>0, "m"=>1, "o"=>2, "n"=>3, "g"=>4}

第 3 步:确定要从每个单词中删除的字母

letters_to_remove = a1 & a2
  #=> ["a", "o", "n"]

第 4 步:确定每个单词中要保留的字母索引

def indices_to_keep(a, h, letters_to_remove)
  a.size.times.to_a - h.values_at(*letters_to_remove)
end
idx1 = indices_to_keep(a1, h1, letters_to_remove)
  #=>[0, 1, 2, 3, 5, 7, 8, 9, 10, 11]
idx2 = indices_to_keep(a2, h2, letters_to_remove)
  #=> [1, 4]

第 5 步:按顺序确定每个单词中要保留的字母

s1 = a1.values_at(*idx1)
  #=> ["e", "x", "t", "r", "p", "l", "a", "t", "i", "o"]
s2 = a2.values_at(*idx2)
  #=> ["m", "g"]

第 6 步:形成所需的字符串

s1.join + s2.join
  #=> "extrplatiomg"

这与所需的字符串不同,即 。原因是我删除了要删除的每个字母的第一个实例,而通过删除每个字符串的第一个和每个字符串的最后一个来获得所需的字符串。要么是 OP 在给出所需结果时犯了错误,要么是我不明白确定要删除哪个字母实例的规则。"extrpolatimg""a""o"

我没有讨论可能出现大写字母的情况,因为我不知道适用于这种情况的规则。

评论

0赞 Seby 7/9/2023
你好。。像魅力一样工作。移除的顺序并不重要。我相信我在给出结果时在顺序上犯了一个错误。是的,所有字符都是小写的。非常感谢您的帮助。
2赞 Stefan 7/9/2023 #4

您可以使用 sub 替换模式的第一个匹配项:(可以是单个字符)

'extrapolation'.sub('a', '_')
#=> "extr_polation"

您还可以通过传递一个空字符串作为替换来删除第一个匹配项:

'extrapolation'.sub('a', '')
#=> "extrpolation"

这可以在循环中用于将一个字符串中的所有字符替换为另一个字符串:

input1 = 'among'
input2 = 'extrapolation'

result = input1

input2.each_char do |char|
  result = result.sub(char, '')
end

result
#=> "mg"

为了避免在每次迭代时创建一个新字符串,您可以重复调用 sub! 对字符串进行修改,这会就地修改接收器。但是,由于这种修改,您必须复制输入以避免修改:input1

result = input1.dup

input2.each_char do |char|
  result.sub!(char, '')
end

result
#=> "mg"

这可以通过利用 with_object 进一步重构,这对于在方法中提供隐式返回值特别有用:

def word_diff(string1, string2)
  string2.each_char.with_object(string1.dup) do |char, string|
    string.sub!(char, '')
  end
end

diff1 = word_diff(input2, input1)
#=> "extrplatio"

diff2 = word_diff(input1, input2)
#=> "mg"

diff1 + diff2
#=> "extrplatiomg"

从性能上讲,这种方法可能不适合(非常)大的字符串,因为它会为第二个字符串中的每个字符遍历第一个字符串一次(反之亦然)。