Showing posts with label Python. Show all posts
Showing posts with label Python. Show all posts

August 25, 2007

用 Python 写了个背单词小工具

注:此“软件”已被作者开为 Google Code 项目 Rewords
背单词关键在于重复,单词能不能背得取决于你看了它多少遍。把一个单词表(wordlist)中的每个 list 分成许多个 section,反复地浏览记忆就能记住。基于此,昨晚我用 Python 写了一个背单词的小工具,暂定名 Rewords 。

#!/usr/bin/python
# Filename: rw.py

import sys

def locate (f, i, n = 1):
  if n == i:
    print f.readline()
    return f
  if f.readline() == "\n":
    return locate(f, i, n+1)
  return locate(f, i, n)

def struct (f, st = []):
  ln = f.readline()[:-1]
  if ln == "":
    return st
  return struct(f, st+[ln])

def conmat (ls, l, tmp = []):
  if len(tmp) == l:
    return [tmp]+conmat(ls, l)
  if len(ls) <= l and tmp == []:     return [ls]   return conmat(ls[1:], l, tmp+[ls[0]]) def inter (st):   '''usage: `Enter`
-
n : next word
p : prev word
d : down to next section
u : up to prev section
: jump to section
l : jump to list '''
  def term (rt, lt = [], n = 0, cur = 'n'):
    def help ():
      print inter.func_doc
      term(rt, lt, n, cur)

    def next ():
      if rt == []:
        term(lt , rt, n, 'n')
      print rt[0]
      term(rt[1:] , lt+[rt[0]], n, 'n')

    def prev ():
      if lt == []:
        term(lt , rt, n, 'p')
      print lt[-1]
      term([lt[-1]]+rt, lt[:-1], n, 'p')

    def down ():
      if n == len(st)-1:
        term(st[0], n=0)
      term(st[n+1], n = n+1)
  
    def up ():
      if n == 0:
        term(st[len(st)-1], n=len(st)-1)
      term(st[n-1], n = n-1)

    def to (p = 1):
      num = (p-1)%len(st)
      term(st[num], n = num)

    def err ():
      print " # unsupported command"
      term(rt, lt, n, cur)

    cmd = sys.stdin.readline()[:-1]
    if cmd == "q": quit()
    if cmd == "h": help()
    elif cmd == "":
      if cur == 'n': next()
      elif cur == 'p': prev()
    elif cmd == "n": next()
    elif cmd == "p": prev()
    elif cmd == "d": down()
    elif cmd == "u": up()
    elif cmd.isdigit(): to(int(cmd))
    elif cmd[0] == 'l' and cmd[1:].isdigit():
      start(int(cmd[1:]))
    else: err()
  term(st[0])

def quit (m = ""):
  if m:
    print m
    sys.exit(1)
  sys.exit(0)

def start (wl = 1):
  '''usage: python rw.py [list] [section]
The wordlist named must be separated by blank lines;
program will start with the [list] or first part of the wordlist;
the each section will contain [section] or 8 words. '''
  inter(conmat(struct(locate( \
    open(sys.argv[1] if len(sys.argv) > 1 \
      else quit(start.func_doc)), wl)), \
    int(sys.argv[3] if len(sys.argv) > 3 else 8)))

print "rw.py - Rewords 0.1a by lichray\n"
start(int(sys.argv[2] if len(sys.argv) > 2 else 1))

程序是自省的,用起来应该没问题。无参数运行 python rw.py 显示帮助。
参数1 是单词表文件名,这个文件需要被空行分解为多个 list,每个 list 的第一行是标题;
参数2 是启动时加载的 list 编号,默认为 1;
参数3 是每个 section 包含的单词数,默认为 8;
进入互交描述后参考帮助,输入 h 命令,回车。
我这儿有一个可用的单词表——Barron SAT 词表,但存在一个小 Bug,不知为什么这个词表只能加载前13个 list,想帮忙的人留个邮箱地址,我把东西都发过去。
另外 locate() 函数还不能处理 readline() 越界的情况,这部分没完成。
最后根据我的代码风格,猜猜看我最近什么语言用的比较多?

July 14, 2007

新人报到!

大家好,我叫B...不是不是,我姓叶,叫 B哥葉。我是氷の鋭 同班同学,他教我学 Python 几个月了,前天我终于第一次在仅有师父提示的情况下自己写出了一个程序,耶!
原题是这样的:

