Displaying a tree in ASCII - python

As a time-pass activity, I decided to implement a Tree(like) structure in python.
I implemented a Node class (which alone serves the purpose here) like so:
class Node:
def __init__(self, name, parent, *data):
self.name = name
self.parent = parent
self.data = data
self.children = []
self.is_root = False
def __repr__(self):
return 'Node '+repr(self.name)
def dic(self):
retval = {self:[]}
for i in self.children:
retval[self].append(i.dic())
return retval
def display(self): # Here
pass
def has_children(self):
return bool(self.children)
def get_parent(self):
return self.parent
def add_child(self, name, *data):
child = Node(name, self,*data)
self.children.append(child)
return child
As you can see the display function is not implemented.
Here's an example tree.
A = Node('A',Node)
A.is_root = True
B = A.add_child('B')
D = B.add_child('D')
C = A.add_child('C')
E = C.add_child('E')
F = C.add_child('F')
G = C.add_child('G')
Here's some sample output for display.
>>> A.display()
A
+-^-+
B C
| +-+-+
D E F G
>>> C.display()
C
+-+-+
E F G
In the shortest form,
How can I "build" an ASCII tree (like above) from the Node class??
In a longer form,
The "Logic" of printing is:
When there is only one child, | is put above the child. (D)
Else, Every child has a + above it, (B,C,E,F)
When there are even no. of children, ^ is put below the parent. (A)
Else, (there are odd no. of children) + is put below the parent. (C)
I have been thinking of starting from below.
I realized that there has to be a call to the each of the children, but have been unable to implement anything (of that sorts or otherwise) that gave anything close to it.

