如何开发亲戚计算器
這是M小白實驗室第一篇娛樂性科普文章
筆者博客:mwhitelab.com
筆者公眾號:技術雜學鋪
又到了過年的時候,每到這個時候,你總是能見到自己幾乎沒印象但父母就是很熟的親戚。
而且關系凌亂到你自己都說不清。
不信?那就來幾道測試題。
2019年親戚關系測試題正式開始。請完成如下填空。
參考答案如下:
啥?
由于不知道該如何稱呼,面對陌生的親戚時,我們只能說一句“您好”,附帶一個尷尬又不失禮貌的微笑。
BUT!?作為21世紀的資深網民(手機重度依賴患者),我們應該使用新時代的技術來解決這個尷尬的局面。那就是使用軟件——親戚關系計算器。
在微信小程序中搜索“親戚計算器”會顯示很多類似的程序。
操作界面和普通的計算器類似,不過數字和加減乘除鍵都變成了“父” “母” “兄” “姐” 這樣的關系。
以后遇見類似有不確定該如何稱呼的親戚,直接這樣用程序就可以了。
再BUT!?作為21世紀的新型人才(這個詞是我現想的,我也不知道是啥意思),我們不能只能滿足于使用,更應該探求其本質,了解親戚關系計算器是如何實現的。
實現方法一:死記硬背法
| 關系 | 稱謂 |
| 父親的父親 | 爺爺 |
| 父親的母親 | 奶奶 |
| 父親的姐姐 | 姑媽 |
| 父親的妹妹 | 姑媽 |
| …… | …… |
該方法嘗試記下所有親戚關系的結果,當用戶想要查詢某一種關系時,直接查表。
假設親戚之間的關系只有父、母、兄、弟、姐、妹、子、女八種。(先不考慮夫妻關系)
那么像父親的父親,哥哥的女兒這樣簡單的 “XX的XX” 的關系有 8*8 = 64種可能,而 “XX的XX的XX” 有8*8*8 = 512種可能,四個關系的有4096種可能!如此大量的關系,光是把這些可能一個一個地列舉出來就會讓程序員精神崩潰。
然而這樣的死記硬背法是可行的,之前我們看到的微信小程序(其源代碼已公布在github上)就是用這個方法來實現的:
我們先對關系進行簡化,比如在 ‘我’ 是男性的情況下,那么‘我的兒子的父親的XX’在正常情況下就可以化簡成 ‘我的XX’。
再比如 母親的丈夫 = 我的父親,兄弟的父母=我的父母,姐姐的姐姐 = 姐姐等等。
接著,我們人為給出六七百條最常用的關系和其對應的稱謂。任何一條用戶輸入的關系,其化簡后如果在已知的六七百條關系中,我們則返回其對應的稱謂,否則,返回不知道。
實現方法二:網狀圖
在親戚關系中,所有的名詞可以分為兩類。
一類是稱謂,也就是我們如何稱呼其他人的,如父親、母親、爺爺、姑姑、舅舅等。
另一類是基礎關系,是稱謂的子集,由父親、母親、兒子、女兒、哥哥、弟弟、姐姐、妹妹、丈夫、妻子,這十個詞組成。任何一個稱謂都可以由基礎關系來表達。
如 爺爺 = 父親的父親;姥爺 = 母親的父親;太爺爺 = 父親的父親的父親。
圓角長方形框內為稱謂,箭頭為基礎關系(先不考慮丈夫與妻子這兩個關系)。我們可以用如下圖來表示“我”的親戚關系:
我們對圖中的每一個圓角長方形(稱謂)計算其八種關系(父母兒女兄弟姐妹)。
比如,對于上圖,我們接著計算父親和母親的八種關系對應的人,獲得如下圖:
之后對于得到的這張圖,接著計算每個圓角長方形(稱謂)對應的關系, 不斷地畫下去,可以得到一張巨大的網狀圖。
這張網狀圖可以無限延伸(如父親 的 父親 的 父親 的 父親……),我們根據實際情況,將網狀圖擴展到足夠用的地步就行了。
關系網
網狀圖的每一個稱謂和關系都是我們人為確定了。不過其工作量遠遠小于“死記硬背法”。因為對于一個經過四個關系的問題,如:父親的兒子的父親的父親=爺爺,母親的母親的女兒的父親=姥爺,一個很小的網狀圖就能確定這個問題的結果。而“死記硬背法”則需要記錄下所有 “XX的XX的XX的XX” 對應的結果才行。
網狀圖如何實現
不懂編程的朋友可跳過本節往下看。
C語言可以使用結構體來表示稱謂,用指針來表示關系(這里沒有考慮父親的兒子可能是自己,哥哥,弟弟多種可能)。
struct node {struct node *father; struct node *mother; struct node *big_bro; struct node *small_bro; struct node *big_sister; struct node *small_sister; struct node *son; struct node *daughter; };python可以使用字典。這里主要用python寫一個簡單的示意程序,具體代碼見github:
1.建立數據庫(該工作量十分龐大,這里只展示幾個例子):
me = {'f':'父親','m':'母親','bb':'哥哥','sb':'弟弟','bs':'姐姐','ss':'妹妹','son':'兒子','dau':'女兒'} father = {'f':'爺爺','m':'奶奶','bb':'伯父','sb':'叔叔','bs':'姑媽','ss':'姑媽','son':['我','哥哥','弟弟'],'dau':['我','姐姐','妹妹']} mother = {'f':'姥爺','m':'姥姥','bb':'大舅','sb':'小舅','bs':'大姨','ss':'小姨','son':['我','哥哥','弟弟'],'dau':['我','姐姐','妹妹']} …………2.建立中文名與變量的對應關系:
name2var = {'我':me,'父親':father,'母親':mother,'哥哥':big_bro,\'弟弟':small_bro,'姐姐':big_sister,'妹妹':small_sister,\'兒子':son,'女兒':daughter} relation2char = dict(zip(me.values(), me.keys()))import numpy as np# 考慮返回值可能不止一個 如父親的兒子可能為[‘我’,‘哥哥’,‘弟弟’] def returnNext(names,relation):return_name = []for name in names:return_name.append(name2var[name][relation2char[relation]])return list(set(np.array(return_name).flatten()))3.使用一個函數,封裝所有操作:
def getName(relation_name):relationships = relation_name.split('的')name = [relationships[0]]for relation in relationships[1:]:name = returnNext(name,relation)return name4. 使用:
| 輸入 | 輸出 |
| getName(‘我的父親的兒子’) | [‘哥哥’, ‘我’, ‘弟弟’] |
| getName(‘我的母親的女兒’) | [‘姐姐’, ‘我’, ‘妹妹’] |
| getName(‘我的父親的兒子的父親’) | [‘父親’] |
?
一些細節
首先,是性別:如果‘我’是女性,那么‘我的父親的兒子’可以為[‘哥哥’,‘弟弟’],而不可以包含‘我’。(上述代碼沒實現)
另外,關于夫妻關系:在正常情況下,男性稱謂只可以有‘妻子’,女性稱謂只可以有‘丈夫’。(上述代碼沒實現)
第三,多種可能:‘我的父親的兒子’ 可以是[‘我’,‘哥哥’,‘弟弟’],再若是再往后計算,如‘我的父親的兒子的兒子’ ,需要同時考慮‘我的兒子’,‘哥哥的兒子’,‘弟弟的兒子’這三種可能。(上述代碼已實現)
?
最后,給出一個線上的親戚關系計算器。該計算器為開源代碼,由mumuy開發。
參考資料
- “親戚關系計算器”算法實現
- “親戚關系”程序github源代碼
總結
- 上一篇: 换行符与回车符
- 下一篇: 随机数生成器(RNG, random n