3

有人可以向我解释下面的代码在做什么。 before并且after是哈希。

def differences(before, after)
    before.diff(after).keys.sort.inject([]) do |diffs, k|
        diff = { :attribute => k, :before => before[k], :after => after[k] }
        diffs << diff; diffs
    end
end

它是从纸迹不同的宝石。

4

2 回答 2

4

这是密集的代码,毫无疑问。因此,正如您所说before,并且after是作为参数传递给方法的哈希(-like?)对象。调用before.diff(after)返回另一个哈希,然后立即.keys调用它。这将返回返回的哈希中的所有键diff。键作为数组返回,然后立即排序。

然后我们得到最复杂/最密集的位。使用inject该排序的键数组,该方法构建一个数组(diffsinject块内调用),该数组将作为该inject方法的返回值。

该数组由差异记录组成。before.diff(after)每条记录都是一个散列 - 通过从返回值的排序键数组中获取一个键来构建。这些散列存储了被区分的属性,它在前散列中的样子以及在后散列中的样子。

因此,简而言之,该方法获取两个散列之间的一堆差异,并将它们收集到一个散列数组中。该哈希数组是该方法的最终返回值。

注意inject可以而且经常比这简单得多。通常它用于简单地将一组值简化为一个结果,方法是一遍又一遍地应用一个操作并将结果存储在累加器中。您可能知道inject其他reduce语言;reduceinjectRuby 中的别名。这是一个更简单的示例inject

[1,2,3,4].inject(0) do |sum, number|
  sum + number
end
# => 10

0 是累加器 - 初始值。在 pair|sum, number|中,sum将是累加器,并且number将是数组中的每个数字,一个接一个。什么inject是加 1 到 0,将结果存储到sum下一轮,将 2 加到sumsum再次存储结果等等。累加器的单个最终值sum将是返回值。这里 10. 在您的示例中增加的复杂性是累加器与块内的值在类型上不同。这不太常见,但还不错或不习惯。(编辑:Andrew Marshall 提出了一个很好的观点,也许这很糟糕。请参阅他对原始问题的评论。@tokland 指出,inject这里只是地图的一个非常复杂的替代方案。它不好。)有关更多示例,请参阅我在对您的问题的评论中链接到的文章inject

编辑:正如@tokland 在一些评论中指出的那样,代码似乎只需要一个简单的map. 那时它会更容易阅读。

def differences(before, after)
  before.diff(after).keys.sort.map do |k|
    { :attribute => k, :before => before[k], :after => after[k] }
  end
end

我太专注于解释代码在做什么。我什至没有想到如何简化它。

于 2012-06-21T00:42:19.893 回答
1

它根据底层对象查找前后不同的条目,然后以更方便的格式构建这些差异的列表。

before.diff(after)查找不同的条目。

keys.sort按排序顺序为您提供(差异地图的)键

inject([])就像map,但从初始化为空数组的差异开始。

该块为这些差异中的每一个创建diff一行(哈希),然后将其附加到diffs.

于 2012-06-20T23:31:11.350 回答