我想在ruby中模拟像hadoop这样的系统的map
和reduce
函数的实现,以验证该想法是否至少有效。
我有以下问题。我有两个元素列表:
List1
3 - A
4 - B
5 - C
7 - D
8 - F
List2
2 - A
8 - B
6 - C
9 - D
4 - E
我需要构建一个通用列表,其中包含与两个列表中常见字母相关联的数字总和:
commonList
5 - A
12 - B
11 - C
16 - D
我想使用map
和reduce
操作创建一个ruby脚本来解决此问题。我不确定如何解决这个问题,或者在ruby脚本中用什么程序来模拟这个问题。
任何帮助表示感谢。
答案 0 :(得分:2)
您可以尝试考虑MapReduce维基百科文章中提供的元素:
[key, value]
对上的方法调用。map
工作人员只会返回它作为输入获得的[key, value]
对key.hash % REDUCER_COUNT
。[key, list]
对,list是与该键相关联的值列表。如果列表长度超过一个元素,它将返回list
的总和(因为您只需要处理两个输入哈希中出现的元素)。here's我的(过)简化了上述的实现。
答案 1 :(得分:2)
假设我们已经实现了所有其他与map-reduce相关的函数(输入阅读器,输出编写器,全局排序......),这些函数将是map
和reduce
:< / p>
def map(input)
input.each do |count, letter|
yield [letter, count]
end
end
def reduce(letter, partial_counts)
result = if partial_counts.size == 2
partial_counts[0] + partial_counts[1]
end
yield result
end
map
函数将yield
一对(letter, count)
,稍后将对其进行分组。然后,对于从letter
map
收到的每个reduce
,我们会收到一个数组,其中包含map
为letter
生成的每个计数。如果您希望仅在两个哈希值上都出现字母时,我们需要count
s出现在partial_counts
两次以使用它来计算结尾处的总和。 reduce
函数可以通过多种方式实现。我试图让它尽可能简单地理解,虽然它的实现非常适应这个问题。
使用这些map
和reduce
实现将返回带有键和值的最后一个哈希,这更有意义,因为可能有多个具有相同计数的字母。如果它反转键和值也会更好。这样,map
就像生成每对(letter, count)
:
def map(input)
input.each do |letter, count|
yield [letter, count]
end
end
或
def map(input)
input.each do |i|
yield i
end
end
答案 2 :(得分:2)
list_1 = ["3 - A", "4 - B", "5 - C", "7 - D", "8 - F"]
list_2 = ["2 - A", "8 - B", "6 - C", "9 - D", "4 - E"]
(list_1 + list_2).map do |str|
# change array of strings to array in the form of [[name, value], ...]
str =~ /(\d+) - (.*)/ && [$2, $1.to_i]
end.reduce({}) do |memo, obj|
# use a temporary Hash to sum up the values;
# the value is an array in the form of [value_counter, iteration_counter]
prev = memo[obj.first] || [0, 0]
memo[obj.first] = [prev.first + obj.last, prev.last + 1]
memo
end.map do |key, value|
# convert to array in original format or
# nil, if occurred only once
value.last > 1 ? "#{key} - #{value.first}" : nil
end.compact
=> ["A - 5", "B - 12", "C - 11", "D - 16"]
此代码使用Ruby的map
和reduce
方法,但直接在Hash上完成所有这些操作会更加优雅。
答案 3 :(得分:2)
使用irb(ruby-1.9.2-p180):
list = [ {a:2, b:1, d:3}, {a:3, b:2, c:3}, {a:4, b:1, c:3} ]
=> [{:a=>2, :b=>1, :d=>3}, {:a=>3, :b=>2, :c=>3}, {:a=>4, :b=>1, :c=>3}]
Hash[list.map(&:keys).inject(&:&).map{|key| [key,list.map{|arr| arr[key]}.inject(&:+)]}]
=> {:a=>9, :b=>4}
此解决方案适用于多个数组(2+),它可以找到常用键并将它们相加返回结果哈希值
找到公共密钥(收集密钥并查找公共部分):
list.map(&:keys).inject(&:&)
查找键的总和(按键选择值并求和):
list.map{|arr| arr[key]}.inject(&:+)]
从数组[[:a,9], [:b,4]]
:
results = [[:a,9], [:b,4]]
Hash[ results ]
我喜欢这款衬里的红宝石!