Class for database of recipes not working? [closed] - python

Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 1 year ago.
Improve this question
there are 3 files, and I moved a condensed database into one of the files so that I could just prove that the concept works.
the first file is called find_a_recipe.py which is the one that is run
[find_a_recipe.py]
from random import sample
from typing import List
from main import *
#from cfonts import render
## main logic for type ingredient mode
def type_mode():
print("Let's find the ingredient you are looking for...")
keep_choosing = True
recipes = recipe_list
ingredient_list = get_ingredient_list(recipe_list)
ingredients_sorted = quicksort(ingredient_list)
while keep_choosing:
ingredients = ingredient_filtering(ingredients_sorted)
recipes = filter_recipes(ingredients, recipes)
ingredient_list = get_ingredient_list(recipes)
ingredients_sorted = quicksort(ingredient_list)
print(f"\nWe have {len(recipes)} recipes with those ingredients.")
keep_choosing = bolean_test("Want to choose other ingredients?")
if len(recipes) > 5:
recipe_choice_list = sample(recipes, 5)
else:
recipe_choice_list = recipes
print("\nHere are a few suggestions! Choose one and good luck!")
chosen_recipe = choose_recipe(recipe_choice_list, "Ok! Just choose one of those!")
print(chosen_recipe)
## main logig for yes/no mode
def yes_no_mode():
pass
recipe_dictionary = [
{'id': '192281',
'name': 'southern butter mints',
'minutes': '15',
'steps': 'melt cream cheese and butter in large saucepan over low heat, etc',
'ingredients': ['cream cheese', 'butter']},
{'id': '15017',
'name': 'baked ricotta with parmesan and thyme',
'minutes': '70',
'steps': 'preheat oven to 150c, place the parmesan',
'ingredients': ['parmesan cheese', 'thyme leaves', 'chili flakes']},
{'id': '193618',
'name': 'spaghetti with italian sausage spinach and diced tomatoes',
'minutes': '60',
'steps': 'boil spaghetti until al dente',
'ingredients': ['spaghetti', 'sweet italian turkey sausage', 'diced tomatoes']}]
##Print Welcome message
title = "Find A Recipe"
title_message = """
Welcome to Find A Recipe, the Recipe suggestion app that will blow your...kitchen?!
"""
#print(render(title))
print(title_message)
##create Recipe instances from dictionary
recipe_list = []
print(recipe_dictionary)
for i in recipe_dictionary:
id = i ["id"]
print(id)
#id = Recipe(i, id)
#recipe_list.append(id)
## Get an input on suggestion mode
choose_mode = "Please, choose a suggestion mode:"
modes_list = ["Type an ingredient", "Yes or No"]
suggestion_mode = get_choice(modes_list, choose_mode)
# Based on suggestion mode, run suggestion logic
if suggestion_mode == modes_list[0]:
type_mode()
else:
yes_no_mode()
the second file holds all the logic [main.py]
#import recipe_dict
from recipes import Recipe
from math import inf
from random import randrange
# ingredient list function
def get_ingredient_list(recipes):
ingredient_list = []
for recipe in recipes:
for ingredient in recipe.ingredients:
if ingredient not in ingredient_list:
ingredient_list.append(ingredient)
return ingredient_list
# ingredient count function
def get_ingredient_count(recipes):
ingredient_count = {}
for recipe in recipes:
for ingredient in recipe.ingredients:
if ingredient not in ingredient_count.keys():
ingredient_count[ingredient] = 1
else:
ingredient_count[ingredient] += 1
return ingredient_count
# def recipe_by_ingredient function
def get_recipes_by_ingredient(recipes, ingredient):
recipes_by_ingredient = []
for recipe in recipes:
if ingredient in recipe.ingredients:
recipes_by_ingredient.append(recipe)
return recipes_by_ingredient
# ingredient for optimal subset function
def get_optimal_ingredient(recipes):
best_subset_possible = len(recipes) // 2
optimal_ing = ""
optimal_count = inf
ingredient_count = get_ingredient_count(recipes)
for ingredient, count in ingredient_count.items():
if abs(best_subset_possible - count) < abs(best_subset_possible - optimal_count):
optimal_ing = ingredient
optimal_count = count
return optimal_ing
# logic for getting user recipe choice
def choose_recipe(choices, input_text):
count = 0
for choice in choices:
count += 1
print(f"{count}) {choice.name}\n")
choice_range = [f"{num}" for num in range(1, count + 1)]
user_choice = input(input_text)
if user_choice not in choice_range:
print(f"invalid input: please choose from 1 to {count}")
choose_recipe(choices, input_text)
else:
return choices[int(user_choice) - 1]
# quicksort function
def quicksort(arr):
if len(arr) <= 1: return arr
m = arr[randrange(0, len(arr))]
return quicksort([i for i in arr if i < m]) + \
[i for i in arr if i == m] + \
quicksort([i for i in arr if i > m])
# quick search in sorted list
def check_match(input, text):
match_count = 0
for char in range(len(input)):
if len(input) > len(text):
return False
elif input[char] == text[char]:
match_count += 1
else:
break
if match_count == len(input):
return True
return False
def find_match(list, input):
# base case
if len(list) == 1:
if check_match(input, list[0]) is True:
return list[0]
return "no match found..."
# define slicers
pivot = len(list) // 2
start = pivot
end = pivot
# check for match
if check_match(input, list[pivot]) is True:
while start >= 0 and check_match(input, list[start]) is True:
start -= 1
while end <= (len(list) - 1) and check_match(input, list[end]) is True:
end += 1
# else call recursive steps
else:
if input < list[pivot]:
return find_match(list[:pivot + 1], input)
return find_match(list[pivot:], input)
# return sliced list
return list[start + 1:end]
##helper variables and functions
def bolean_test(prompt):
user_input = input(f"{prompt} [y/n]")
if user_input.lower() == "y":
return True
elif user_input.lower() == "n":
return False
else:
return bolean_test(prompt)
def get_choice(choices, input_text):
count = 0
for choice in choices:
count += 1
print(f"{count}) {choice}\n")
choice_range = [f"{num}" for num in range(1, count)]
user_choice = input(input_text)
if user_choice not in choice_range:
print(f"invalid input: please choose from 1 to {count}")
return get_choice(choices, input_text)
else:
return choices[int(user_choice) - 1]
# ingredient filtering logic
def ingredient_filtering(ingredient_list):
search_ingredient_input = input("Type the first letter or first few letters of the ingredient you are looking for:")
match = find_match(ingredient_list, search_ingredient_input)
if type(match) is list:
print("\nMatches found:\n")
for i in match:
print(i)
test = bolean_test("Want to filter some more?")
elif type(match) is str:
print(match)
test = False
if test is True:
return ingredient_filtering(match)
else:
if type(match) is list:
return match
return ingredient_list
# recipe filtering logic
def filter_recipes(ingredients, recipes):
recipes_filtered = []
for i in ingredients:
subset = get_recipes_by_ingredient(recipes, i)
for r in subset:
if r not in recipes_filtered:
recipes_filtered.append(r)
return recipes_filtered
and the third holds the classes which I am having issues with, called [recipes.py]
class Recipe():
def __init__(self, dict, id):
self.id = id
self.name = dict["name"]
self.minutes = dict["minutes"]
self.steps = eval(dict["steps"])
self.ingredients = eval(dict["ingredients"])
def has_ingredient(self, ingredient):
return ingredient in self.ingredients
def __str__(self):
print(self.name.title() + "\n")
print(f"Preparation time: {self.minutes} minutes \n")
print("Ingredients:")
for i in self.ingredients:
print(f"- {i};")
print("\nPreparation Steps:")
for s in self.steps:
print(f"- {s};")
return ""
when I moved the database into the one file I stared getting a whole bunch of errors