一个六位数,分别用2,3,4,5,6乘它,得到的五个新数仍是由原数中的六个数字组成,只是位置不同,则此六位数是多少?

我把这题给做出来了!

def pcb(i):
  if a(i)==a(i*2):
return pcb_3(i)

def pcb_3(i):
  if a(i)==a(i*3):
    return pcb_4(i)

def pcb_4(i):
  if a(i)==a(i*4):
    return pcb_5(i)

def pcb_5(i):
  if a(i)==a(i*5):
    return pcb_6(i)

def pcb_6(i):
  if a(i)==a(i*6):
    return i

def a(i):
  c=b(i)
  c.sort()
  return c

def b(i):
  return list(str(i))

# 这个原来我写的是错的,后来师父改滴——其实改滴也不好!
for i in range(100000,1000000):
  if i and pcb(i):
    print i
    break

师父在学校那台破电脑上输代码滴时候抱怨说我的程序可以用程序写唠。这有什么关系,反正我的代码的速度超过师父的啦!

def list_equ (ls):
  for cond in map(lambda x: ls[0] == x, ls):
    if not cond:
      return False
    return True

def sort (ls):
  ls.sort()
  return ls

def test_num (num):
  return list_equ(map(lambda x: reduce( \
    lambda i,j: i+j, sort(list(str(x * num)))), range(2,7)))

def give_rst ():
  return filter(test_num, range(100000,1000000))

for i in range(100000,100000):
  if (test_num(i)):
      print i

但是,最后师父使出了杀手锏,把这题用数学方法解出来唠,他个DB。。。
以后一定要超过他!

September 21, 2006

《称球问题》的完整代码

晕死,上次发的那篇文章居然忘了给代码。现在把它贴出来,顺便加点注释。
(最近拼命写Lua数据结构实现中...)

#metga.py
#useage: python metga.py datefile
import sys
import string

#比较结果代码(左盘?右盘)
HEAVY = 1
LIGHT = -1
EQUAL = 0
QUESTION = 0 #问题球的问题
ANSWER = ""

#球的数据结构
class Ball:
def __init__ (self, weight):
self.weight = weight
self.number = 0

#求总质量
def sum (balls):
tmp = 0
for ball in balls:
tmp += ball.weight
return tmp

#天平函数,计算左右盘质量返回比较结果
def metage (leftBalls, rightBalls):
left = sum(leftBalls)
right = sum(rightBalls)
if left > right: return HEAVY
if left < style="color: rgb(51, 51, 255);">return LIGHT
return EQUAL

#对球进行预处理,判断问题球是轻是重
def pre (balls):
global QUESTION
n = len(balls) / 3
parts = [balls[:n], balls[n:2*n], balls[2*n:3*n]]
statu = metage(parts[0], parts[1])
if statu == EQUAL:
QUESTION = metage(parts[2], parts[0])
return balls[2*n:]
QUESTION = statu
if metage(parts[0], parts[2]) == EQUAL:
return parts[1]
else:
return parts[0]

#递归地分3片称球
def test (balls):
l = len(balls)
if l == 1:
return balls[0].number
n = l / 3
if l < n =" 1" parts =" [balls[:n]," statu =" metage(parts[0]," style="color: rgb(51, 51, 255);">if statu == EQUAL:
return test(balls[2*n:])
elif statu == QUESTION:
return test(balls[:n])
else:
return test(balls[n:2*n])

#读取数据文件(内容为n个数字,每个一行,其中有一个与其它不等)
weight_list = map(string.atoi, open(sys.argv[1]).readlines())
ball_list = map(Ball, weight_list) #创建球组成的list
i = 1
for ball in ball_list: #初始化下标
ball.number = i
i += 1
if QUESTION == 1:
ANSWER = "heavier"
else:
ANSWER = "lighter"
print "The No.%d ball is %s than others." % (test(pre(ball_list)), ANSWER)

可恶的Blogger对于程序的排版支持约等于无,忙死我了。等我学完编译原理,我一定要开发一个JavaScript实现的词法分析器!

September 18, 2006

找到的一个八皇后问题Python版解法

原文称参考了All Start From A Game
觉得有参考价值,虽然好像还不够快和简洁。以后我来自己写一个递归版的罢。
排版了一下,加了点注释。

