Stable matching matches least preferable - nim-lang

I have implemented the stable matching algorithm but it seems that the implementation matches the least preferable candidates. I'm asking for a code review:
import options, sequtils
type
Person* = ref object
id: int
name: string
engagedTo: Option[Person]
preferences: seq[Person]
MatchPool* = object
husbands, wives: seq[Person]
proc newPerson*(nameofperson: string, isMale: bool = true, engagedTo: Option[
Person] = none(Person), preferences: openArray[Person] = []): Person =
var
nextMaleId = 1
nextFemaleId = -1
id: int
if isMale:
id = nextMaleId
inc nextMaleId
else:
id = nextFemaleId
dec nextFemaleId
return Person(id: id, name: nameofperson, engagedTo: engagedTo,
preferences: preferences.toSeq())
proc addPreference*(self: var Person, preference: varargs[Person]) =
self.preferences.add(preference)
proc newMatchPool*(husbands, wives: openArray[Person]): Option[MatchPool] =
let dim = husbands.len()
if wives.len() == dim:
if husbands.allIt(it.preferences.len() == dim):
if wives.allIt(it.preferences.len() == dim):
result = some(MatchPool(husbands: husbands.toSeq(),
wives: wives.toSeq()))
proc isSingle(self: Person): bool = self.engagedTo.isNone()
proc isEngaged(self: Person): bool = not self.isSingle()
proc disengage(person: var Person) =
if person.engagedTo.isSome():
person.engagedTo.get().engagedTo = none(Person)
person.engagedTo = none(Person)
proc engage(husband, wife: var Person) =
if husband.isEngaged():
disengage(husband)
if wife.isEngaged():
disengage(wife)
husband.engagedTo = some(wife)
wife.engagedTo = some(husband)
proc prefersMoreThanCurrent(self, other: Person): Option[bool] =
if self.isSingle():
result = some(true)
else:
for personRef in self.preferences:
if personRef.id == self.engagedTo.get().id:
result = some(false)
break
elif personRef.id == other.id:
result = some(true)
break
proc solve*(self: var MatchPool): Option[string] =
for husband in self.husbands.mitems():
for wife in husband.preferences.mitems():
let prefers = wife.prefersMoreThanCurrent(husband)
if prefers.isNone():
result = some("Found a spouse that does not prefer another spouse")
break
elif prefers.get():
engage(husband, wife)
result = none(string)
proc print*(self: MatchPool) =
for husband in self.husbands:
echo(husband.name, " is engaged to ", husband.engagedTo.get().name)
echo "and"
for wife in self.wives:
echo(wife.name, " is engaged to ", wife.engagedTo.get().name)
driver:
import unittest
import options
import cdsan/stable_matching
test "stable_matching":
var
rose = newPerson("Rose", false)
alexis = newPerson("Alexis", false)
alicia = newPerson("Alicia", false)
samantha = newPerson("Samantha", false)
ads = newPerson("Ads")
bruce = newPerson("Bruce")
zab = newPerson("Zab")
eddy = newPerson("Eddy")
rose.addPreference(ads, zab, eddy, bruce)
alexis.addPreference(bruce, zab, eddy, ads)
alicia.addPreference(eddy, zab, bruce, ads)
samantha.addPreference(bruce, eddy, zab, ads)
ads.addPreference(rose, alicia, alexis, samantha)
bruce.addPreference(samantha, alicia, rose, alexis)
zab.addPreference(alexis, rose, alicia, samantha)
eddy.addPreference(samantha, rose, alicia, alexis)
var mp = newMatchPool(wives = [rose, alexis, alicia, samantha], husbands = [
ads, bruce, zab, eddy])
assert mp.isSome()
var pool = mp.get()
assert pool.solve().isNone()
pool.print()
result:
Ads is engaged to Samantha
Bruce is engaged to Alexis
Zab is engaged to Alicia
Eddy is engaged to Rose
and
Rose is engaged to Eddy
Alexis is engaged to Bruce
Alicia is engaged to Zab
Samantha is engaged to Ads
As you can see, Ads and Samantha likes each others the least.Samantha likes Bruce.Rose and Ads prefer each other.
What's causing this?

