在Python中的Map reduce问题

3

我目前在努力完成一项任务。其解决方案将输入一个txt文件,并通过计算回文数及其频率来运行。我需要使用Map Reduce来实现。

例如:字符串"bab bab bab cab cac dad"会输出:

bab 3
cab 1
dad 1

这是我目前的内容

def palindrome(string):
    palindromes = []
    for word in string.split(" "):
        if (word == word[::-1]):
            palindromes.append(word)
    return palindromes 

string = "abc abd bab tab cab tat yay uaefdfdu"
print map(lambda x: palindrome(x), ["bab abc dab bab bab dad crap pap pap "])

当前打印

[['bab', 'bab', 'bab', 'dad', 'pap', 'pap', '']]

这是我目前在reduce部分的尝试。
def p(lists):
for list in lists:

set_h = set(list) 

return set_h

使用p函数,我想创建一个包含所有回文的集合。然后在列表上运行回文计数,并将其转换为字典。
print reduce(p, [['bab', 'bab', 'bab', 'dad', 'pap', 'pap', '']])

我是否在正确的轨道上?


这是“回文”……我纠正了拼写并清理了格式。 - Jim Garrison
应该使用“homework”标签来标记。 - a paid nerd
1
FYI,map(lambda x: palindrome(x), ...)是多余的。你可以很容易地使用map(palindrome, ...)并获得相同的结果。然而,你应该重新考虑一下你的palindrome()函数,使其一次只操作一个项目,并提前拆分输入。还要记住,在map和reduce步骤之间需要对结果进行排序。 - Austin Marshall
5个回答

3

如果你的map()reduce()输入是一个实际的单词列表,那么你会觉得操作更加容易。为了实现这个目标,在将字符串传递给map()之前,请使用.split()对其进行分割。然后,如果你的映射器遇到回文,则将单词映射到它本身,否则映射到None。接下来,你可以用filter()过滤掉None值,排序并将其传递给reduce()reduce()将把它缩小到将单词映射到它们的总计数的dict

我不会提供可工作的解决方案,以免影响学习因素。


基本上,map 函数将会检查列表中的任何单词是否为回文。如果是,则将其添加到另一个列表中。palindrome = [] def palindromes(word): if (word == word[::-1]): palindrome.append(word) return palindromes map(palindromes, list_of_strings) - shenn
map() 的哲学是它只会一次传递一个标记给映射函数,而映射函数也应该只返回一个映射值。reduce() 同样适用这个原则——它只会逐个传递标记给 reductor。在 mapper / reductor 函数中,您不需要维护自己的列表。实际上,您也不需要 filter(),因为 reductor 可以检查 None 并忽略它。 - patrys

2

在映射之前,将您的字符串拆分为列表。 map() 适用于列表、集合和字典,不适用于字符串。

word_list = words_str.split(" ")

除非你的任务要求使用,否则避免使用 map-filter-reduceGVR 如此。正确的解决方案是使用Python的列表推导式语法。实际上,你可以用一个相当恶心的单行代码来完成它。
pal_count = {
    x: word_list.count(x)  # reduce-ish
    for x in word_list     # map-ish
    if x == x[::-1]        # filter-ish
    }
for x, y in pal_count.iteritems():
    print x, y             # print the results!

将其分解...
  1. 将其捕获在字典对象中以便稍后打印:pal_count = {
  2. 定义返回对象:x: word_list.count(x) 我们使用键值语法将回文串 x 与其出现次数相关联。 count() 就像列表的内置 reduce 函数。
  3. 使用 for 循环 遍历列表,将当前值分配给 'x':for x in word_list
  4. 我们只想返回回文串,因此我们添加比较运算符来筛选掉不好的值:if x == x[::-1] # cool logic, btw
  5. 万岁!}
顺便说一下,我只是帮你做作业,因为我从来没有做过我的作业。
更慢、不够灵活、不够便携、不够的等价物使用嵌套的 for 循环:
pal_count = dict()
for x in word_list:                     # same loop
    if x == x[::-1]                     # is this a palindrome?
        if x in pal_count:              # have we seen before?
            pal_count[x] += 1
        else:                           # this one is new!
            pal_count.setdefault(x, 1)

1
在标记为作业或任务的问题中提供完整的工作解决方案并不酷。不确定为什么您认为第二个版本较慢。在大型数据集上调用.count()并不是地球上最快的事情,特别是如果您为相同单词的每个出现都调用它。对于您的第二个示例,请使用pal_count.setdefault(x, 0),然后是pal_count[x] += 1pal_count[x] = pal_count.setdefault(x, 0) + 1 - patrys
@patrys 不好意思...我只是很兴奋自己能够回答问题;随时可以标记它。感谢你在 pal_count[x] = pal_count.setdefault(x, 0) + 1 上的提示 - 这是解决常见问题的非常酷的方法。 - Cody Hess
1
如果您使用的是现代(2.5+)版本的Python,您还可以使用:pal_count = defaultdict(int),然后只需pal_count[x] += 1 - patrys
哦,defaultdict!我在浏览文档时经常忽略它。现在你不能因为评论区有很多学习内容而标记我的答案了 :-p - Cody Hess

1

对于你的reduce函数,你应该从一个空字典开始,并更新/填充你的计数。Reduce函数需要2个参数,因此一个可以是你的字典,另一个可以是你的回文。你可以在reduce中像这样提供一个初始值:

reduce(lambda x, y: x+y, some_list, initial_value_for_x)

看一下 dict的get,了解如何设置默认值,这应该会帮助你大大简化reduce函数。


1

如果我们将问题分解为小挑战,那就非常简单。在我们的情况下,这可以是:

  1. 从单词列表中过滤出所有回文单词。
  2. 获取唯一的单词以查找计数。
  3. 将所有唯一的单词映射到它们适当的计数。

代码:

words =  "bab bab bab cab cac dad"
is_palindrome = lambda word : word == word[::-1]
palindromes = filter(is_palindrome,words.split(" "))
get_count = lambda word : (word , palindromes.count(word))
unique = set(palindromes)
dict(map(get_count,unique))
Out[1]: {'bab': 3, 'cac': 1, 'dad': 1}

这是简短的说明:

#Input:
    words =  "bab bab bab cab cac dad"

#Step 1: Filter out the palindromes.
    is_palindrome = lambda word : word == word[::-1]
    palindromes = filter(is_palindrome,words.split(" "))

#Step 2: Get the unique set of string to find their counts.
    unique = set(palindromes)

#Step 3: Map every unique palindrome to their respective count.
    get_count = lambda word : (word , palindromes.count(word))
    dict(map(get_count,unique))

#Output:
    Out[1]: {'bab': 3, 'cac': 1, 'dad': 1}
注意:在Python中,map函数可以接受任何序列,不仅限于列表、集合或字典。Python中的字符串也是序列,因此Cody Hess的说法不正确:map不能接受字符串。
为了演示这一点,这里有一个非常简单的示例:
In [10]: map(echo, "python")
Out[10]: ['p', 'y', 't', 'h', 'o', 'n']

0

对于Map/Reduce来说,使用Counter对象非常简单明了。

from collections import Counter 
words = "bab bab bab cab cac dad"
words_list = words.split(" ") 
cont = Counter()
for word in words_list:
    cont[word] += 1
print(cont)
# or if you want dict
print(dict(cont))

https://docs.python.org/3/library/collections.html


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接