size = 8 # 棋盘大小
EMPTY = "O" # 空位
QUEEN = "X" # 皇后

# 查看棋盘的信息
def show_board(cols):
for i in range(size):
for j in range(size):
if j == int(cols[i]) - 1:
print QUEEN,
else:
print EMPTY,
print "\n",

# 检测棋盘上皇后摆法是否合法
# return:
# True(不冲突), False(有冲突)
def check_board(cols):
for i in range(size - 1):
for j in range(i + 1, size):
if j - i == abs(int(cols[j]) - int(cols[i])):
return False
return True

# 得到全排列
def permute(seq):
seqn = [ seq.pop() ]
while seq:
newseq = []
new = seq.pop()
#print "seq:",seq,'seqn', seqn ,'new', new
for i in range(len(seqn)):
item = seqn[i]
for j in range(len(item)+1):
newseq.append(
''.join([item[:j],new,item[j:]]))
seqn = newseq
#print 'newseq',newseq
return seqn

#测试代码
if __name__ == "__main__":
solve_count = 0
numbers =
''.join([str(i) for i in range(1, size + 1)])

for x in permute(list(numbers)):
y = list(x)
if check_board(y):
solve_count += 1
show_board(y)
print "\n",

print "found %i solves." % solve_count

September 16, 2006

《称球问题》的 python 版解答

《程序员》杂志第8期上讲解了这样一个问题:在N个球中,有一个球重量与其他球重不同(偏重或偏轻),在没有砝码的天平上进行k(N<=(3^k-1)/2)次称量,得到这个球的编号,并判断它比其它球轻或重。

《程序员》上使用了将球分为0~n-1,n~2n-1,2n~N-1(n=(N%3)?(N/3+1):(N/3))两两递归比较的方法。但由于在整个比较过程中,这个球到底偏轻还是偏重一直没有确定而进行了多次无效的比较,而且使用C++描述,对于这个需要大量出来数组的算法来说十分繁琐。我采用了支持函数式编程的Python语言优化了这个算法,脚本和测试用数据文件(举例)在附件中有下载。

主要思想与《程序员》中的类似,不过对球的列表的分片有所不同:
parts = [balls[:n], balls[n:2*n], balls[2*n:3*n]]
保证3片球数相同。确定是那一片出了问题后返回它时,最后一片由于可能不是balls[2*n:3*n](len(balls)%3!=0),所以返回balls[2*n:]。

球包括号码和质量两个属性,类定义如下:
class Ball:
def __init__ (self, weight):
self.weight = weight
self.number = 0
(注:number的默认值0是无效的,号码从1开始)
sum()用于给质量求和:
def sum (balls):
tmp = 0
for ball in balls:
tmp += ball.weight
return tmp
天平函数,返回比较结果——HEAVY = 1,LIGHT = -1,EQUAL = 0:
def metage (leftBalls, rightBalls):
left = sum(leftBalls)
right = sum(rightBalls)
if left > right: return HEAVY
if left < right: return LIGHT
return EQUAL

用全局变量QUESTION保存问题球是轻是重,这由预测量函数pre()给出,它工作后还返回有问题的分片。这样test()函数在工作时可以少一半比较次数。

test函数递归调用自身,可以采用折半比较的方式。但那样会提供算法的时间复杂度。假设n个质量数据求和要进行n次运算,折3片比较共需p=2*(x/3+x/3^2+...x/3^(N-1))次运算,化简得p=x-x/3^n,即求和运算次数不会大于球总个数。而折半比较则需(2^(N+1)-1)x(不准)次运算,明显多于使用分3片比较。

具体比较的条件详见代码,自行阅读。

最后解释一下数据文件的读入情况。数据文件是普通文本文件,每行一个数字,其中一个与其它不同。open(sys.argv[1]).readlines()返回一个由每行的字符串构成的列表,weight_list = map(string.atoi, open(sys.argv[1]).readlines())对这个列表中的每一项进行转数字操作并存入weight_list。ball_list = map(Ball, weight_list)把表中每一项创建Ball对象,最后test(pre(ball_list)计算返回球的编号。

关于python的函数式编程请初学者自己参考教材理解。感谢网友孔辉GID2257990(Lava-Lava平台)在程序调试方面给予的帮助。