Chinaunix首页 | 论坛 | 博客
  • 博客访问: 379531
  • 博文数量: 73
  • 博客积分: 3574
  • 博客等级: 中校
  • 技术积分: 1503
  • 用 户 组: 普通用户
  • 注册时间: 2010-03-26 11:17
文章分类

全部博文(73)

文章存档

2012年(14)

2011年(15)

2010年(44)

分类: Python/Ruby

2012-07-22 22:58:26

    其实是在为了写上一篇blog,在网上搜索python groupby关键字搜索到的一篇文章,是《深入Python 3》中高级迭代器中的一章,文章通过一个python解字母算术的示例代码对其中的关键特性进行了分析,不过原代码时基于python 3的,我这里的环境是python 2.7,于是就比照原代码做了一些修改。
  
    原文章地址:

    首先,介绍下什么是字母算术:

点击(此处)折叠或打开

  1. HAWAII + IDAHO + IOWA + OHIO == STATES
  2. 510199 + 98153 + 9301 + 3593 == 621246

  3. '''像这样的谜题被称为字母算术,把每一个字母都用0-9中的某一个数字替换后,同样可以拼出一个算术等式'''
  4. H = 5
  5. A = 1
  6. W = 0
  7. I = 9
  8. D = 8
  9. O = 3
  10. S = 6
  11. T = 2
  12. E = 4
    对于求解这样的难题,可以通过仅仅十多行的python代码实现,先把修改后的最终代码放上来:

点击(此处)折叠或打开

  1. #!/usr/bin/env python
  2. import re
  3. import itertools
  4. import string

  5. def solve(puzzle):
  6.     words = re.findall('[A-Z]+', puzzle.upper())
  7.     unique_characters = set(''.join(words))

  8.     assert len(unique_characters) <= 10, 'Too many letters'
  9.     #first_letters = {word[0] for word in words}
  10.     first_letters = [word[0] for word in words]
  11.     n = len(first_letters)
  12.     sorted_characters = ''.join(first_letters) + \
  13.         ''.join(unique_characters - set(first_letters))

  14.     #characters = tuple(ord(c) for c in sorted_characters)
  15.     #digits = tuple(ord(c) for c in '0123456789')
  16.     characters = sorted_characters
  17.     digits = '0123456789'

  18.     zero = digits[0]
  19.     for guess in itertools.permutations(digits, len(characters)):
  20. #前n个为首字母,保证非0
  21.         if zero not in guess[:n]:
  22.             numbers = ''.join(guess)
  23.             table = string.maketrans(characters,numbers)
  24.             #equation = puzzle.translate(dict(zip(characters, guess)))
  25.             equation = puzzle.translate(table)
  26.             if eval(equation):
  27.                 return equation

  28. if __name__ == '__main__':
  29.     import sys
  30.     for puzzle in sys.argv[1:]:
  31.         print(puzzle)
  32.         solution = solve(puzzle)
  33.         if solution:
  34.             print(solution)
    测试用例:

点击(此处)折叠或打开

  1. $ python puzz.py 'I + LOVE + YOU == DORA'
  2. I + LOVE + YOU == DORA
  3. 1 + 2784 + 975 == 37 

点击(此处)折叠或打开

  1. Lyn@HOME ~/python
  2. $ python puzz.py 'SEND + MORE == MONEY'
  3. SEND + MORE == MONEY
  4. 9567 + 1085 == 10652

  5. Lyn@HOME ~/python
  6. $ python puzz.py 'HAWAII + IDAHO + IOWA + OHIO == STATES'
  7. HAWAII + IDAHO + IOWA + OHIO == STATES
  8. 510199 + 98153 + 9301 + 3593 == 621246
    注:既然是最简单的实现,那么必然方法不可能是最优,这段python代码的实现也就是基于穷举法进行的测试,那么运行时间必然不那么让人满意。
    
    python代码逻辑如下:
1、通过re.findall()函数找到谜题中的所有字母
2、使用集合和set()函数找到谜题中出现的所有不同字母
3、通过assert语句检查是否超过10个不同的字母
4、通过itertools.permutations()函数计算所有可能的解法
5、构建trans table,并使用translate()字符串方法将所有可能的解转换成python表达式
6、使用eval()函数通过求值python表达式来检验解法
7、返回第一个求值结果为True的解法

   这其中比较新颖的用法有两个,一个是itertools.permutations方法,一个是string的translage方法。
1、itertools.permutations()
   这是python中计算排列的一种简单方法,当有一个列表,接着需要将它们拆开然后组合成小一点的列表的所有可能,所有的小列表的大小必须一致。最小是1,最大是元素的总数目,并且不能有重复。这个时候,我们就可以使用permutations()方法
   举个例子:

点击(此处)折叠或打开

  1. >>> import itertools
  2. >>> perms = itertools.permutations([1, 2, 3], 2)
  3. >>> next(perms)
  4. (1, 2)
  5. >>> next(perms)
  6. (1, 3)
  7. >>> next(perms)
  8. (2, 1)
  9. >>> next(perms)
  10. (2, 3)
  11. >>> next(perms)
  12. (3, 1)
  13. >>> next(perms)
  14. (3, 2)
  15. >>> next(perms)
  16. Traceback (most recent call last):
  17.   File "", line 1, in <module>
  18. StopIteration
    permutations()函数接受一个序列(列表、深圳字符串)和一个表示要排列的元素的数目的数字,函数返回迭代器,可以在需要的时候遍历使用
    在permutations()的返回序列中,(2,1)和(1,2)是不同的;但在itertools.combinations函数(同样用于返回序列给定长度的所有组合的迭代器)中,(1,2)和(2,1)不会同时返回,因为它认为这两个序列只是顺序不同而已。

2、string.translate
    字符串的翻译从一个转换表开始,通过转换表将一个字符映射到另一个字符,在Python2.7中的使用跟Python3不太一样,首先看下示例:

点击(此处)折叠或打开

  1. import string
  2. '''Python 2.7'''
  3. table = string.maketrans('A','0')
  4. print 'MAKE'.translate(table)

  5. output:
  6. MOKE

  7. '''对于多个转换'''
  8. table = string.maketrans('AB','OZ')
  9. print 'MABKE'.translate(table)

  10. output:
  11. MOZKE

  12. '''Python3'''
  13. print 'MABKE'.translate({'A':'0','B':'Z'})

  14. output
  15. MOZKE
    在2.7版本中,使用translate方法之前首先需要手动构建转换表,string.maketrans(from,to)接收两个字符串参数,这两个字符串确定转换关系,转换时根据字符串中字符的index进行对应的匹配;string.translate(table[,deletechars])以上面生成的trans table作为参数完成最终的动作
    在3版本中,可以直接使用dict作为参数完成translate动作,从个人感觉来说,3.0的方法更符合逻辑一些。

    理解了这两个主要的函数,那整个逻辑也就差不多清晰了,按照上文提供的大纲理解上面那段代码应该没什么问题了。
阅读(2835) | 评论(0) | 转发(0) |
0

上一篇:一个python小功能

下一篇:创建python的C扩展

给主人留下些什么吧!~~