百姓网的面试题

原题在这里百姓网公开笔试题:查询条件的子集判断,这道题在5月份的时候就看到了,一直想做,中间学习python,断断续续知道今天才发布出来:(,不过也算自己干完了一件事。测试代码直接使用了赖总的

1 # -*-coding:utf-8-*-
2  
3 class BTree:
4 def __init__(self, data):
5 self.l = None
6 self.r = None
7 self.data = data
8
9 def insertl(self, ltree):
10 self.l = ltree
11
12 def insertr(self, rtree):
13 self.r = rtree
14
15 def printTree(self, indent):
16 if isa(self.data, str):
17 print indent + self.data
18 else:
19 l, op, r = self.data
20 print indent + op,l,r
21
22
23 # BNF语法树解析
24 # Compare = > | < | =
25 # Atom = Field Compare Number
26 # SubSet = Atom|(Exp)*
27 # Factor = SubSet(and SubSet)*
28 # Exp = Factor(or Factor)*
29 isa = isinstance
30 conjunction = ['and', 'or']
31 compare = ['>', '<', '=']
32 keyword = ['and', 'or', '>', '<', '=']
33
34 def atom(token):
35 try: return int(token)
36 except ValueError:
37 try: return float(token)
38 except ValueError:
39 return str(token)
40
41 def getNumber(num):
42 if isa(num, str):
43 raise SyntaxError('should be number')
44 elif isa(num, list):
45 raise SyntaxError('should be number string')
46 else:
47 return num
48
49 def getField(field):
50 if isa(field, str):
51 if field in keyword:
52 raise SyntaxError('field should not be keyword')
53 else:
54 return field
55 else:
56 raise SyntaxError('field should not be number')
57
58 def getCompare(string):
59 if isa(string, str):
60 if string in compare:
61 return string
62 else:
63 raise SyntaxError('should be compare word')
64 else:
65 raise SyntaxError('should be compare string')
66
67 def getAtom(strSQL):
68 if len(strSQL) < 3:
69 raise SyntaxError('should be leng')
70 atom = strSQL.pop(0)
71 field = getField(atom)
72
73 atom = strSQL.pop(0)
74 compare = getCompare(atom)
75
76 atom = strSQL.pop(0)
77 num = getNumber(atom)
78
79 L = []
80 L.append(field)
81 L.append(compare)
82 L.append(num)
83 subset = BTree(L)
84 return subset
85
86 def getSubSet(strSQL):
87 if isa(strSQL[0], str):
88 return getAtom(strSQL)
89 else:
90 atom = strSQL.pop(0)
91 return getExp(atom)
92
93 def getFactor(strSQL):
94 factor = getSubSet(strSQL)
95 while(len(strSQL) > 0):
96 op = strSQL.pop(0)
97 if op == 'and':
98 atom = getSubSet(strSQL)
99 else:
100 strSQL.insert(0, op)
101 break
102 factorOP = BTree(op)
103 factorOP.insertl(factor)
104 factorOP.insertr(atom)
105 factor = factorOP
106 return factor
107
108 def getExp(strSQL):
109 exp = getFactor(strSQL)
110 while(len(strSQL) > 0):
111 op = strSQL.pop(0)
112 if op == 'or':
113 factor = getFactor(strSQL)
114 else:
115 raise SyntaxError('keyword should be or')
116 break
117 expOP = BTree(op)
118 expOP.insertl(exp)
119 expOP.insertr(factor)
120 exp = expOP
121 return exp
122
123 ##########################
124 #解析SQL字符串,得到语法树
125 ##########################
126 def tokenize(s):
127 for key in compare:
128 s = s.replace(key, ' '+key+' ')
129 return s.replace('(', ' ( ').replace(')', ' ) ').split()
130
131 def read_fromPart(s):
132 L = []
133 while len(s) > 0:
134 ch = s.pop(0)
135 if ch == ')':
136 return L
137 elif ch == '(':
138 L.append(getPart(s))
139 else:
140 L.append(atom(ch))
141 if ch != ')':
142 raise SyntaxError('unexpcted ) part')
143 return L
144
145 def read_from(s):
146 L = []
147 while len(s) > 0:
148 ch = s.pop(0)
149 if ch == ')':
150 raise SyntaxError('unexpcted )')
151 return L
152 elif ch == '(':
153 L.append(read_fromPart(s))
154 else:
155 L.append(atom(ch))
156
157 return L
158
159 def read(s):
160 return read_from(tokenize(s))
161
162 #得到语法树
163 def pharse(stringExp):
164 strSQL = read(stringExp)
165 exp = getExp(strSQL)
166 return exp
167
168 ##########################
169 #输出表达式
170 ##########################
171 INDENT = ' '
172 def outputExp(exp, indent):
173 if exp.data:
174 exp.printTree(indent)
175 if exp.l:
176 outputExp(exp.l, indent+INDENT)
177 if exp.r:
178 outputExp(exp.r, indent+INDENT)
179
180 def addtowlist(l, r):
181 result = []
182 for subsetl in l:
183 for subsetr in r:
184 for atom in subsetr:
185 subsetl.append(atom)
186 result.append(subsetl)
187 return result
188
189 ##########################
190 #处理SQL表达式
191 #将(A<10 OR A>20) AND (B<10 OR B>20)
192 #变换成为:
193 #(A<10 AND B<10) OR (A<10 AND B>20) OR (A>20 AND B<10) OR (A>20 AND B>20)
194 ##########################
195 def normalizeExp(exp):
196 if not exp.l:
197 return [[exp.data]]
198 l = normalizeExp(exp.l)
199 r = normalizeExp(exp.r)
200 op = exp.data
201 result = []
202 if op == 'and':
203 result = addtowlist(l, r)
204 elif op == 'or':
205 for subsetl in l:
206 result.append(subsetl)
207 for subsetr in r:
208 result.append(subsetr)
209 return result
210
211 ##########################
212 #判断是否为子集
213 ##########################
214 def is_subset_atom_atom (left, right):
215 assert left and right
216 ll, lop, lr = left
217 rl, rop, rr = right
218 assert lop in compare and rop in compare
219 if ll != rl:
220 return False
221 if lop == rop == '>':
222 return lr >= rr
223 elif lop == rop == '<':
224 return lr <= rr
225 elif lop == rop == '=':
226 return lr == rr
227 elif lop == '>':
228 return False
229 elif lop == '<':
230 return False
231 elif lop == '=':
232 if rop == '>':
233 return lr > rr
234 elif rop == '<':
235 return lr < rr
236 else:
237 raise RuntimeError('Error ')
238
239 def get_sub_field(subset):
240 L = []
241 for x in subset:
242 l, op, r = x
243 if len(L) == 0:
244 L.append(l)
245 elif l not in L:
246 L.append(l)
247 return L
248
249 #判断and子式的关系
250 def is_subset_sub(left, right):
251 assert left and right
252 fieldL = get_sub_field(left)
253 fieldR = get_sub_field(right)
254
255 for x in fieldR:
256 if x not in fieldL:
257 return False #age>10 不是 age>10 and weight>100的子集
258 b = False
259 if len(fieldR) == len(fieldL):
260 b = True
261
262 if b:
263 #对于 age>10 and weight>10 和 age>20 and weight>20的子集
264 #必须左子式的每个原子条件都是右子式任一原子条件的子集
265 for atoml in left:
266 bSubset = False
267 for atomr in right:
268 bSubset = is_subset_atom_atom(atoml, atomr)
269 if bSubset == True:
270 break
271 if bSubset == False:
272 return False
273 return True
274 else:
275 #对于 age>10和 age>20 and weight>20的子集
276 #只要左子式的有原子条件都是右子式任一原子条件的子集,则左子式为右子式的子集
277 for atoml in left:
278 bSubset = False
279 for atomr in right:
280 bSubset = is_subset_atom_atom(atoml, atomr)
281 if bSubset == True:
282 return True
283 return False
284
285 def is_subset_exp(left, right):
286 assert left and right
287 for subl in left:
288 b = False
289 for subr in right:
290 b = is_subset_sub(subl, subr)
291 if b == True:
292 break
293 if b == False:
294 return False
295
296 return True
297
298 class Query(object):
299 def __init__(self, q):
300 self._q = q
301 self._tree = normalizeExp(pharse(q))
302 assert self._tree
303
304 def is_subset(self, other):
305 if not self._tree:
306 return False
307 if not other._tree:
308 return True
309 return is_subset_exp(self._tree, other._tree)
310
311
312 if __name__ == '__main__':
313 t0 = Query('age > 40') # 中年人
314 t1 = Query('age > 18') # 成年人
315 print t0.is_subset(t0)
316 print t0.is_subset(t1)
317 print t1.is_subset(t0)
318 print t1.is_subset(t1)
319 print '- '*30
320
321 t2 = Query('age > 18 and weight < 100 ') # 成年瘦子
322 t3 = Query('age > 18 or weight < 100 ') # 成年人,或体重小于 100
323 print t0.is_subset(t2)
324 print t0.is_subset(t3)
325
326 print t2.is_subset(t0)
327 print t2.is_subset(t3)
328
329 print t3.is_subset(t2)
330
331 r0 = Query('age > 30 and sex = 0 ')
332 r1 = Query('age > 40 and sex = 0 ')
333
334 print r0.is_subset(r1)
335 print r1.is_subset(r0)
336 print '= '*30
337
338 t0 = Query('(age < 15 and sex = 0) or age > 30')
339 t1 = Query('age < 7 ')
340 t2 = Query('age < 18 ')
341
342 print '* '*30
343 assert 't0 is subset of t0: ' and t0.is_subset(t0) == True
344 print '- '*30
345 assert 't0 is subset of t1: ' and t0.is_subset(t1) == False
346 print '- '*30
347 assert 't1 is subset of t0: ' and t1.is_subset(t0) == False
348 print '- '*30
349 assert 't2 is subset of t0: ' and t2.is_subset(t0) == False
350 print '- '*30
351
352 q0 = Query('age < 15 ')
353 q1 = Query('age > 30 ')
354 q2 = Query('age > 18 ')
355 q3 = Query('age > 40 ')
356 q4 = Query('age > 30 and sex = 0 ')
357
358
359 assert 'q0 is subset of q0: ' and q0.is_subset(q0) == True
360 print '- '*30
361 assert 'q0 is subset of q1: ' and q0.is_subset(q1) == False
362 print '- '*30
363 assert 'q0 is subset of q2: ' and q0.is_subset(q2) == False
364 print '- '*30
365 assert 'q0 is subset of q3: ' and q0.is_subset(q3) == False
366 print '- '*30
367 assert 'q0 is subset of q4: ' and q0.is_subset(q4) == False
368 print '- '*30
369 print
370
371 assert 'q1 is subset of q0: ' and q1.is_subset(q0) == False
372 print '- '*30
373 assert 'q1 is subset of q1: ' and q1.is_subset(q1) == True
374 print '- '*30
375 assert 'q1 is subset of q2: ' and q1.is_subset(q2) == True
376 print '- '*30
377 assert 'q1 is subset of q3: ' and q1.is_subset(q3) == False
378 print '- '*30
379 assert 'q1 is subset of q4: ' and q1.is_subset(q4) == False
380 print '- '*30
381 print
382
383 assert 'q2 is subset of q0: ' and q2.is_subset(q0) == False
384 print '- '*30
385 assert 'q2 is subset of q1: ' and q2.is_subset(q1) == False
386 print '- '*30
387 assert 'q2 is subset of q2: ' and q2.is_subset(q2) == True
388 print '- '*30
389 assert 'q2 is subset of q3: ' and q2.is_subset(q3) == False
390 print '- '*30
391 assert 'q2 is subset of q4: ' and q2.is_subset(q4) == False
392 print '- '*30
393 print
394
395 assert 'q3 is subset of q0: ' and q3.is_subset(q0) == False
396 print '- '*30
397 assert 'q3 is subset of q1: ' and q3.is_subset(q1) == True
398 print '- '*30
399 assert 'q3 is subset of q2: ' and q3.is_subset(q2) == True
400 print '- '*30
401 assert 'q3 is subset of q3: ' and q3.is_subset(q3) == True
402 print '- '*30
403 assert 'q3 is subset of q4: ' and q3.is_subset(q4) == False
404 print '- '*30
405 print
406
407 assert 'q4 is subset of q0: ' and q4.is_subset(q0) == False
408 print '- '*30
409 assert 'q4 is subset of q1: ' and q4.is_subset(q1) == True
410 print '- '*30
411 assert 'q4 is subset of q2: ' and q4.is_subset(q2) == True
412 print '- '*30
413 assert 'q4 is subset of q3: ' and q4.is_subset(q3) == False
414 print '- '*30
415 assert 'q4 is subset of q4: ' and q4.is_subset(q4) == True
416 print '- '*30
417

 

[参考]

百姓网那道题

2 《百姓网公开笔试题:查询条件的子集判断》的一份PHP答卷

3 从离散数学到编译原理--百姓网编程题后序

4 (How to Write a (Lisp) Interpreter (in Python))

posted on 2010-11-29 21:40  wuzy  阅读(1162)  评论(1编辑  收藏  举报

导航