third holds the classes which I am having issues with
At least one of these lines will fail because you are trying to eval() non-Python code.
self.steps = eval(dict["steps"])
self.ingredients = eval(dict["ingredients"])
Refer
'steps': 'melt cream cheese and butter in large saucepan over low heat, etc',
'ingredients': ['cream cheese', 'butter']},
e.g.
>>> eval('melt cream cheese and butter in large saucepan over low heat, etc')
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<string>", line 1
melt cream cheese and butter in large saucepan over low heat, etc
^
SyntaxError: invalid syntax
Instead, you should make your class like this (or better, use a dataclass)
class Recipe():
def __init__(self, id, name, minutes, steps, ingredients):
self.id = id
self.name = name
self.minutes = minutes
self.steps = steps
self.ingredients = ingredients
Then remove the need for dictionaries
##create Recipe instances
recipe_list = [
Recipe(id='192281',name='southern butter mints', minutes='15', steps='melt cream cheese and butter in large saucepan over low heat, etc', ingredients=['cream cheese', 'butter']),
...
]
If you want in recipes conditional to work, you need to implement __eq__ function in that class. If you want to be able to sort the list, then __cmp__
If you want a proper database where you can filter, sort, and query, then start with sqlite3

Related

how i create new object to use on turn based battle game 3units vs 3 ai units