The problem is that nextMaleId and nextFemaleId are local to newPerson. So every male gets id=1 and every female get id=-1.
If you make nextMaleId and nextFemaleId global variables and change solve to only engage two people if they both prefer each other over their current partner, you get
Ads is engaged to Samantha
Bruce is engaged to Alexis
Zab is engaged to Alicia
Eddy is engaged to Rose
and
Rose is engaged to Eddy
Alexis is engaged to Bruce
Alicia is engaged to Zab
Samantha is engaged to Ads
Which looks like an acceptable solution.

Related

Compute uniswap 3.0 pool (pair) address via python3

I stucked a little bit with a problem how to compute
new uniswap`s version 3 pool (earlier versions it called pair)
address based on 1 and 2
In the new uniswap v3.0 there is also one additional parameter
for computing pool address - fees amount in percents, defined like in sdk
with uint24 type.
From sdk`s computePoolAddress at the first times settled
with computing pool address problem there was one confused me part of the source
[defaultAbiCoder.encode(['address', 'address', 'uint24'], [token0.address, token1.address, fee])
And somewhy I decided to compute it using encodePacked (i.e. encode_abi_packed for python3 from eth_abi.packed) function. But it produced wrong result.
Look deeper in the uniswap v3.0 periphery pool conract - 3 clarified
my mistake. It turns out in version 3.0 using encode (i.e. encode_abi for python3 from eth_abi) function. A little bit more explanations here
So, coupled all together.
Main function to compute pool address with the aids of python3.
from web3 import Web3
from eth_abi.packed import encode_abi_packed
from eth_abi import encode_abi
def compute_pairs_address_with_target_v3(factory = '0x1F98431c8aD98523631AE4a59f267346ea31F984', token_0 = None, token_1 = None, fee = 3000):
POOL_INIT_CODE_HASH = '0xe34f199b19b2b4f47f68442619d555527d244f78a3297ea89325f843f87b8b54'
token_0 = Web3.toChecksumAddress(token_0)
token_1 = Web3.toChecksumAddress(token_1)
abiEncoded_1 = encode_abi(['address', 'address', 'uint24'], (token_0, token_1, fee )) if int(token_0,16)<int(token_1,16) else encode_abi(['address', 'address', 'uint24'], (token_1, token_0, fee ))
salt = Web3.solidityKeccak(['bytes'], ['0x' +abiEncoded_1.hex()])
abiEncoded_2 = encode_abi_packed([ 'address', 'bytes32'], ( factory, salt))
resPair = Web3.solidityKeccak(['bytes','bytes'], ['0xff' + abiEncoded_2.hex(), POOL_INIT_CODE_HASH])[12:]
return(resPair.hex())
Testing it, based on 4 and 5
factoryAddress = '0x1111111111111111111111111111111111111111'
token0 = '0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48'
token1 = '0x6B175474E89094C44Da98b954EedeAC495271d0F'
fee = 500 #https://docs.uniswap.org/sdk/reference/enums/FeeAmount#low
targetPoolAddress = '0x90B1b09A9715CaDbFD9331b3A7652B24BfBEfD32'
assert(targetPoolAddress.lower() == compute_pairs_address_with_target_v3(factory = factoryAddress, token_0 = token0, token_1 = token1, fee = fee).lower())
token0 = '0x7d1afa7b718fb893db30a3abc0cfc608aacfebb0'
token1 = '0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2'
factoryAddress = '0x1F98431c8aD98523631AE4a59f267346ea31F984'
fee = 3000 #https://docs.uniswap.org/sdk/reference/enums/FeeAmount#medium
targetPoolAddress = '0x290a6a7460b308ee3f19023d2d00de604bcf5b42' #WETH /MATIC 0.3 % fee
assert(targetPoolAddress.lower() == compute_pairs_address_with_target_v3(factory = factoryAddress, token_0 = token0, token_1 = token1, fee = fee).lower())

Regex Error and Improvement Driving Licence Data Extraction

I am trying to extract the Name, License No., Date Of Issue and Validity from an Image I processed using Pytesseract. I am quite a lot confused with regex but still went through few documentations and codes over the web.
I got till here:
import pytesseract
import cv2
import re
import cv2
from PIL import Image
import numpy as np
import datetime
from dateutil.relativedelta import relativedelta
def driver_license(filename):
"""
This function will handle the core OCR processing of images.
"""
i = cv2.imread(filename)
newdata=pytesseract.image_to_osd(i)
angle = re.search('(?<=Rotate: )\d+', newdata).group(0)
angle = int(angle)
i = Image.open(filename)
if angle != 0:
#with Image.open("ro2.jpg") as i:
rot_angle = 360 - angle
i = i.rotate(rot_angle, expand="True")
i.save(filename)
i = cv2.imread(filename)
# Convert to gray
i = cv2.cvtColor(i, cv2.COLOR_BGR2GRAY)
# Apply dilation and erosion to remove some noise
kernel = np.ones((1, 1), np.uint8)
i = cv2.dilate(i, kernel, iterations=1)
i = cv2.erode(i, kernel, iterations=1)
txt = pytesseract.image_to_string(i)
print(txt)
text = []
data = {
'firstName': None,
'lastName': None,
'age': None,
'documentNumber': None
}
c = 0
print(txt)
#Splitting lines
lines = txt.split('\n')
for lin in lines:
c = c + 1
s = lin.strip()
s = s.replace('\n','')
if s:
s = s.rstrip()
s = s.lstrip()
text.append(s)
try:
if re.match(r".*Name|.*name|.*NAME", s):
name = re.sub('[^a-zA-Z]+', ' ', s)
name = name.replace('Name', '')
name = name.replace('name', '')
name = name.replace('NAME', '')
name = name.replace(':', '')
name = name.rstrip()
name = name.lstrip()
nmlt = name.split(" ")
data['firstName'] = " ".join(nmlt[:len(nmlt)-1])
data['lastName'] = nmlt[-1]
if re.search(r"[a-zA-Z][a-zA-Z]-\d{13}", s):
data['documentNumber'] = re.search(r'[a-zA-Z][a-zA-Z]-\d{13}', s)
data['documentNumber'] = data['documentNumber'].group().replace('-', '')
if not data['firstName']:
name = lines[c]
name = re.sub('[^a-zA-Z]+', ' ', name)
name = name.rstrip()
name = name.lstrip()
nmlt = name.split(" ")
data['firstName'] = " ".join(nmlt[:len(nmlt)-1])
data['lastName'] = nmlt[-1]
if re.search(r"[a-zA-Z][a-zA-Z]\d{2} \d{11}", s):
data['documentNumber'] = re.search(r'[a-zA-Z][a-zA-Z]\d{2} \d{11}', s)
data['documentNumber'] = data['documentNumber'].group().replace(' ', '')
if not data['firstName']:
name = lines[c]
name = re.sub('[^a-zA-Z]+', ' ', name)
name = name.rstrip()
name = name.lstrip()
nmlt = name.split(" ")
data['firstName'] = " ".join(nmlt[:len(nmlt)-1])
data['lastName'] = nmlt[-1]
if re.match(r".*DOB|.*dob|.*Dob", s):
yob = re.sub('[^0-9]+', ' ', s)
yob = re.search(r'\d\d\d\d', yob)
data['age'] = datetime.datetime.now().year - int(yob.group())
except:
pass
print(data)
I need to extract the Validity and Issue Date as well. But not getting anywhere near it. Also, I have seen using regex shortens the code like a lot so is there any better optimal way for it?
My input data is a string somewhat like this:
Transport Department Government of NCT of Delhi
Licence to Drive Vehicles Throughout India
Licence No. : DL-0820100052000 (P) R
N : PARMINDER PAL SINGH GILL
: SHRI DARSHAN SINGH GILL
DOB: 10/05/1966 BG: U
Address :
104 SHARDA APPTT WEST ENCLAVE
PITAMPURA DELHI 110034
Auth to Drive Date of Issue
M.CYL. 24/02/2010
LMV-NT 24/02/2010
(Holder's Sig natu re)
Issue Date : 20/05/2016
Validity(NT) : 19/05/2021 : c
Validity(T) : NA Issuing Authority
InvCarrNo : NA NWZ-I, WAZIRPUR
Or like this:
in
Transport Department Government of NCT of Delhi
Licence to Drive Vehicles Throughout India
2
Licence No. : DL-0320170595326 () WN
Name : AZAZ AHAMADSIDDIQUIE
s/w/D : SALAHUDDIN ALI
____... DOB: 26/12/1992 BG: O+
\ \ Address:
—.~J ~—; ROO NO-25 AMK BOYS HOSTEL, J.
— NAGAR, DELHI 110025
Auth to Drive Date of Issue
M.CYL. 12/12/2017
4 wt 4
Iseue Date: 12/12/2017 a
falidity(NT) < 2037
Validity(T) +: NA /
Inv CarrNo : NA te sntian sana
Note: In the second example you wouldn't get the validity, will optimise the OCR for later. Any proper guide which can help me with regex which is a bit simpler would be good.
You can use this pattern: (?<=KEY\s*:\s*)\b[^\n]+ and replace KEY with one of the issues of the date, License No. and others.
Also for this pattern, you need to use regex library.
Code:
import regex
text1 = """
Transport Department Government of NCT of Delhi
Licence to Drive Vehicles Throughout India
Licence No. : DL-0820100052000 (P) R
N : PARMINDER PAL SINGH GILL
: SHRI DARSHAN SINGH GILL
DOB: 10/05/1966 BG: U
Address :
104 SHARDA APPTT WEST ENCLAVE
PITAMPURA DELHI 110034
Auth to Drive Date of Issue
M.CYL. 24/02/2010
LMV-NT 24/02/2010
(Holder's Sig natu re)
Issue Date : 20/05/2016
Validity(NT) : 19/05/2021 : c
Validity(T) : NA Issuing Authority
InvCarrNo : NA NWZ-I, WAZIRPUR
"""
for key in ('Issue Date', 'Licence No\.', 'N', 'Validity\(NT\)'):
print(regex.findall(fr"(?<={key}\s*:\s*)\b[^\n]+", text1, regex.IGNORECASE))
Output:
['20/05/2016']
['DL-0820100052000 (P) R']
['PARMINDER PAL SINGH GILL']
['19/05/2021 : c']
You can also use re with a single regex based on alternation that will capture your keys and values:
import re
text = "Transport Department Government of NCT of Delhi\nLicence to Drive Vehicles Throughout India\n\nLicence No. : DL-0820100052000 (P) R\nN : PARMINDER PAL SINGH GILL\n\n: SHRI DARSHAN SINGH GILL\n\nDOB: 10/05/1966 BG: U\nAddress :\n\n104 SHARDA APPTT WEST ENCLAVE\nPITAMPURA DELHI 110034\n\n\n\nAuth to Drive Date of Issue\nM.CYL. 24/02/2010\nLMV-NT 24/02/2010\n\n(Holder's Sig natu re)\n\nIssue Date : 20/05/2016\nValidity(NT) : 19/05/2021 : c\nValidity(T) : NA Issuing Authority\nInvCarrNo : NA NWZ-I, WAZIRPUR"
search_phrases = ['Issue Date', 'Licence No.', 'N', 'Validity(NT)']
reg = r"\b({})\s*:\W*(.+)".format( "|".join(sorted(map(re.escape, search_phrases), key=len, reverse=True)) )
print(re.findall(reg, text, re.IGNORECASE))
Output of this short online Python demo:
[('Licence No.', 'DL-0820100052000 (P) R'), ('N', 'PARMINDER PAL SINGH GILL'), ('Issue Date', '20/05/2016'), ('Validity(NT)', '19/05/2021 : c')]
The regex is
\b(Validity\(NT\)|Licence\ No\.|Issue\ Date|N)\s*:\W*(.+)
See its online demo.
Details:
map(re.escape, search_phrases) - escapes all special chars in your search phrases to be used as literal texts in a regex (else, . will match any chars, ? won't match a ? char, etc.)
sorted(..., key=len, reverse=True) - sorts the search phrases by length in descending order (to get longer matches first)
"|".join(...) - creates an alternation pattern, a|b|c|...
r"\b({})\s*:\W*(.+)".format( ... ) - creates the final regex.
Regex details
\b - a word boundary (NOTE: replace with (?m)^ if your matches occur at the beginning of a line)
(Validity\(NT\)|Licence\ No\.|Issue\ Date|N) - Group 1: one of the search phrases
\s* - zero or more whitespaces
: - a colon
\W* - zero or more non-word chars
(.+) - (capturing) Group 2: one or more chars other than line break chars, as many as possible.

Text in a class - href statement

How could i get all the categories mentioned on each listing page of the same website "https://www.sfma.org.sg/member/category". for example, when i choose alcoholic beverage category on the above mentioned page, the listings mentioned on that page has the category information like this :-
Catergory: Alcoholic Beverage, Bottled Beverage, Spirit / Liquor / Hard Liquor, Wine, Distributor, Exporter, Importer, Supplier
how can i extract the categories mentioned here with in same variable.
The code i have written for this is :-
category = soup_2.find_all('a', attrs ={'class' :'clink'})
links = [links['href'] for links in category]
cat_name = [cat_name.text.strip() for cat_name in links]
but it is producing the below output which are all the links on the page & not the text with in the href:-
['http://www.sfma.org.sg/about/singapore-food-manufacturers-association',
'http://www.sfma.org.sg/about/council-members',
'http://www.sfma.org.sg/about/history-and-milestones',
'http://www.sfma.org.sg/membership/',
'http://www.sfma.org.sg/member/',
'http://www.sfma.org.sg/member/alphabet/',
'http://www.sfma.org.sg/member/category/',
'http://www.sfma.org.sg/resources/sme-portal',
'http://www.sfma.org.sg/resources/setting-up-food-establishments-in-singapore',
'http://www.sfma.org.sg/resources/import-export-requirements-and-procedures',
'http://www.sfma.org.sg/resources/labelling-guidelines',
'http://www.sfma.org.sg/resources/wsq-continuing-education-modular-programmes',
'http://www.sfma.org.sg/resources/holistic-industry-productivity-scorecard',
'http://www.sfma.org.sg/resources/p-max',
'http://www.sfma.org.sg/event/',
.....]
What i need is the below data for all the listings of all the categories on the base URL which is "https://www.sfma.org.sg/member/category/"
['Ang Leong Huat Pte Ltd',
'16 Tagore Lane
Singapore (787476)',
'Tel: +65 6749 9988',
'Fax: +65 6749 4321',
'Email: sales#alh.com.sg',
'Website: http://www.alh.com.sg/',
'Catergory: Alcoholic Beverage, Bottled Beverage, Spirit / Liquor / Hard Liquor, Wine, Distributor, Exporter, Importer, Supplier'
Please excuse if the question seems to be novice, i am just very new to python,
Thanks !!!
The following targets the two javascript objects housing mapping info about companies names, categories and the shown tags e.g. bakery product. More more detailed info on the use of regex and splitting item['category'] - see my SO answer here.
It handles unquoted keys with hjson library.
You end up with a dict whose keys are the company names (I use permalink version of name, over name, as this should definitely be unique), and whose values are a tuple with 2 items. The first item is the company page link; the second is a list of the given tags e.g. bakery product, alcoholic beverage). The logic is there for you to re-organise as desired.
import requests
from bs4 import BeautifulSoup as bs
import hjson
base = 'https://www.sfma.org.sg/member/info/'
p = re.compile(r'var tmObject = (.*?);')
p1 = re.compile(r'var ddObject = (.*?);')
r = requests.get('https://www.sfma.org.sg/member/category/manufacturer')
data = hjson.loads(p.findall(r.text)[0])
lookup_data = hjson.loads(p1.findall(r.text)[0])
name_dict = {item['id']:item['name'] for item in lookup_data['category']}
companies = {}
for item in data['tmember']:
companies[item['permalink']] = (base + item['permalink'], [name_dict[i] for i in item['category'].split(',')])
print(companies)
Updating for your additional request at end (Address info etc):
I then loop companies dict visiting each company url in tuple item 1 of value for current dict key; extract the required info into a dict, which I add the category info to, then update the current key:value with the dictionary just created.
import requests
from bs4 import BeautifulSoup as bs
import hjson
base = 'https://www.sfma.org.sg/member/info/'
p = re.compile(r'var tmObject = (.*?);')
p1 = re.compile(r'var ddObject = (.*?);')
r = requests.get('https://www.sfma.org.sg/member/category/manufacturer')
data = hjson.loads(p.findall(r.text)[0])
lookup_data = hjson.loads(p1.findall(r.text)[0])
name_dict = {item['id']:item['name'] for item in lookup_data['category']}
companies = {}
for item in data['tmember']:
companies[item['permalink']] = (base + item['permalink'], [name_dict[i] for i in item['category'].split(',')])
with requests.Session() as s:
for k,v in companies.items():
r = s.get(v[0])
soup = bs(r.content, 'lxml')
tel = soup.select_one('.w3-text-sfma ~ p:contains(Tel)')
fax = soup.select_one('.w3-text-sfma ~ p:contains(Fax)')
email = soup.select_one('.w3-text-sfma ~ p:contains(Email)')
website = soup.select_one('.w3-text-sfma ~ p:contains(Website)')
if tel is None:
tel = 'N/A'
else:
tel = tel.text.replace('Tel: ','')
if fax is None:
fax = 'N/A'
else:
fax = fax.text.replace('Fax: ','')
if email is None:
email = 'N/A'
else:
email = email.text.replace('Email: ','')
if website is None:
website = 'N/A'
else:
website = website.text.replace('Website: ','')
info = {
# 'Address' : ' '.join([i.text for i in soup.select('.w3-text-sfma ~ p:not(p:nth-child(n+4) ~ p)')])
'Address' : ' '.join([i.text for i in soup.select('.w3-text-sfma ~ p:nth-child(-n+4)')])
, 'Tel' : tel
, 'Fax': fax
, 'Email': email
,'Website' : website
, 'Categories': v[1]
}
companies[k] = info
Example entry in companies dict:

Finding multiple accounts under the same name for Python bank system

In my bank system I have a set of customer accounts but for one name Adam Smith he has two accounts:
def load_bank_data(self):
# the customers in the bank system
account_no = 1234
customer_1 = CustomerAccount("Adam", "Smith", 14, "Wilcot Street", "Bath", "B5 5RT", account_no, "Current", 2500.00)
self.accounts_list.append(customer_1)
account_no += 5678
customer_2 = CustomerAccount("David", "White", 60, "Holburn Viaduct", "London", "EC1A 2FD", account_no, "Savings", 3200.00)
self.accounts_list.append(customer_2)
account_no += 3456
customer_3 = CustomerAccount("Alice", "Churchil", 55, "Cardigan Street", "Birmingham", "B4 7BD", account_no, "Current", 18000.00)
self.accounts_list.append(customer_3)
account_no += 6789
customer_4 = CustomerAccount("Ali", "Abdallah", 44, "Churchill Way West", "Basingstoke", "RG21 6YR", account_no, "Savings", 40.00)
self.accounts_list.append(customer_4)
account_no += 1987
customer_5 = CustomerAccount("Adam", "Smith", 44, "Churchill Way West", "Basingstoke", "RG21 6YR", account_no, "Savings", 5000.00)
self.accounts_list.append(customer_5)
I created a function so when many customer accounts under the same first and last name have been found, it should add all those bank account balances together and print out the final total. (The input is where I type the customer to find multiple accounts for:
def sum_of_all_money(self):
try:
find_customer = input("Enter the surname of the customer to find total sum of money for: ")
for find_customer in self.accounts_list:
find_customer = find_customer.get_balance() + find_customer.get_balance()
print(find_customer)
except SyntaxError as e:
print(e)
This is only just finding one Adam Smith account at the bottom as customer 5 but it doesn't detect the other Adam Smith account as customer 1 and it just adds customer 5 twice giving me an output of 1000.00 which isn't right, what am I doing wrong?
Your code has some flaws, currently it will only loop over your list and always overwrite find_customer with the current balance of the customer * 2.
You need to filter for the right name which was input, try it like this:
try:
find_customer = input("Enter the surname of the customer to find total sum of money for: ")
find_customer_balance = 0
for customer in self.accounts_list:
if customer.get_surname() == find_customer:
find_customer_balance += customer.get_balance()
print(find_customer)
print(find_customer_balance)
except SyntaxError as e:
print(e)

Assign Class attributes from list elements

I'm not sure if the title accurately describes what I'm trying to do. I have a Python3.x script that I wrote that will issue flood warning to my facebook page when the river near my home has reached it's lowest flood stage. Right now the script works, however it only reports data from one measuring station. I would like to be able to process the data from all of the stations in my county (total of 5), so I was thinking that maybe a class method may do the trick but I'm not sure how to implement it. I've been teaching myself Python since January and feel pretty comfortable with the language for the most part, and while I have a good idea of how to build a class object I'm not sure how my flow chart should look. Here is the code now:
#!/usr/bin/env python3
'''
Facebook Flood Warning Alert System - this script will post a notification to
to Facebook whenever the Sabine River # Hawkins reaches flood stage (22.3')
'''
import requests
import facebook
from lxml import html
graph = facebook.GraphAPI(access_token='My_Access_Token')
river_url = 'http://water.weather.gov/ahps2/river.php?wfo=SHV&wfoid=18715&riverid=203413&pt%5B%5D=147710&allpoints=143204%2C147710%2C141425%2C144668%2C141750%2C141658%2C141942%2C143491%2C144810%2C143165%2C145368&data%5B%5D=obs'
ref_url = 'http://water.weather.gov/ahps2/river.php?wfo=SHV&wfoid=18715&riverid=203413&pt%5B%5D=147710&allpoints=143204%2C147710%2C141425%2C144668%2C141750%2C141658%2C141942%2C143491%2C144810%2C143165%2C145368&data%5B%5D=all'
def checkflood():
r = requests.get(river_url)
tree = html.fromstring(r.content)
stage = ''.join(tree.xpath('//div[#class="stage_stage_flow"]//text()'))
warn = ''.join(tree.xpath('//div[#class="current_warns_statmnts_ads"]/text()'))
stage_l = stage.split()
level = float(stage_l[2])
#check if we're at flood level
if level < 22.5:
pass
elif level == 37:
major_diff = level - 23.0
major_r = ('The Sabine River near Hawkins, Tx has reached [Major Flood Stage]: #', stage_l[2], 'Ft. ', str(round(major_diff, 2)), ' Ft. \n Please click the link for more information.\n\n Current Warnings and Alerts:\n ', warn)
major_p = ''.join(major_r)
graph.put_object(parent_object='me', connection_name='feed', message = major_p, link = ref_url)
<--snip-->
checkflood()
Each station has different 5 different catagories for flood stage: Action, Flood, Moderate, Major, each different depths per station. So for Sabine river in Hawkins it will be Action - 22', Flood - 24', Moderate - 28', Major - 32'. For the other statinos those depths are different. So I know that I'll have to start out with something like:
class River:
def __init__(self, id, stage):
self.id = id #station ID
self.stage = stage #river level'
#staticmethod
def check_flood(stage):
if stage < 22.5:
pass
elif stage.....
but from there I'm not sure what to do. Where should it be added in(to?) the code, should I write a class to handle the Facebook postings as well, is this even something that needs a class method to handle, is there any way to clean this up for efficiency? I'm not looking for anyone to write this up for me, but some tips and pointers would sure be helpful. Thanks everyone!
EDIT Here is what I figured out and is working:
class River:
name = ""
stage = ""
action = ""
flood = ""
mod = ""
major = ""
warn = ""
def checkflood(self):
if float(self.stage) < float(self.action):
pass
elif float(self.stage) >= float(self.major):
<--snip-->
mineola = River()
mineola.name = stations[0]
mineola.stage = stages[0]
mineola.action = "13.5"
mineola.flood = "14.0"
mineola.mod = "18.0"
mineola.major = "21.0"
mineola.alert = warn[0]
hawkins = River()
hawkins.name = stations[1]
hawkins.stage = stages[1]
hawkins.action = "22.5"
hawkins.flood = "23.0"
hawkins.mod = "32.0"
hawkins.major = "37.0"
hawkins.alert = warn[1]
<--snip-->
So from here I'm tring to stick all the individual river blocks into one block. What I have tried so far is this:
class River:
... name = ""
... stage = ""
... def testcheck(self):
... return self.name, self.stage
...
>>> for n in range(num_river):
... stations[n] = River()
... stations[n].name = stations[n]
... stations[n].stage = stages[n]
...
>>> for n in range(num_river):
... stations[n].testcheck()
...
<__main__.River object at 0x7fbea469bc50> 4.13
<__main__.River object at 0x7fbea46b4748> 20.76
<__main__.River object at 0x7fbea46b4320> 22.13
<__main__.River object at 0x7fbea46b4898> 16.08
So this doesn't give me the printed results that I was expecting. How can I return the string instead of the object? Will I be able to define the Class variables in this manner or will I have to list them out individually? Thanks again!
After reading many, many, many articles and tutorials on class objects I was able to come up with a solution for creating the objects using list elements.
class River():
def __init__(self, river, stage, flood, action):
self.river = river
self.stage = stage
self.action = action
self.flood = flood
self.action = action
def alerts(self):
if float(self.stage < self.flood):
#alert = "The %s is below Flood Stage (%sFt) # %s Ft. \n" % (self.river, self.flood, self.stage)
pass
elif float(self.stage > self.flood):
alert = "The %s has reached Flood Stage(%sFt) # %sFt. Warnings: %s \n" % (self.river, self.flood, self.stage, self.action)
return alert
'''this is the function that I was trying to create
to build the class objects automagically'''
def riverlist():
river_list = []
for n in range(len(rivers)):
station = River(river[n], stages[n], floods[n], warns[n])
river_list.append(station)
return river_list
if __name__ == '__main__':
for x in riverlist():
print(x.alerts())

Resources