Ruby实现考虑位置的数组差异方法:计算句子单词变化数
如何在Ruby中计算两个数组的“差异元素”(保留重复实例)
你需要对比两个单词数组(比如句子拆分后的结果),计算变化的单词数量,但Ruby内置的Array#-方法会移除所有相同值的实例,无法满足需求。例如:
arr1 = [1, 2, 3, 4] arr2 = [4, 1, 2, 1, 2, 3, 4, 4] arr2 - arr1 # => [],但你期望得到 [4, 1, 2, 4] arr3 = [1, 2, 3, 4] arr4 = [4, 3, 2, 1] arr4 - arr3 # => [],但你期望得到 [4, 3, 2, 1]
直接按索引对比会因为元素偏移导致结果不准确,你希望通过找到原数组的最长连续子集并移除,剩余部分即为变化内容。
解决方案
核心思路是:先检查修改后的数组中是否包含原数组的连续完整副本,若存在则移除该副本,剩余元素就是变化的部分;若不存在,则整个修改后的数组都视为变化内容。
1. 获取变化的元素数组
def get_changed_elements(original, modified) subarray_length = original.length return modified.dup if subarray_length.zero? || modified.length < subarray_length # 找到原数组在修改后数组中连续出现的起始索引 match_index = (0..modified.length - subarray_length).find do |i| modified[i, subarray_length] == original end if match_index # 移除匹配的连续子数组,拼接剩余部分 modified[0...match_index] + modified[match_index + subarray_length..-1] else modified.dup end end
2. 计算变化的单词数量
如果只需要统计数量,可以简化为:
def count_changed_words(original, modified) subarray_length = original.length return modified.length if subarray_length.zero? || modified.length < subarray_length # 检查是否存在连续匹配的原数组 has_consecutive_match = (0..modified.length - subarray_length).any? do |i| modified[i, subarray_length] == original end has_consecutive_match ? modified.length - subarray_length : modified.length end
测试示例
# 第一个示例 arr1 = [1, 2, 3, 4] arr2 = [4, 1, 2, 1, 2, 3, 4, 4] get_changed_elements(arr1, arr2) # => [4, 1, 2, 4] count_changed_words(arr1, arr2) # => 4 # 第二个示例 arr3 = [1, 2, 3, 4] arr4 = [4, 3, 2, 1] get_changed_elements(arr3, arr4) # => [4, 3, 2, 1] count_changed_words(arr3, arr4) # => 4
说明
- 该实现优先寻找原数组的第一个连续匹配项并移除,若你需要处理多个匹配场景,可以将
find替换为select后做进一步逻辑调整,你的示例场景下第一个匹配已能满足需求。 - 若原数组为空,直接返回修改后的数组;若修改后的数组比原数组短,也直接返回修改后的数组(因为不可能包含原数组的连续副本)。
内容的提问来源于stack exchange,提问作者Max Williams
相关产品推荐
相关产品推荐