Your team has been assigned to develop a console or GUI turn-based battle game. The game allows player setup his/her team which made up of a numbers of units (default is 3). Each unit has a name, health point (HP), attack point (ATK), defence point (DEF), experience (EXP) and a rank. On top of that, a unit can be either a Warrior or Tanker which having different strength in different range for ATK and DEF point. The initial value for each attribute point are describe in the details requirement in Part A – Table 1.
The game will then setup another team belongs to AI which made up of same number of unit as the player’s team. The type of unit will be assigned randomly by chances. The name of each unit will be specify by the player while the name of each unit for AI team will be defined with prefix with “AI” follow by 2 random digits i.e. AI87.
A player can select a unit from his/her team and attack the other unit (the target) in the opponent / AI team. Unit which are severely damaged (i.e. HP equals to less than 0) will be defeated and removed from the team. The team (player / AI) which destroy all the opponent units first will be declared as winner of the game.
enter code here
class GameCharacter:
char_name = ""
char_type = ""
__hp = 0
__atk = 0
__def = 0
__rank = 0
def __init__(self, char_type, char_name):
self.char_type: str = char_type
self.char_name: str = char_name
if char_type == "Warrior":
self.setup_warrior()
elif char_type == "Tanker":
self.setup_tanker()
def setup_warrior(self):
self.__hp = 100
self.__atk = 20
self.__def = 6
self.__rank = 1
return [self]
def setup_tanker(self):
self.__hp = 100
self.__atk = 8
self.__def = 9
self.__rank = 1
return [self]
def get_attack(self):
return self.__atk
def get_health(self):
return self.__hp
def __str__(self):
text = "Character type:{},name:{}".format(self.char_type, self.char_name)
return text
enter code here
import game_setting
import random
rounds = 1
count = 0
gs = game_setting.GameCharacter.__init__(char_type, char_name)
player_team = []
ai_bot = []
def detail_ai():
print(ai_bot)
def detail_player():
print(player_team)
def details_all():
print(player_team)
print(ai_bot)
def main():
get_name = ""
j = random.randint(1, 2)
ch = ""
i: int
types = ""
for i in range(1, 4):
get_name = (input("Choose character name:"))
ch = (input("Choose character type [w/t]:")).lower()
if ch == 'w' and get_name != "":
types: str = "Warrior"
player_team.append(types)
player_team.append(get_name)
print("character", i, ":", types, "Name:", get_name)
elif ch == 't':
types: str = "Tanker"
player_team.append(self.types)
print("character", i, ":", types, "Name:", get_name)
else:
print("Wrong value ")
# =======================================Ai Bot name=================================================
for i in range(1, 4):
if ch == "w" and j != j:
ch: str = "Warrior"
ai_bot.append(ch)
elif ch == "t" and j != j:
types: str = "Tanker"
player_team.append(types)
else:
print("Wrong value ")
k = str(random.randint(10, 99))
if get_name != get_name:
get_name: str = "AI" + k
ai_bot.append(get_name)
else:
print("Done setting.")
print("character", i, " : ", types, "Name:", get_name)
show_name: str = ""
show_type: str = ""
main()

How to print the file name by calling a function name in the file in python

