如何开发亲戚计算器
這是M小白實(shí)驗(yàn)室第一篇娛樂性科普文章
筆者博客:mwhitelab.com
筆者公眾號(hào):技術(shù)雜學(xué)鋪
又到了過年的時(shí)候,每到這個(gè)時(shí)候,你總是能見到自己幾乎沒印象但父母就是很熟的親戚。
而且關(guān)系凌亂到你自己都說不清。
不信?那就來幾道測(cè)試題。
2019年親戚關(guān)系測(cè)試題正式開始。請(qǐng)完成如下填空。
參考答案如下:
啥?
由于不知道該如何稱呼,面對(duì)陌生的親戚時(shí),我們只能說一句“您好”,附帶一個(gè)尷尬又不失禮貌的微笑。
BUT!?作為21世紀(jì)的資深網(wǎng)民(手機(jī)重度依賴患者),我們應(yīng)該使用新時(shí)代的技術(shù)來解決這個(gè)尷尬的局面。那就是使用軟件——親戚關(guān)系計(jì)算器。
在微信小程序中搜索“親戚計(jì)算器”會(huì)顯示很多類似的程序。
操作界面和普通的計(jì)算器類似,不過數(shù)字和加減乘除鍵都變成了“父” “母” “兄” “姐” 這樣的關(guān)系。
以后遇見類似有不確定該如何稱呼的親戚,直接這樣用程序就可以了。
再BUT!?作為21世紀(jì)的新型人才(這個(gè)詞是我現(xiàn)想的,我也不知道是啥意思),我們不能只能滿足于使用,更應(yīng)該探求其本質(zhì),了解親戚關(guān)系計(jì)算器是如何實(shí)現(xiàn)的。
實(shí)現(xiàn)方法一:死記硬背法
| 關(guān)系 | 稱謂 |
| 父親的父親 | 爺爺 |
| 父親的母親 | 奶奶 |
| 父親的姐姐 | 姑媽 |
| 父親的妹妹 | 姑媽 |
| …… | …… |
該方法嘗試記下所有親戚關(guān)系的結(jié)果,當(dāng)用戶想要查詢某一種關(guān)系時(shí),直接查表。
假設(shè)親戚之間的關(guān)系只有父、母、兄、弟、姐、妹、子、女八種。(先不考慮夫妻關(guān)系)
那么像父親的父親,哥哥的女兒這樣簡單的 “XX的XX” 的關(guān)系有 8*8 = 64種可能,而 “XX的XX的XX” 有8*8*8 = 512種可能,四個(gè)關(guān)系的有4096種可能!如此大量的關(guān)系,光是把這些可能一個(gè)一個(gè)地列舉出來就會(huì)讓程序員精神崩潰。
然而這樣的死記硬背法是可行的,之前我們看到的微信小程序(其源代碼已公布在github上)就是用這個(gè)方法來實(shí)現(xiàn)的:
我們先對(duì)關(guān)系進(jìn)行簡化,比如在 ‘我’ 是男性的情況下,那么‘我的兒子的父親的XX’在正常情況下就可以化簡成 ‘我的XX’。
再比如 母親的丈夫 = 我的父親,兄弟的父母=我的父母,姐姐的姐姐 = 姐姐等等。
接著,我們?nèi)藶榻o出六七百條最常用的關(guān)系和其對(duì)應(yīng)的稱謂。任何一條用戶輸入的關(guān)系,其化簡后如果在已知的六七百條關(guān)系中,我們則返回其對(duì)應(yīng)的稱謂,否則,返回不知道。
實(shí)現(xiàn)方法二:網(wǎng)狀圖
在親戚關(guān)系中,所有的名詞可以分為兩類。
一類是稱謂,也就是我們?nèi)绾畏Q呼其他人的,如父親、母親、爺爺、姑姑、舅舅等。
另一類是基礎(chǔ)關(guān)系,是稱謂的子集,由父親、母親、兒子、女兒、哥哥、弟弟、姐姐、妹妹、丈夫、妻子,這十個(gè)詞組成。任何一個(gè)稱謂都可以由基礎(chǔ)關(guān)系來表達(dá)。
如 爺爺 = 父親的父親;姥爺 = 母親的父親;太爺爺 = 父親的父親的父親。
圓角長方形框內(nèi)為稱謂,箭頭為基礎(chǔ)關(guān)系(先不考慮丈夫與妻子這兩個(gè)關(guān)系)。我們可以用如下圖來表示“我”的親戚關(guān)系:
我們對(duì)圖中的每一個(gè)圓角長方形(稱謂)計(jì)算其八種關(guān)系(父母兒女兄弟姐妹)。
比如,對(duì)于上圖,我們接著計(jì)算父親和母親的八種關(guān)系對(duì)應(yīng)的人,獲得如下圖:
之后對(duì)于得到的這張圖,接著計(jì)算每個(gè)圓角長方形(稱謂)對(duì)應(yīng)的關(guān)系, 不斷地畫下去,可以得到一張巨大的網(wǎng)狀圖。
這張網(wǎng)狀圖可以無限延伸(如父親 的 父親 的 父親 的 父親……),我們根據(jù)實(shí)際情況,將網(wǎng)狀圖擴(kuò)展到足夠用的地步就行了。
關(guān)系網(wǎng)
網(wǎng)狀圖的每一個(gè)稱謂和關(guān)系都是我們?nèi)藶榇_定了。不過其工作量遠(yuǎn)遠(yuǎn)小于“死記硬背法”。因?yàn)閷?duì)于一個(gè)經(jīng)過四個(gè)關(guān)系的問題,如:父親的兒子的父親的父親=爺爺,母親的母親的女兒的父親=姥爺,一個(gè)很小的網(wǎng)狀圖就能確定這個(gè)問題的結(jié)果。而“死記硬背法”則需要記錄下所有 “XX的XX的XX的XX” 對(duì)應(yīng)的結(jié)果才行。
網(wǎng)狀圖如何實(shí)現(xiàn)
不懂編程的朋友可跳過本節(jié)往下看。
C語言可以使用結(jié)構(gòu)體來表示稱謂,用指針來表示關(guān)系(這里沒有考慮父親的兒子可能是自己,哥哥,弟弟多種可能)。
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寫一個(gè)簡單的示意程序,具體代碼見github:
1.建立數(shù)據(jù)庫(該工作量十分龐大,這里只展示幾個(gè)例子):
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.建立中文名與變量的對(duì)應(yīng)關(guān)系:
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# 考慮返回值可能不止一個(gè) 如父親的兒子可能為[‘我’,‘哥哥’,‘弟弟’] 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.使用一個(gè)函數(shù),封裝所有操作:
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(‘我的父親的兒子的父親’) | [‘父親’] |
?
一些細(xì)節(jié)
首先,是性別:如果‘我’是女性,那么‘我的父親的兒子’可以為[‘哥哥’,‘弟弟’],而不可以包含‘我’。(上述代碼沒實(shí)現(xiàn))
另外,關(guān)于夫妻關(guān)系:在正常情況下,男性稱謂只可以有‘妻子’,女性稱謂只可以有‘丈夫’。(上述代碼沒實(shí)現(xiàn))
第三,多種可能:‘我的父親的兒子’ 可以是[‘我’,‘哥哥’,‘弟弟’],再若是再往后計(jì)算,如‘我的父親的兒子的兒子’ ,需要同時(shí)考慮‘我的兒子’,‘哥哥的兒子’,‘弟弟的兒子’這三種可能。(上述代碼已實(shí)現(xiàn))
?
最后,給出一個(gè)線上的親戚關(guān)系計(jì)算器。該計(jì)算器為開源代碼,由mumuy開發(fā)。
參考資料
- “親戚關(guān)系計(jì)算器”算法實(shí)現(xiàn)
- “親戚關(guān)系”程序github源代碼
總結(jié)
- 上一篇: 换行符与回车符
- 下一篇: 随机数生成器(RNG, random n