Here's a solution that covers most of what you're looking for.
Like any tree algorithm, recurse down the children of the tree, and combine results at each node. Here's the trick: display() returns a rectangle of text, for example:
aaaaaa
aaaaaa
aaaaaa
Most of the rectangle will be whitespace. Returning only rectangles of text makes it easy to combine results. We'll use the following two helper functions, one to measure block widths, and the other to combine blocks horizontally into larger blocks:
def block_width(block):
try:
return block.index('\n')
except ValueError:
return len(block)
def stack_str_blocks(blocks):
"""Takes a list of multiline strings, and stacks them horizontally.
For example, given 'aaa\naaa' and 'bbbb\nbbbb', it returns
'aaa bbbb\naaa bbbb'. As in:
'aaa + 'bbbb = 'aaa bbbb
aaa' bbbb' aaa bbbb'
Each block must be rectangular (all lines are the same length), but blocks
can be different sizes.
"""
builder = []
block_lens = [block_width(bl) for bl in blocks]
split_blocks = [bl.split('\n') for bl in blocks]
for line_list in itertools.izip_longest(*split_blocks, fillvalue=None):
for i, line in enumerate(line_list):
if line is None:
builder.append(' ' * block_lens[i])
else:
builder.append(line)
if i != len(line_list) - 1:
builder.append(' ') # Padding
builder.append('\n')
return ''.join(builder[:-1])
See where this is going? Children return a rectangle that displays themselves and their descendants, and each node will combine these rectangles into a larger rectangle that contains itself. The rest of the code just renders the dashes and pluses:
class Node:
def display(self): # Here
if not self.children:
return self.name
child_strs = [child.display() for child in self.children]
child_widths = [block_width(s) for s in child_strs]
# How wide is this block?
display_width = max(len(self.name),
sum(child_widths) + len(child_widths) - 1)
# Determines midpoints of child blocks
child_midpoints = []
child_end = 0
for width in child_widths:
child_midpoints.append(child_end + (width // 2))
child_end += width + 1
# Builds up the brace, using the child midpoints
brace_builder = []
for i in xrange(display_width):
if i < child_midpoints[0] or i > child_midpoints[-1]:
brace_builder.append(' ')
elif i in child_midpoints:
brace_builder.append('+')
else:
brace_builder.append('-')
brace = ''.join(brace_builder)
name_str = '{:^{}}'.format(self.name, display_width)
below = stack_str_blocks(child_strs)
return name_str + '\n' + brace + '\n' + below
# SNIP (your other methods)
And we're off to the races!
a
+-+-+---------------------------+
b e f g
+ +-+-------------------------+
c h i k
+ + +-+-+-+-------------+-------------+-+------+
d j l m p r s O P Q
+ + +-+-+-+---------+ +-----+
n q t u w x y R S
+ + +-------+-------+ +---+---+
o v z A M T U Z
+-+-+-+-+-+-+ + + +
B D E H I K L N V a
+ + + +-+-+ +
C F J W X Y b
+
G
(Requirements like "placing a ^ below the parent" are left as an exercise for the reader)

I'd like to suggest to take a look at ETE module http://ete.cgenomics.org which implements the functionality you describe here and much more.
At the same time, I'd like to provide this entry Pretty Print output in a sideways tree format in console window where a similar question has been asked before. As you can see in such discussion, the _asciiArt function from ETE provides what, I think, you are looking for.
I hope this helps,

Related

15 puzzle astar search that goes into an infinite loop

I am trying to develop a 15 star puzzle program in Python and its supposed to sort everything in numerical order using the a star search algorithm with the 0 being at the end.
Here is my a star algorithm I've developed so far:
"""Search the nodes with the lowest f scores first.
You specify the function f(node) that you want to minimize; for example,
if f is a heuristic estimate to the goal, then we have greedy best
first search; if f is node.depth then we have breadth-first search.
There is a subtlety: the line "f = memoize(f, 'f')" means that the f
values will be cached on the nodes as they are computed. So after doing
a best first search you can examine the f values of the path returned."""
def best_first_graph_search_manhattan(root_node):
start_time = time.time()
f = manhattan(root_node)
node = root_node
frontier = []
# how do we create this association?
heapq.heappush(frontier, node)
explored = set()
z = 0
while len(frontier) > 0:
node = heapq.heappop(frontier)
print(node.state.tiles)
explored.add(node)
if (goal_test(node.state.tiles)):
#print('In if statement')
path = find_path(node)
end_time = time.time()
z = z + f
return path, len(explored), z, (end_time - start_time)
for child in get_children(node):
# calcuate total cost
f_0 = manhattan(child)
z = z + f_0
print(z)
if child not in explored and child not in frontier:
#print('Pushing frontier and child')
heapq.heappush(frontier, child)
print('end of for loop')
return None
"""
Return the heuristic value for a given state using manhattan function
"""
def manhattan(node):
# Manhattan Heuristic Function
# x1, y1 = node.state.get_location()
# x2, y2 = self.goal
zero_location = node.state.tiles.index('0')
x1 = math.floor(zero_location / 4)
y1 = zero_location % 4
x2 = 3
y2 = 3
return abs(x2 - x1) + abs(y2 - y1)
"""
astar_search() is a best-first graph searching algortithim using equation f(n) = g(n) + h(n)
h is specified as...
"""
def astar_search_manhattan(root_node):
"""A* search is best-first graph search with f(n) = g(n)+h(n).
You need to specify the h function when you call astar_search, or
else in your Problem subclass."""
return best_first_graph_search_manhattan(root_node)
Here is the rest of my program. Assume that everything is working correctly in the following:
import random
import math
import time
import psutil
import heapq
#import utils.py
import os
import sys
from collections import deque
# This class defines the state of the problem in terms of board configuration
class Board:
def __init__(self,tiles):
self.size = int(math.sqrt(len(tiles))) # defining length/width of the board
self.tiles = tiles
#This function returns the resulting state from taking particular action from current state
def execute_action(self,action):
new_tiles = self.tiles[:]
empty_index = new_tiles.index('0')
if action=='l':
if empty_index%self.size>0:
new_tiles[empty_index-1],new_tiles[empty_index] = new_tiles[empty_index],new_tiles[empty_index-1]
if action=='r':
if empty_index%self.size<(self.size-1):
new_tiles[empty_index+1],new_tiles[empty_index] = new_tiles[empty_index],new_tiles[empty_index+1]
if action=='u':
if empty_index-self.size>=0:
new_tiles[empty_index-self.size],new_tiles[empty_index] = new_tiles[empty_index],new_tiles[empty_index-self.size]
if action=='d':
if empty_index+self.size < self.size*self.size:
new_tiles[empty_index+self.size],new_tiles[empty_index] = new_tiles[empty_index],new_tiles[empty_index+self.size]
return Board(new_tiles)
# This class defines the node on the search tree, consisting of state, parent and previous action
class Node:
def __init__(self,state,parent,action):
self.state = state
self.parent = parent
self.action = action
#self.initial = initial
#Returns string representation of the state
def __repr__(self):
return str(self.state.tiles)
#Comparing current node with other node. They are equal if states are equal
def __eq__(self,other):
return self.state.tiles == other.state.tiles
def __hash__(self):
return hash(self.state)
def __lt__(self, other):
return manhattan(self) < manhattan(other)
# Utility function to randomly generate 15-puzzle
def generate_puzzle(size):
numbers = list(range(size*size))
random.shuffle(numbers)
return Node(Board(numbers),None,None)
# This function returns the list of children obtained after simulating the actions on current node
def get_children(parent_node):
children = []
actions = ['l','r','u','d'] # left,right, up , down ; actions define direction of movement of empty tile
for action in actions:
child_state = parent_node.state.execute_action(action)
child_node = Node(child_state,parent_node,action)
children.append(child_node)
return children
# This function backtracks from current node to reach initial configuration. The list of actions would constitute a solution path
def find_path(node):
path = []
while(node.parent is not None):
path.append(node.action)
node = node.parent
path.reverse()
return path
# Main function accepting input from console , running iterative_deepening_search and showing output
def main():
global nodes_expanded
global path
global start_time
global cur_time
global end_time
nodes_expanded = 0
process = psutil.Process(os.getpid())
initial_memory = process.memory_info().rss / 1024.0
initial = str(input("initial configuration: "))
initial_list = initial.split(" ")
root = Node(Board(initial_list),None,None)
print(astar_search_manhattan(root))
final_memory = process.memory_info().rss / 1024.0
print('Directions: ', path)
print('Total Time: ', (end_time-start_time), ' seconds')
print('Total Memory: ',str(final_memory-initial_memory)+" KB")
print('Total Nodes Expanded: ', nodes_expanded)
# Utility function checking if current state is goal state or not
def goal_test(cur_tiles):
return cur_tiles == ['1','2','3','4','5','6','7','8','9','10','11','12','13','14','15','0']
if __name__=="__main__":main()
I've managed to narrow it down into my for loop in my best_first_graph_search_manhattan function and it appears that the infinite loop is caused if the if statement where its checking if child is not in explored and child is not in frontier. I'm unsure if its the way I'm calling my child function or the way I'm pushing frontier and child into my priority queue. I have imported heapq into my program and I've done extensive research where importing that function allows you to utilize priority queue into your program. Please don't mind other variables that are not used in my a star search.
Here is a test case: 1 0 3 4 5 2 6 8 9 10 7 11 13 14 15 12 | DRDRD
Thank you all very much for your help!

Counting word strokes while parsing Trie tree

I'm trying to solve the keyboard autocompletion problem described here.
The problem is to calculate how many keystrokes a word requires, given some dictionary and autocomplete rules. For example, for the dictionary:
data = ['hello', 'hell', 'heaven', 'goodbye']
We get the following results (please refer to the link above for further explanations):
{'hell': 2, 'heaven': 2, 'hello': 3, 'goodbye': 1}
Quick explanation: if the user types h, then e is autocompleted because all words starting with h also have e as second letter. Now if the user types in l, the other l is filled, giving 2 strokes for the word hell. Of course, hello would require one more stroke. Please, see the link above for more examples.
My Trie code is the following, and it works fine (taken from https://en.wikipedia.org/wiki/Trie). The Stack code is to parse the tree from root (see edit below):
class Stack(object):
def __init__(self, size):
self.data = [None]*size
self.i = 0
self.size = size
def pop(self):
if self.i == 0:
return None
item = self.data[self.i - 1]
self.i-= 1
return item
def push(self, item):
if self.i >= self.size:
return None
self.data[self.i] = item
self.i+= 1
return item
def __str__(self):
s = '# Stack contents #\n'
if self.i == 0:
return
for idx in range(self.i - 1, -1, -1):
s+= str(self.data[idx]) + '\n'
return s
class Trie(object):
def __init__(self, value, children):
self.value = value #char
self.children = children #{key, trie}
class PrefixTree(object):
def __init__(self, data):
self.root = Trie(None, {})
self.data = data
for w in data:
self.insert(w, w)
def insert(self, string, value):
node = self.root
i = 0
n = len(string)
while i < n:
if string[i] in node.children:
node = node.children[string[i]]
i = i + 1
else:
break
while i < n:
node.children[string[i]] = Trie(string[:i], {})
node = node.children[string[i]]
i = i + 1
node.value = value
def find(self, key):
node = self.root
for char in key:
if char in node.children:
node = node.children[char]
else:
return None
return node
I couldn't figure it out how to count the number of strokes:
data = ['hello', 'hell', 'heaven', 'goodbye']
tree = PrefixTree(data)
strokes = {w:1 for w in tree.data} #at least 1 stroke is necessary
And here's the code to parse the tree from the root:
stack = Stack(100)
stack.push((None, pf.root))
print 'Key\tChilds\tValue'
print '--'*25
strokes = {}
while stack.i > 0:
key, curr = stack.pop()
# if something:
#update strokes
print '%s\t%s\t%s' % (key, len(curr.children), curr.value)
for key, node in curr.children.items():
stack.push((key, node))
print strokes
Any idea or constructive comment would help, thanks!
Edit
Great answer by #SergiyKolesnikov. There's one small change that can be done in order to avoid the call to endsWith(). I just added a boolean field to the Trie class:
class Trie(object):
def __init__(self, value, children, eow):
self.value = value #char
self.children = children #{key, trie}
self.eow = eow # end of word
And at the end of insert():
def insert(self, string, value):
#...
node.value = value
node.eow = True
Then just replace curr.value.endswith('$'): with curr.eow. Thank you all!
The trie for your example can look like this
' '
| \
H G
| |
E O
| \ |
L A O
| | |
L$ V D
| | |
O E B
| |
N Y
|
E
What nodes in the trie can be seen as markers for user key strokes? There are two types of such nodes:
Inner nodes with more than one child, because the user has to choose among multiple alternatives.
Nodes that represent the last letter of a word, but are not leaves (marked with $), because the user has to type the next letter if the current word is not what is needed.
While traversing the trie recursively one counts how many of these marker nodes were encountered before the last letter of a word was reached. This count is the number of strokes needed for the word.
For the word "hell" it is two marker nodes: ' ' and E (2 strokes).
For the word "hello" it is three marker nodes: ' ', E, L$ (3 strokes).
And so on...
What needs to be changed in your implementation:
The end of a valid word needs to be marked in the tree, so that the second condition can be checked. Therefore, we change the last line of the PrefixTree.insert() method from
node.value = value
to
node.value = value + '$'
Now we add a stroke counter for each stack item (the last value in the triple pushed to the stack) and the checks that increase the counter:
stack = Stack(100)
stack.push((None, tree.root, 0)) # We start with stroke counter = 0
print('Key\tChilds\tValue')
print('--'*25)
strokes = {}
while stack.i > 0:
key, curr, stroke_counter = stack.pop()
if curr.value is not None and curr.value.endswith('$'):
# The end of a valid word is reached. Save the word and the corresponding stroke counter.
strokes[curr.value[:-1]] = stroke_counter
if len(curr.children) > 1:
# Condition 2 is true. Increase the stroke counter.
stroke_counter += 1
if curr.value is not None and curr.value.endswith('$') and len(curr.children) > 0:
# Condition 1 is true. Increase the stroke counter.
stroke_counter += 1
print('%s\t%s\t%s' % (key, len(curr.children), curr.value))
for key, node in curr.children.items():
stack.push((key, node, stroke_counter)) # Save the stroke counter
print(strokes)
Output:
Key Childs Value
--------------------------------------------------
None 2 None
h 1
e 2 h
a 1 he
v 1 hea
e 1 heav
n 0 heaven$
l 1 he
l 1 hell$
o 0 hello$
g 1
o 1 g
o 1 go
d 1 goo
b 1 good
y 1 goodb
e 0 goodbye$
{'heaven': 2, 'goodbye': 1, 'hell': 2, 'hello': 3}
While you go through your stack, you should keep a stroke counter for each node:
It begins at 0 for None.
If the current node has more than 2 children, the counter of the
children will be 1 more than the current counter.
If the current value is a valid word and has at least one child, the
counter of the child(ren) will be 1 more than the current counter.
For documentation purpose, here's my Ruby answer :
class Node
attr_reader :key, :children
attr_writer :final
def initialize(key, children = [])
#key = key
#children = children
#final = false
end
def final?
#final
end
end
class Trie
attr_reader :root
def initialize
#root = Node.new('')
end
def add(word)
node = root
word.each_char.each{|c|
next_node = node.children.find{|child| child.key == c}
if next_node then
node = next_node
else
next_node = Node.new(c)
node.children.push(next_node)
node = next_node
end
}
node.final = true
end
def count_strokes(node=root,word="",i=0)
word=word+node.key
strokes = {}
if node.final? then
strokes[word]=i
if node.children.size>0 then
i+=1
end
elsif node.children.size>1 then
i+=1
end
node.children.each{|c|
strokes.merge!(count_strokes(c, word, i))
}
strokes
end
end
data = ['hello', 'hell', 'heaven', 'goodbye']
trie = Trie.new
data.each do |word|
trie.add(word)
end
# File.readlines('/usr/share/dict/british-english').each{|line|
# trie.add line.strip
# }
puts trie.count_strokes
#=> {"hell"=>2, "hello"=>3, "heaven"=>2, "goodbye"=>1}
60 lines only, and it take less than 3 seconds for 100 000 words.

Optimize finding diameter of binary tree in Python

I'm wondering how I can optimally find the diameter (or longest path between any two leaf nodes) of a binary tree. I have the basic solution below, but the second solution requires passing pointers. How can I do something like this in Python?
def find_tree_diameter(node):
if node == None:
return 0
lheight = height(node.left)
rheight = height(node.right)
ldiameter = find_tree_diameter(node.left)
rdiameter = find_tree_diameter(node.right)
return max(lheight+rheight+1, ldiameter, rdiameter)
def find_tree_diameter_optimized(node, height):
lheight, rheight, ldiameter, rdiameter = 0, 0, 0, 0
if node == None:
# *height = 0;
return 0
ldiameter = diameterOpt(root.left, &lheight)
rdiameter = diameterOpt(root.right, &rheight)
# *height = max(lheight, rheight) + 1;
return max(lh + rh + 1, max(ldiameter, rdiameter));
Python supports multiple return values, so you don't need pointer arguments like in C or C++. Here's a translation of the code:
def diameter_height(node):
if node is None:
return 0, 0
ld, lh = diameter_height(node.left)
rd, rh = diameter_height(node.right)
return max(lh + rh + 1, ld, rd), 1 + max(lh, rh)
def find_tree_diameter(node):
d, _ = diameter_height(node)
return d
The function diameter_height returns the diameter and the height of the tree, and find_tree_diameter uses it to just compute the diameter (by discarding the height).
The function is O(n), no matter the shape of the tree. The original function is O(n^2) in the worst case when the tree is very unbalanced because of the repeated height calculations.
Simple Python 3 solution
def findDepth(root):
if root is None:
return 0
return 1 + max(findDepth(root.left), findDepth(root.right))
class Solution:
def diameterOfBinaryTree(self, root: TreeNode) -> int:
if root is None:
return 0
left = findDepth(root.left)
right = findDepth(root.right)
ldia = self.diameterOfBinaryTree(root.left)
rdia = self.diameterOfBinaryTree(root.right)
return max(left+right, max(ldia, rdia))

Assigning items to a dictionary of an object

The following code does not work.
def set_view_counts(self):
"""
Initializes the view counts for all of the Concept objects in the ConceptModel. See Concept for a
description of why this parameter is optional.
"""
for node in self.nodes():
p = PageviewsClient().article_views("en.wikipedia", [node.concept.replace(' ', '_')])
p = [p[key][node.concept.replace(' ', '_')] for key in p.keys()]
p = int(sum([daily_view_count for daily_view_count in p if daily_view_count])/len(p))
node.properties['view_count'] = p
When I check the contents of my node.properties dictionaries I find 4560, 4560, 4560, 4560.
The following code does.
def set_view_counts(self):
"""
Initializes the view counts for all of the Concept objects in the ConceptModel. See Concept for a
description of why this parameter is optional.
"""
for node in self.nodes():
p = PageviewsClient().article_views("en.wikipedia", [node.concept.replace(' ', '_')])
p = [p[key][node.concept.replace(' ', '_')] for key in p.keys()]
p = int(sum([daily_view_count for daily_view_count in p if daily_view_count])/len(p))
node.properties = p
When I check properties I find 11252, 7367, 3337, 4560.
What's going on here?
We would need to see more of your code, but I put some meat around your function, guessing what you could have written to reproduce your bug:
class Node:
def __init__(self, props={}):
self.properties = props
class G:
def __init__(self):
self.n = [Node(), Node(), Node(), Node()]
def nodes(self):
return self.n
def set_view_counts(self):
p = 0
for node in self.nodes():
node.properties['view_count'] = p
p = p + 1
def __repr__(self):
r = ''
for node in self.nodes():
r += node.properties.__repr__()
return r
g = G()
g.set_view_counts()
print g
With this, I get:
{'view_count': 3}{'view_count': 3}{'view_count': 3}{'view_count': 3}
This is because of the default value on the props parameter in Node.__init__. The same dict (the one used as the default value) is shared by all Nodes. Fix this by removing the default value.

How to print a line from a text file without a certain character

Not quite sure if this question is a duplicate, but it seems like it isn't, after searching for a fair while.
Let's say I have these lines of text in text file.
Q5) What is 1+1
A) = 1
B) = *2
C) = 0
D) = -342
E) = 121
The correct answer, B) = *2, is written with a * mark over the line. How would you print this line, but without the character, so the line would be printed like so:
Q5) What is 1+1
A) = 1
B) = 2
C) = 0
D) = -342
E) = 121
I am still new to Python, but I understand that:
print lines[3]
Would print the specific line. Yet I would like to know how to print a line, without a certain character.
Any help and explanation on the Coding, will be much appreciated. Thanks Guys.
EDIT:
Given this input:
Q1) What is 1*1?
A) = 0
B) = *1
C) = 2
D) = -1
Q2) What is 1-1?
A) = *0
B) = 1
C) = 2
D) = -1
Q3) What is 1/1?
A) = 0
B) = *1
C) = 2
D) = -1
Q4) What is 1%1?
A) = *0
B) = 1
C) = 2
D) = -1
Q5) What is 1+1?
A) = 1
B) = *2
C) = 0
D) = -342
E) = 121
There are many ways to tackle this. These are my first thoughts:
import re
def ask_user(answer):
user_ans = raw_input("> ").strip()
if user_ans == answer:
print "Correct!\n"
result = True
else:
print "Wrong!\n"
result = False
return result
question = None
with open('test.txt') as test:
for line in test:
if line[0] == 'Q':
if question:
ask_user(answer)
question = line
else:
m = re.match(r'(.*?)\*(\d+)', line)
if m:
line, answer = m.groups()
line = "%s%s\n" % (line,answer)
print line,
# Final question
ask_user(answer)
A * might appear in:
the question, e.g. Q5) What is 2*2 seems a likely possibility,
as a marker for the correct answer (as shown by OP),
elsewhere within an answer (a reasonable assumption)
Blind use of str.replace() on every line of the file is not practical as it will affect all line types possibly corrupting questions and answers.
Maybe a further assumption can be that when * is used to mark the correct answer it will always appear at the same location, i.e. one space after the equals sign, so this might be a better solution:
line = line.replace(') = *', ') = ', 1)
which will replace the first occurrence of ) = * with ) =. It is unlikely that the same sequence of characters would appear elsewhere.
If the whitespace is variable, e.g. tabs mixed with spaces or different numbers of spaces, you can turn to a regular expression like this:
import re
pattern = re.compile(r'([A-Z]\)\s+=\s+)\*(.*)$')
line = pattern.sub(r'\1\2', line)
You want to print lines without a certain character, right? Just iterate and replace:
for line in data:
print line.replace('*', '')
Assuming you do not have a * in your answer body, just do the following:
>>> questions = Question.from_file('your_file.here')
>>> print(questions[0])
Q5) What is 1+1
A) = 1
B) = 2
C) = 0
D) = -342
E) = 121
>>> print(questions[0].correct_answer)
B) = 2
Below you may find the definitions:
class Question(object):
def __init__(self, body):
super(Question, self).__init__()
self.body = body
self.answers = []
self.correct_answer = None
def add_answer(self, answer, is_correct=False):
self.answers.append(answer):
if is_correct:
self.correct_answer = answer
def __repr__(self):
result = self.body + '\n'
for answer in self.answers:
result += answer + '\n'
return result
#classmethod
def from_lines(cls, lines):
question = cls(lines[0])
for ans_line in lines[1:]:
body = ans_line
is_correct = False
if Answer.CORRECT_MARK in ans_line:
body = ans_line.replace(Answer.CORRECT_MARK, '')
is_correct = False
question.add_answer(Answer(body, question, is_correct))
#classmethod
def from_file(cls, filename):
questions = []
with open(filename) as q_file:
lines = q_file.readlines()
for i in range(0, len(lines), 6):
questions.append(cls.from_lines(lines[i:i+6]))
class Answer(object):
CORRECT_MARK = '*'
def __init__(self, body, question, is_correct=False):
super(Answer, self).__init__()
self.body = body
self.question = question
question.add_answer(self, is_correct)
def is_correct(self):
return self.question.correct_answer == self
def __repr__(self):
return self.body
you could read the file in for loop itself as the other user has done .By using strip function you can remove the unwanted trialing and leading edges
My code:
a=open("filename","r")
contents=a.readlines()
i=0
for content in contents:
print str.strip(content.replace("*",""))
print i
i=i+1

Categories

Resources