Here is a program based on CV screening. In this program I have given scoring for each CV to rank them. Now the output just gives me the scoring number I want in the output that it gives me the file name.
The program is:
import re
import fitz
import os
# Create an array "zs[]" that store the score values
zs = []
# call the Resume files by calling the folder name
for filename in os.listdir('resume/'):
# Select only PDF files
if filename.endswith('.pdf'):
print(filename)
os.chdir('C:/Users/M. Abrar Hussain/Desktop/cv/resume')
pdfFileObj = open(filename, 'rb')
# Extract the text Data from resume files
with fitz.open(pdfFileObj) as doc:
text = ""
for page in doc:
text += page.getText()
print(text)
# Splitting the Resume Data into many indexes of Array
p = doc.loadPage(0)
p_text = p.getText()
p_lines = p_text.splitlines()
# Split the information and the data
split_lst = [i.split(': ', 1) for i in p_lines]
d = {a: b.rstrip() for a, b in split_lst}
# Naming the information part
f = d["Name"]
g = d["GPA"]
h = d["Skills"]
i = d["Experience"]
p = re.findall(r"[-+]?\d*\.\d+|\d+", i)
# search the keywords with the data that extract from resume
search_keywords = ['Laravel', 'Java', 'Python']
search_exp = ['1', '1.5', '2', '2.5', '3']
search_gpa = ['2.5', '2.6', '2.7', '2.8', '2.9', '3.0', '3.1', '3.2', '3.3', '3.4', '3.5', '3.6', '3.7',
'3.8', '3.9', '4.0']
# Comparing GPA data with the keywords
lst = []
for gpa in search_gpa:
if gpa in g:
lst.append(gpa)
# Comparing Skills data with keywords
lst1 = []
for word in search_keywords:
if word in h:
lst1.append(word)
# Comparing Experience data with keywords
lst2 = []
for exp in search_exp:
if exp in p:
lst2.append(exp)
# Scoring the Extracted data to see the best resume
score = 0
w1 = []
# Scoring the GPA
for w1 in lst:
if '3.0' <= w1 < '3.5':
score += 1
if '3.5' <= w1 <= '4':
score += 2
# Scoring the SKills
for w1 in lst1:
if w1 == 'Laravel':
score += 2
if w1 == 'Python':
score += 2
if w1 == 'Java':
score += 1
# Scoring the Experience
for w1 in lst2:
if '2.5' <= w1 < '3':
score += 0.5
if '3' <= w1 < '3.5':
score += 1
if '3.5' <= w1:
score += 2
# store score values in an array
tt = zs.append(score)
print("%s has Scored %s" % (f, score))
print('\n')
pdfFileObj.close()
# Rank the CV's on the basis of Scoring
zs.sort(reverse=True)
print(zs)
The Output of the program is:
cv2.pdf
Name: Danish Ejaz
GPA: 3.7
Skills: Python, Java
Experience: 2.5 years
Danish Ejaz has Scored 5.5
cv3.pdf
Name: Abdullah
GPA: 3.2
Skills: Laravel, Java
Experience: 2 years
Abdullah has Scored 4
cv5.pdf
Name: M. Abrar Hussain
GPA: 3.5
Skills: Python, Laravel
Experience: 3 years
M. Abrar Hussain has Scored 7
[7, 5.5, 4]
Process finished with exit code 0
The second last line is the result after scoring. In this result it just gives us the scoring number, can I call the file name in the result as well? if yes then kindly help me to complete this project.
The proper way IMHO is to define a class, minimal variant would be
class Candidate:
def __init__(self, name, score, filename):
self.name = name
self.score = score
self.filename = filename
def __gt__(self, other):
return self.score > other.score
def __str__(self):
return f'Candidate{self.name, self.filename, self.score}'
def __repr__(self):
return self.__str__()
put this before your main for loop. Then instead of
tt = zs.append(score)
put
tt = zs.append(Candidate(f, score, filename))
It should work the same otherwise. Here is little explanatory usage:
class Candidate:
def __init__(self, name, score, filename):
self.name = name
self.score = score
self.filename = filename
def __gt__(self, other):
return self.score > other.score
def __str__(self):
return f'Candidate{self.name, self.filename, self.score}'
def __repr__(self):
return self.__str__()
# __init__ allows this
a = Candidate("Arnold", 10, "arnold.pdf")
b = Candidate("Betty", 11, "betty.pdf")
# __gt__ allows this
print(a < b)
print(a > b)
# __str__ allows this
print(a)
# __repr__ allows human-readable this
print([a, b])
# __repr__ and __gt__ allows human-readable this
print(sorted([b, a]))
This would print
True
False
Candidate('Arnold', 'arnold.pdf', 10)
[Candidate('Arnold', 'arnold.pdf', 10), Candidate('Betty', 'betty.pdf', 11)]
[Candidate('Arnold', 'arnold.pdf', 10), Candidate('Betty', 'betty.pdf', 11)]
You just have to store your filenames and print them at the end together with the scores:
# Create a dictionary with filenames as key and add the score as value
# Note that this might be an issue if you have irrelevant files in your directory
file_scores = dict.fromkeys(listdir('resume/'))
# call the Resume files by calling the folder name
for filename in file_scores:
# Your scoring logic
(...)
# store score values in the dictionary
file_scores[filename] = score
(...)
# Remove items without value
file_scores = {k: v for k, v in file_scores.items() if v}
# Sort the dictionary based on score descending
file_scores = {k: v for k, v in sorted(file_scores.items(), key=lambda x: x[1], reverse=True)}
# Print the file and the score together
for filename, score in file_scores.items():
if score: # Ignore other files
print(f"File {filename}: Score = {score}")
The easiest way to achieve what you want is by using table-structures. Given that you have similar fields in each result, you could for instance create a pd.DataFrame that you fill with all your values and then afterwards use sort_values and select the score column.
There are of course other alternatives where you use np.argsort or similar, but a DataFrame is probably the easiest way to achieve what you are after.

How to store the total withdrawal amount for each category object?

