[英]How to filter a dictionary value (within another dictionary)
我會盡力解釋這個問題,所以請為長篇文章道歉。
首先,我在這里有一個API( http://dev.c0l.in:5984/income_statements/_all_docs ),在這本詞典中還有5000個其他詞典,我可以通過他們的ID訪問( http://dev.c0l.in :5984 / income_statements / 30e901a7b7d8e98328dcd77c369b6ad7 )
到目前為止,我已經創建了一個程序,可以對這些詞典進行排序,並且只打印(到csv)與用戶輸入扇區相關的詞典(例如醫療保健)
但是,我希望能夠實現過濾器搜索,以便程序只打印高於或低於用戶輸入值的語句,例如,僅從(用戶輸入)關閉庫存中檢索數據,並且僅檢索以下公司(<=)a期末股票價值 - 40,000。
我的問題是,我不一定確定如何 。
我理解如何獲取用戶輸入,以及如何訪問字典中的字典,但我不知道如何過濾或低於用戶輸入值。
這是我的代碼的副本,任何指針將不勝感激!
import urllib #Imports the url - library module (older the urllib2 but has some useful decodes if needed)
import urllib2 #Imports the Url- Library module (Most recently updated + used)
import csv #Imports the commands that allows for csv writing/reading
import json #Imports the ability to read/use Json data
import time #Imports the time module - allows the developer to examine benchmarks (How long did it take to fetch data)
import os
income_csv = csv.writer(open("Income Statement_ext.csv", "wb")) #This creates a CSV file and writes functions to it
financial_csv = csv.writer(open("Statement of financial position_ext.csv", "wb"))
#The two csv 'writers' create the headers for the information within the CSV file before the information from the api is added to it
financial_csv.writerow([
('Company name'),
('Non Current Assets'),
('Current Assets'),
('Equity'),
('Non-Current Assets'),
('Current Liabilities')])
income_csv.writerow([
('Company name'),
('Sales'),
('Opening Stock'),
('Purchases'),
('Closing Stock'),
('Expenses'),
('Interest payable'),
('Interest receivable')])
income_url = "http://dev.c0l.in:5984/income_statements/_all_docs"
income_request = urllib2.urlopen(income_url).read()
income_response = json.loads(income_request)
#defines the income url
financial_url = "http://dev.c0l.in:5984/financial_positions/_all_docs"
financial_request = urllib2.urlopen(financial_url).read()
financial_response = json.loads(financial_request)
#defines the financial postion url
count = 0
#sets the count for documents printed to 0
def income_statement_fn():
global count #allows for the count to be kept globally
print ("(Type help if you would like to see the available choices)")
income_user_input = raw_input("Which sector would you like to iterate through in Income Statement?: ").lower()# Asks the user which sector within the chosen statement he/she would like to examine
if income_user_input == "help":
print ("Available sectors are: ")
print ("Technology")
print ("Healthcare")
print ("Industrial goods")
print ("Financial")
print ("Utilities")
print ("Basic materials")
print ("Services")
income_statement_fn()
elif income_user_input == "technology" or income_user_input == "healthcare" or income_user_input == "industrial goods" or income_user_input == "financial" or income_user_input == "utilities" or income_user_input == "basic materials" or income_user_input == "services":
print 'Starting...' # I use this print to set a milestone (if it prints this, everything before it has worked without error)
start = time.clock()
start
for item in income_response['rows']:
is_url = "http://dev.c0l.in:5984/income_statements/" + item['id'] #This combines the api with the array's ID's allowing us to access every document automatically
is_request = urllib2.urlopen(is_url).read() #Opens is_url and reads the data
is_response = json.loads(is_request) #loads the data in json format
if is_response.get ('sector') == income_user_input: #matches the sector the user inputed - allows us to access that dictionary
income_csv.writerow([
is_response['company']['name'],
is_response['company']['sales'],
is_response['company']['opening_stock'],
is_response['company']['purchases'],
is_response['company']['closing_stock'],
is_response['company']['expenses'],
is_response['company']['interest_payable'],
is_response['company']['interest_receivable']]) # The lines of code above write the chosen fields to the csv file
count +=1
print ("filtering statements") + ("( "+" %s "+" )") % count
start
print start
restart_fn()
else:
print ("Invalid input!")
income_statement_fn()
def financial_statement_fn(): # Within this function is the code required to fetch information related to the financial position statement
global count # Allows for the count to be kept globally (outside the function)
print ("(Type help if you would like to see the available choices)")
financial_user_input = raw_input("Which sector would you like to iterate through in financial statements?: ").lower()
if financial_user_input == "help":
print ("Available sectors are: ")
print ("Technology")
print ("Healthcare")
print ("Industrial goods")
print ("Financial")
print ("Utilities")
print ("Basic materials")
print ("Services")
financial_statement_fn()
elif financial_user_input == "technology" or financial_user_input == "healthcare" or financial_user_input == "industrial goods" or financial_user_input == "financial" or financial_user_input == "utilities" or financial_user_input == "basic materials" or financial_user_input == "services":
print 'Starting'
for item in financial_response['rows']:
fs_url = "http://dev.c0l.in:5984/financial_positions/" + item['id']#This combines the api with the array's ID's allowing us to access every document automatically
fs_request = urllib2.urlopen(fs_url).read()
fs_response = json.loads(fs_request)
if fs_response.get ('sector') == financial_user_input:
financial_csv.writerow([
fs_response['company']['name'],
fs_response['company']['non_current_assets'],
fs_response['company']['current_assets'],
fs_response['company']['equity'],
fs_response['company']['non_current_liabilities'],
fs_response['company']['current_liabilities']])
count +=1
print ("printing statements") + ("( "+" %s "+" )") % count
print ("---------------------------------------------------------------------")
print ("finished fetching data")
print ("---------------------------------------------------------------------")
restart_fn()
else:
print ("Invalid Input!")
financial_statement_fn()
def launch_fn():
print ("Please type 'help' if you would like to examine all available options")
launch_user_input = raw_input("Welcome, Which statement would you like to examine?: ").lower()
if launch_user_input == "income" or launch_user_input == "income statement":
income_statement_fn()
elif launch_user_input == "financial" or launch_user_input == "financial statement":
financial_statement_fn()
elif launch_user_input == "help" :
print ("You can use the following commands on this menu: ")
print ("---------------------------------------------------------------------")
print ("Income or Income statement")
print ("Will allow you to retrieve data relating to financial Income statements")
print ("---------------------------------------------------------------------")
print ("Financial or Financial statement")
print ("Will allow you to retrieve data relating to the statement of financial position")
print ("---------------------------------------------------------------------")
launch_fn()
else:
print ("If you would like to look at the available options please type help")
launch_fn()
def restart_fn():
restart_prompt = raw_input("Would you like to examine another statement?: ").lower()
if restart_prompt == 'y' or restart_prompt == 'yes':
launch_fn()
count = 0
elif restart_prompt == 'n' or restart_prompt == 'no':
raise SystemExit("Shutting down....")
def restart_api_down_fn():
print ("Type 'y' or 'yes' to continue, 'n' or 'no' to exit or 'r' or 'reconnect' to test servers again")
restart_prompt_api = raw_input("Would you like to continue anyway?: ").lower()
if restart_prompt_api == 'r' or restart_prompt_api == 'reconnect' or restart_prompt_api == 'test':
api_status_fn()
count = 0
elif restart_prompt_api == 'n' or restart_prompt_api == 'no':
raise SystemExit("Shutting down....")
elif restart_prompt_api == 'y' or restart_prompt_api == 'yes':
print (" Continuing... Programme performance may be severely affected")
launch_fn()
else:
print ("Invalid input...")
restart_api_down_fn()
def api_status_fn():
hostname_income = "http://dev.c0l.in:5984/income_statements"
response_income = os.system("ping -c 1 " + hostname_income)
hostname_financial = "http://dev.c0l.in:5984/financial_positions"
response_financial = os.system("ping -c 1 " + hostname_financial)
global count
count = 0
if response_income == 0:
print hostname_income, 'is up!'
count +=1
else:
print hostname_income, 'is experiencing connection issues!'
if response_financial == 0:
print hostname_financial, 'is up!'
count +=1
else:
print hostname_financial, 'is experiencing connection issues!'
if count == 2:
launch_fn()
elif count == 0:
restart_api_down_fn() # Code only for UNIX SYSTEMS?
#def api_status_fn():
# hostname = "http://dev.c0l.in:5984/income_statements"
# ping = urllib.urlopen(hostname).getcode()
# if ping == "200":
# print 'oh no!'
# add filtering & sorting
api_status_fn()
如果您需要任何其他解釋,請告訴我們,
干杯!
我會說你的代碼很混亂,如果你試圖把它分解一下,你可能會有更多的運氣。 我會嘗試在這個答案結束時提出一些建議。
從根本上說,您需要過濾得到的具體結果。 查看您的代碼,我可以看到以下內容:
elif financial_user_input == "technology" or financial_user_input == "healthcare" or financial_user_input == "industrial goods" or financial_user_input == "financial" or financial_user_input == "utilities" or financial_user_input == "basic materials" or financial_user_input == "services":
print 'Starting'
for item in financial_response['rows']:
fs_url = "http://dev.c0l.in:5984/financial_positions/" + item['id']#This combines the api with the array's ID's allowing us to access every document automatically
fs_request = urllib2.urlopen(fs_url).read()
fs_response = json.loads(fs_request)
if fs_response.get ('sector') == financial_user_input:
此代碼混合了以下職責:
如果您將這些職責分解為單獨的方法,那么您會發現您的代碼更容易推理。 此外,正如我將簡要介紹的那樣,以這種方式拆分可以讓您重新組合不同的部分,以自定義過濾記錄的方式等。
如果它分裂了一點:
def _get_single_record(id):
""" Request an individual financial position.
This does not filter """
... read and return the json decoded data ...
def _record_matches_sector(record, sector):
""" Determine if the record provided matches the sector """
return record['sector'] == sector
def _record_meets_closing_stock_limit(record, limit):
""" Determine if the record provided has a
closing stock of at least limit """
return record['closing stock'] >= limit
def _get_all_filtered_records(ids, sector, limit):
""" Return all financial position records that
match the sector and closing stock limit """
record_generator = (_get_single_record(id) for id in ids)
return (
record for record in record_generator
if _record_matches_sector(record, sector)
and _record_meets_closing_stock_limit(record, limit)
)
這顯然只返回一個生成器,它返回與您的扇區和限制匹配的記錄。 您可以添加更多測試等,但更新代碼以測試每個測試仍然非常手動。 您需要的是一種將一些可選測試應用於record_generator並返回匹配結果的方法。
這在python中非常簡單,因為python將函數視為第一類對象(意味着您可以將它們分配給變量),並且您可以使用lambdas快速創建自定義函數。 這意味着您可以將_get_all_filtered_records
為:
def _make_limit_test(limit):
""" This returns a function which accepts records that meet the limit """
return lambda record: record['closing stock'] >= limit
def _make_sector_test(sector):
""" This returns a function which accepts records that match the sector """
return lambda record: record['sector'] == sector
def _filter_records_by_tests(ids, tests):
""" Returns all the records that pass all the tests """
record_generator = (_get_single_financial_position_record(id) for id in ids)
for record in record_generator:
if all(test(record) for test in tests):
yield record
然后,您可以通過詢問用戶來構建要傳遞的測試列表。 這將是一個足夠的演示,只是為了驗證這種方法是否有效:
def demo_filtering_by_healthcare_and_40k(ids):
tests = [_make_sector_test("healthcare"), _make_limit_test(40000)]
return _filter_records_by_tests(ids, tests)
正如您所看到的,我的方法名稱很長,而且方法很短。 這實際上是個人風格的問題,但我發現以這種方式執行它會使方法顯而易見,並允許您快速理解代碼以驗證它是否與名稱匹配。
所以要包裝它,你要從遠程api請求記錄。 您可以使用列表推導來過濾這些。 列表推導非常強大,允許您獲取源數據並對其進行轉換並對其進行過濾。 閱讀它們會對你有很大幫助。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.