I have a Category class and there is a ledger attribute for each instance of this class. This ledger attribute is actually a list of dictionaries which contain the withdrawal and deposit amounts and descriptions in the form {"amount" : amount, "description" : description}. Now, I want to define a function create_spend_chart which will take a list of objects as the parameter, and will find the total amount of withdrawals. I have been able to do this successfully:
def create_spend_chart(categories):
total_withdrawn = 0
for i in categories:
for p in i.ledger:
if p["amount"] < 0:
total_withdrawn += -p["amount"]
But the problem I'm facing here is, I can't seem to store the total withdrawal amount for each category object separately. How can I do this?
My code-base might help you ins answering the question:
class Category:
def __init__(self, name):
self.name = name
self.ledger = list()
def get_balance(self):
total_balance = 0
for i in self.ledger:
total_balance += i["amount"]
return total_balance
def check_funds(self, amount):
if self.get_balance() >= amount:
return True
else:
return False
def deposit(self, amount, description = "Deposit"):
form = {"amount" : int(amount), "description" : description}
self.ledger.append(form)
def withdraw(self, amount, description = "Withdrawal"):
if description == None:
description = "Withdrawal"
form = {"amount" : -int(amount), "description" : description}
if self.check_funds(amount):
self.ledger.append(form)
return True
else:
return False
def transfer(self, amount, category_object):
form1 = {"amount" : -int(amount), "description" : f"Transfer to {category_object.name}"}
form2 = {"amount" : int(amount), "description" : f"Transfer from {self.name}"}
if self.check_funds(amount):
self.ledger.append(form1)
category_object.ledger.append(form2)
return True
else:
return False
def __repr__(self):
Ledger = ""
for i in self.ledger:
if len(i["description"]) > 23:
des = i["description"][:23]
else:
des = i["description"]
Ledger += des.ljust(23) + str(round(i["amount"], 2)).rjust(7) + "\n"
Ledger = Ledger + "Total: " + str(round(self.get_balance(), 2))
receipt = f"{self.name}".center(30, "*") + "\n" + Ledger
return receipt
def create_spend_chart(categories):
total_withdrawn = 0
withdrawals = list()
for i in categories:
for p in i.ledger:
if p["amount"] < 0:
total_withdrawn += -p["amount"]
PS: This function is not a method, it is defined outside of the class declaration.
Use a collections.defaultdict to make aggregations such as that easy as pie.
import collections
# ...
withdrawn_per_category = collections.defaultdict(int)
for i in categories:
for p in i.ledger:
if p["amount"] < 0:
withdrawn_per_category[i.name] += -p["amount"]
(I've opted to use int as the default data type, but it doesn't truly matter here, so long as it's a conversible numeric type.)
Without collections
If for some reason you don't want to use the handy, built-in collections module, you can emulate the same behavior yourself with a regular dict:
withdrawn_per_category = {}
for i in categories:
for p in i.ledger:
if p["amount"] < 0:
withdrawn_per_category[i.name] = withdrawn_per_category.get(i.name, 0) - p["amount"]

How are finite automata implemented in code?

How does one implement a DFA or an NFA for that matter in Python code?
What are some good ways to do it in Python? Are they ever used in real world projects?
A straightforward way to represent a DFA is as a dictionary of dictionaries. For each state create a dictionary which is keyed by the letters of the alphabet and then a global dictionary which is keyed by the states. For example, the following DFA from the Wikipedia article on DFAs
can be represented by a dictionary like this:
dfa = {0:{'0':0, '1':1},
1:{'0':2, '1':0},
2:{'0':1, '1':2}}
To "run" a dfa against an input string drawn from the alphabet in question (after specifying the initial state and the set of accepting values) is straightforward:
def accepts(transitions,initial,accepting,s):
state = initial
for c in s:
state = transitions[state][c]
return state in accepting
You start in the initial state, step through the string character by character, and at each step simply look up the next state. When you are done stepping through the string you simply check if the final state is in the set of accepting states.
For example
>>> accepts(dfa,0,{0},'1011101')
True
>>> accepts(dfa,0,{0},'10111011')
False
For NFAs you could store sets of possible states rather than individual states in the transition dictionaries and use the random module to pick the next state from the set of possible states.
Here is my version of a dfa implementation if you're looking for a more object-oriented one. I was however ever so slightly inspired by John Coleman's answer.
class Node:
def __init__(self, val):
self.val = val
self.links = []
def add_link(self, link):
self.links.append(link)
def __str__(self):
node = "(%s):\n" % self.val
for link in self.links:
node += "\t" + link + "\n"
return node
def __add__(self, other):
return str(self) + other
def __radd__(self, other):
return other + str(self)
def equals(self, node):
ok = (self.val == node.val)
if len(self.links) == len(node.links):
for i in range(len(self.links)):
ok = ok and (self.links[i] == node.links[i])
return ok
else:
return False
class Link:
def __init__(self, from_node, etiquette, to_node):
self.from_node = from_node
self.etiquette = etiquette
self.to_node = to_node
def __str__(self):
return "(%s --%s--> %s)" % (self.from_node.val, self.etiquette, self.to_node.val)
def __add__(self, other):
return str(self) + other
def __radd__(self, other):
return other + str(self)
def equals(self, link):
return (self.from_node == link.from_node) and (self.etiquette == link.etiquette) and (self.to_node == link.to_node)
class Automata:
def __init__(self, initial_node, nodes, terminal_node):
self.initial_node = initial_node
self.nodes = nodes
self.terminal_node = terminal_node
def get_next_node(self, current_node, etiquette):
for link in current_node.links:
if link.etiquette == etiquette:
return link.to_node
return None
def accepts(self, string):
node = self.initial_node
for character in string:
node = self.get_next_node(node, character)
return self.terminal_node.equals(node)
def __str__(self):
automata = "Initial node: %s\nTerminal node: %s\n" % (self.initial_node.val, self.terminal_node.val)
for node in self.nodes:
automata += node
return automata
def __add__(self, other):
return str(self) + other
def __radd__(self, other):
return other + str(self)
if __name__ == '__main__':
pass
s0 = Node("s0")
s1 = Node("s1")
s2 = Node("s2")
s0_0_s0 = Link(s0, '0', s0)
s0_1_s1 = Link(s0, '1', s1)
s1_0_s2 = Link(s1, '0', s2)
s1_1_s0 = Link(s1, '1', s0)
s2_0_s1 = Link(s2, '0', s1)
s2_1_s2 = Link(s2, '1', s2)
s0.add_link(s0_0_s0)
s0.add_link(s0_1_s1)
s1.add_link(s1_0_s2)
s1.add_link(s1_1_s0)
s2.add_link(s2_0_s1)
s2.add_link(s2_1_s2)
a = Automata(s0, [s0, s1, s2], s0)
print(a)
print(a.accepts('1011101')) #True
print(a.accepts('10111011')) #False
Here I present a recursive solution for NFA. Consider the following nfa:
The transitions can be represented using list of lists as follows:
transition = [[[0,1],[0]], [[4],[2]], [[4],[3]], [[4],[4]],[[4],[4]]]
Note: State 4 is a hypothetical state. Once you go to that state, you can't move further. It is helpful when you can't read the input from the current state. You directly go to the state 4 and say input is not accepted for current progress(Check other possibilities by going back). e.g, if you are at q1, and the current input symbol is 'a', you go to state 4 and stop computing further.
Here is the Python code:
#nfa simulation for (a|b)*abb
#state 4 is a trap state
import sys
def main():
transition = [[[0,1],[0]], [[4],[2]], [[4],[3]], [[4],[4]]]
input = raw_input("enter the string: ")
input = list(input) #copy the input in list because python strings are immutable and thus can't be changed directly
for index in range(len(input)): #parse the string of a,b in 0,1 for simplicity
if input[index]=='a':
input[index]='0'
else:
input[index]='1'
final = "3" #set of final states = {3}
start = 0
i=0 #counter to remember the number of symbols read
trans(transition, input, final, start, i)
print "rejected"
def trans(transition, input, final, state, i):
for j in range (len(input)):
for each in transition[state][int(input[j])]: #check for each possibility
if each < 4: #move further only if you are at non-hypothetical state
state = each
if j == len(input)-1 and (str(state) in final): #last symbol is read and current state lies in the set of final states
print "accepted"
sys.exit()
trans(transition, input[i+1:], final, state, i) #input string for next transition is input[i+1:]
i = i+1 #increment the counter
main()
Sample Run(strings ending with abb are accepted):
enter the string: abb
accepted
enter the string: aaaabbbb
rejected
You don't need a for loop over range(len(input)) if you're using recursion. You're overcomplicating the code. Here's a simplified version
import sys
def main():
transition = [[[0,1],[0]], [[4],[2]], [[4],[3]], [[4],[4]]]
input = raw_input("enter the string: ")
input = list(input) #copy the input in list because python strings are immutable and thus can't be changed directly
for index in range(len(input)): #parse the string of a,b in 0,1 for simplicity
if input[index]=='a':
input[index]='0'
else:
input[index]='1'
final = "3" #set of final states = {3}
start = 0
trans(transition, input, final, start)
print "rejected"
def trans(transition, input, final, state):
for each in transition[state][int(input[0])]: #check for each possibility
if each < 4: #move further only if you are at non-hypothetical state
state = each
if len(input)==1:
if (str(state) in final): #last symbol is read and current state lies in the set of final states
print "accepted"
sys.exit()
else:
continue
trans(transition, input[1:], final, state) #input string for next transition is input[i+1:]
main()
I have implemented dfa which works for any of the dfa. But this is not in object oriented pattern.
states=list(map(int,input("Enter States : ").split(" ")))
symbols=list(input("Enter Symbols : ").split(" "))
initial_state=int(input("Enter initial state : "))
final_states=list(map(int,input("Enter final states : ").split(" ")))
transitions=[]
inlists=[]
for i in range(len(symbols)):
print("Enter transitions for symbol "+symbols[i]+" from all states :")
for j in range(len(states)):
inlists.append(int(input()))
transitions.append(inlists)
inlists=[]
cur_state=initial_state
while(1):
cur_state=initial_state
string=input("Enter string : ")
if string=='#':
break
for symbol in string:
print("["+str(cur_state)+"]"+"-"+symbol+"->",end="")
cur_state=transitions[symbols.index(symbol)][cur_state]
if cur_state in final_states:
print("["+str(cur_state)+"]")
print("String is accepted.")
else:
print("["+str(cur_state)+"]")
print("String is not accepted.")
Accepting string 101* and 001* modification of #John Coleman
#Dfa for accepting only 101+00101001
dfa101 = {0:{'1':1},
1:{'0':2},
2:{'1':3},
3:{'0':3, '1':3}}
#Dfa for accepting only 001+00101001
dfa001={0:{'0':1},
1:{'0':2},
2:{'1':3},
3:{'0':3, '1':3}}
def accepts(transitions,initial,accepting,s):
state = initial
try:
for c in s:
state = transitions[state][c]
if(state in accepting):
return 'Accepted'
else:
return 'Rejected'
except:
return 'Rejected'
print('Dfa of 101+ ',accepts(dfa101,0,{3},'10101111000')) #Accepted
print('Dfa of 001+ ',accepts(dfa001,0,{3},'00101010101')) #Accepted
To showcase my solution, let's take the following DFA as an example:
Language over 𝛴 = (0, 1) containing strings that are either made up of only 1’s or strings in which every 0 is followed by a 1.
The transition table for this DFA is:
delta
0
1
->*S
A
S
A
D
S
D
D
D
My program, written in Python3, is designed to accept the transition table of any DFA over the alphabet (0, 1) to check whether a string will be accepted by the DFA or not.
To use my program, we have to input the above transition table in the following format into a text file named fa.txt present in the same directory as the program.
fa.txt:
->*s(a,s)
a(d,s)
d(d,d)
For start state, the state name must be preceded by -> and a final state must be preceded by *. In case the start state is a final state, -> must come before *.
The state name must be only one character in length.
The start state must be named s.
The order of the states in the TXT file is irrelevant.
The code:
file = open("fa.txt", "r")
l = file.readlines()
x = 0
def findState(state):
lines = l
for i in range(0, len(lines)):
if lines[i][0] == '-':
lines[i] = lines[i][2::]
if lines[i][0] == '*':
if state == lines[i][1]:
return [lines[i][3], lines[i][5], 1]
if lines[i][0] == state:
return [lines[i][2], lines[i][4], 0] # state to go to on 0, state to go to on 1, is it final?
s = input("Enter a binary string to test it against the DFA in file fa.txt: ")
on0_on1 = findState('s') # start state
print("s", end = "")
for c in range(0, len(s)):
if s[c] != '0' and s[c] != '1':
print("Fail")
exit(0)
if s[c] == '0':
print(' ---0--->', on0_on1[0], end = '')
on0_on1 = findState(on0_on1[0])
else:
print(' ---1--->', on0_on1[1], end = '')
on0_on1 = findState(on0_on1[1])
if on0_on1[2] == 1 and c == len(s) - 1:
print("\nPass")
elif c == len(s) - 1 and on0_on1[2] == 0:
print("\nFail")

Reading from raw_data.txt and writing to a results.txt file with processing in Python

This is my first post. I have a function that asks for the number of students. Then, for each student, first three lines contain the following information: Student ID, name, and number of courses taken that semester. Now, for each course, the course number, credit hour, and the percentage of scores earned by the student is listed.
def rawdata():
semester = 1
if semester == 1:
raw_file = open('raw_data.txt', 'a')
total = 0.0
total2 = 0.0
num_students = int(input('Enter number of students: '))
for student in range(num_students):
raw_file.write('Start' + '\n')
student_id = input('Enter student ID: ')
name = input('Enter Name: ')
num_classes = int(input('Enter number of courses taken: '))
raw_file.write(student_id + '\n')
raw_file.write(name + '\n')
raw_file.write(str(num_classes) + '\n')
for classes in range(num_classes):
course_number = input('Enter Course Number: ')
credits = int(input('Enter Credit Hours: '))
GPA1 = float(input('Enter percentage grade for class: '))
raw_file.write(course_number + '\n')
raw_file.write(str(credits) + '\n')
raw_file.write(str(GPA1) + '\n')
total += credits
raw_file.write('End' + '\n')
raw_file.close()
print('Data has been written')
All the data is listed to a txt file and now I need to PULL this information from my raw_data.txt which looks like(varies with inputs):
Start
eh2727
Josh D
2
MAT3000
4
95.0
COM3000
4
90.0
End
Start
ah2718
Mary J
1
ENG3010
4
100.0
End
and process it so that I can calculate each students GPA. I have each students block of info contained by a Start/End and I don't know how to read this info in my processing function in order for me to calculate their GPA. This is what I have so far:
def process():
data = open('raw_data.txt', 'r')
results = open('process_results.txt', 'w')
buffer = []
for line in data:
if line.startswith('Start'):
buffer = []
buffer.append(line)
if line.startswith("End"):
for outline in buffer:
results.write(outline)
This simply writes it all into my results text and I don't know how to individually process each block of information to calculate the GPA. Any help would be greatly appreciated.
Since it is your own code writing out the data to the .txt file, you might consider writing it in an easier and/or more fault tolerant format for machine reading, for example JSON or XML. Alternatively, you might want to consider using pickle or cpickle to serialize the data and read it in again.
Anyway, on to your question: how to read the file. Unfortunately, you do not tell us what you want to do with the parsed data. I assume here you want to print it. Normally you would of course create a nice class or classes describing students and courses.
For parsing of files like yours, I use the string method split() a lot. split() is your best friend. See the python docs for more info on string methods.
f = open('raw_data.txt', 'rt')
data = f.read()
students = data.split('Start\n')[1:]
for s in students:
lines = s.split('\n')
id = lines[0]
name = lines[1]
nrcourses = int(lines[2])
line = 2
courses = []
for n in range(nrcourses):
number = lines[line+1]
credit = lines[line+2]
score = lines[line+3]
courses.append((number, credit, score))
line += 3
print 'id: %s; name %s; course list %s' % (id, name, courses)
f.close()
You need to develop a state machine for processing a student record. You're on the right track with your 'if line.strip() == 'Start', that's a sentinel indicating the beginning of a record. What you can do at this point is set a flag, processStudentRecord = true, so the next pass through in 'for line in data' you know the line you get is a part of a record. After setting the flag you should break that if loop so you don't have to have a bunch of elifs.
processStudentRecord = False
for line in data:
if line.strip() == 'Start':
processStudentRecord = True
expecting = "student_id"
# break here so you go immediately to the next line
if line.strip() == 'End':
processStudentRecord = False
# break here so you go immediately to the next line
if processStudentRecord:
# keep track of where you are in the student record
if expecting == "student_id":
# extract the student name and then proceed to the next expected line
expecting = "student_name"
elif expecting == ""
And so on and so forth. Note, this is a "procedural" method of doing this - one can invent object-oriented or functional solutions.
This is quite a bit of code, but if you trace it through until you understand how it works you'll learn a lot.
First we need to take a class mark and convert it to points. You could write this as a cascade of 13 if's, but I like the data-driven approach:
import bisect
def grade_points(pct):
grade = [ 0, 50, 53, 57, 60, 63, 67, 70, 73, 77, 80, 85, 90]
points = [0.0, 0.7, 1.0, 1.3, 1.7, 2.0, 2.3, 2.7, 3.0, 3.3, 3.7, 4.0, 4.0]
if 0 <= pct <= 100:
# find the highest grade <= pct
idx = bisect.bisect_right(grade, pct) - 1
# return the corresponding grade-point
return points[idx]
else:
raise ValueError('pct value should be in 0..100, not {}'.format(pct))
Next we want a Student class to make it easy to track per-student data
class Student(object):
str_format = '{id:>8} {name} {gpa}'
def __init__(self, *args):
if len(args)==1: # copy constructor
student = args[0]
self.id, self.name, self.classes = student.id, student.name, student.classes
elif len(args)==3: # "id", "name", [classes,]
self.id, self.name, self.classes = args
else:
raise ValueError('Failed call to {}.__init__{}'.format(type(self), args))
#property
def gpa(self):
points = sum(hour*grade_points(grade) for code,hour,grade in self.classes)
hours = sum(hour for code,hour,grade in self.classes)
return points / hours
def __str__(self):
return type(self).str_format.format(id=self.id, name=self.name, classes=self.classes, gpa=self.gpa)
def __repr__(self):
return "{}('{}', '{}', {})".format(type(self).__name__, self.id, self.name, self.classes)
So you can create a student and find her GPA like so:
sally = Student('ab2773', 'S Atkins', [
('MAT3000', 4, 81.0),
('ENG3010', 4, 85.0)
])
print sally # ' ab2773 S Atkins 3.85'
Now we need to be able to stream Students to and from a file. This is a bit painful from an OOP point of view, because a Student object really shouldn't need to know anything about a File object or vice-versa, and more so because we want to upgrade you to a better file format - a Student object definitely doesn't need to know about multiple incompatible File types.
I've approached this by subclassing Student; I wrote the Student.__init__ method in such a way that I can cast back and forth and don't have to rewrite it for the subclasses, so the subclass just knows how to convert itself to and from your nasty file format
class NastyFileStudent(Student):
#classmethod
def from_strings(cls, strings):
if len(strings) > 3 and len(strings) == 3 + int(strings[2])*3:
codes = strings[3::3]
hours = map(int, strings[4::3])
grades = map(float, strings[5::3])
return Student(strings[0], strings[1], zip(codes, hours, grades))
else:
# not enough data returned - probably end of file
return None
def __str__(self):
data = [self.id, self.name, str(len(self.classes))] + [str(i) for c in self.classes for i in c]
return '\n'.join(data)
and the file just knows it has Student data but nothing about the contents
class NastyFile(object):
START = 'Start'
END = 'End'
#staticmethod
def _read_until(endfn, seq):
is_end = endfn if callable(endfn) else lambda s: s==endfn
data = []
for s in seq:
if is_end(s):
break
else:
data.append(s)
return data
def __init__(self, name, mode='r'):
self.name = name
self.mode = mode
self._f = open(name, mode)
self.lines = (ln.strip() for ln in self._f)
def __del__(self):
self._f.close()
def __iter__(self):
return self
def next(self):
_ = NastyFile._read_until(NastyFile.START, self.lines)
strings = NastyFile._read_until(NastyFile.END, self.lines)
student = NastyFileStudent.from_strings(strings)
if student is None:
raise StopIteration()
else:
return student
def read(self):
return list(self)
def write(self, s):
if not hasattr(s, '__iter__'):
s = [s]
for student in s:
self._f.write('{}\n{}\n{}\n'.format(NastyFile.START, str(NastyFileStudent(student)), NastyFile.END))
Now we can read and write files of student records like so
>>> students = NastyFile('student_records.txt').read()
>>> for s in students:
... print s
eh2727 Josh D 4.0
ah2718 Mary J 4.0
>>> students.append(sally)
>>> students.sort(key=lambda s: s.name.rsplit(None,1)[-1]) # sort by last name
>>> for s in students:
... print s
ab2773 S Atkins 3.85
eh2727 Josh D 4.0
ah2718 Mary J 4.0
>>> newfile = NastyFile('new_records.txt', 'w')
>>> newfile.write(students)
>>> for i,s in enumerate(NastyFile('new_records.txt'), 1):
... print '{:>2}: {}'.format(i, s)
1: ab2773 S Atkins 3.85
2: eh2727 Josh D 4.0
3: ah2718 Mary J 4.0

Categories

Resources