第 19 章 數(shù)據(jù)列表編程

2018-02-24 15:51 更新

如你所見,應(yīng)用就是處理事件以及作出決策,這一過程是計算機程序的基礎(chǔ),而同樣構(gòu)成程序基礎(chǔ)的就是數(shù)據(jù)——程序所要處理的信息。程序中很少只用到像游戲中的成績這樣的單個數(shù)據(jù),更普遍的是使用復(fù)雜數(shù)據(jù)——一些相互關(guān)聯(lián)的數(shù)據(jù)項,必須像設(shè)計應(yīng)用的功能一樣,非常細心地組織這些數(shù)據(jù)。

{%}

本章將探討App Inventor中處理數(shù)據(jù)的方式,并學(xué)習(xí)兩種數(shù)據(jù)類型的基本編程方法,兩種數(shù)據(jù)類型為靜態(tài)數(shù)據(jù)(數(shù)據(jù)的值保持不變)及動態(tài)數(shù)據(jù)(數(shù)據(jù)由用戶生成),然后將學(xué)習(xí)如何處理更為復(fù)雜的包含數(shù)據(jù)的數(shù)據(jù),即數(shù)據(jù)項本身也是一組數(shù)據(jù)。

許多應(yīng)用中都存在這樣復(fù)雜的數(shù)據(jù),如facebook中的好友列表,測試應(yīng)用中的問題及答案列表等等,游戲中也會有角色的列表以及當(dāng)前最高成績的列表。

列表變量的使用如同普通的文本及數(shù)字變量一樣,只是它們不僅僅代表單一的有名稱的存儲單元,而是表示一組相互關(guān)聯(lián)的存儲單元,例如,考慮表19-1中的電話號碼列表。

表19-1 列表變量表示一系列的存儲單元

{%}

使用索引值(index)來訪問列表元素,因此在列表19-1中,index為1時表示第一項111-2222,index為2時表示第二項333-4444,而index為3時表示555-6666。

App Inventor提供了操作這些數(shù)據(jù)的塊,包括數(shù)據(jù)的創(chuàng)建、為數(shù)據(jù)添加元素、從列表中選擇指定的項以及對整個列表的操作,讓我們從創(chuàng)建列表開始。

創(chuàng)建列表變量

在塊編輯器中,使用“initialize global (name) to”塊以及“make a list”塊來創(chuàng)建列表變量。例如,假設(shè)你正在寫一個“一鍵發(fā)送短信”的應(yīng)用,通過點擊一個按鍵向電話號碼列表中的所有成員發(fā)送短信。用如下方式創(chuàng)建一個電話號碼列表:

1. 從塊編輯器的Variables抽屜中拖出一個“initialize global (name)to”塊到應(yīng)用中,如圖19-1。

{%}

圖 19-1 初始化變量的塊

2. 點擊文本“name”,將其改為phoneNumbers,如圖19-2所示。

{%}

圖 19-2 將變量重命名為phoneNumber

3. 從Lists抽屜中拖出“make a list”塊插入初始化變量塊,如圖19-3所示。這是告訴應(yīng)用,要存儲的變量是一個列表,而非單個值。通過點擊“make a list”塊上的藍色增項圖標來指定所需存儲槽的數(shù)量,來增加數(shù)據(jù)項,如圖19-3所示。

{%}

圖 19-3 使用“make a list”塊來定義列表變量phoneNumber

4. 最后,從Text抽屜中拖出文本塊,輸入需要的電話號碼,插入到“make a list”塊的數(shù)據(jù)項插槽中。

{%}

圖 19-4 當(dāng)列表中添加了全部數(shù)據(jù)項,相當(dāng)于開辟了一個新的存儲空間

數(shù)據(jù)項的存儲中可以插入任何類型的數(shù)據(jù),但在本例中,這些數(shù)據(jù)項是文本類型的對象,而不是數(shù)字,因為電話號碼中含有一個破折號“-”,這種非數(shù)字類型的符號無法輸入到數(shù)字塊中,也無法與數(shù)字進行任何運算(而數(shù)字運算必須用到數(shù)字塊)。

圖19-4中所示的塊定義了一個名為phoneNumber的變量,在應(yīng)用啟動時,你定義的任何變量就在此時被創(chuàng)建,而像表19-1中的存儲槽也被同時創(chuàng)建并被填寫上初始值。一旦有了這個列表變量,就可以使用列表中的數(shù)據(jù)開始編程了。

選擇列表項

應(yīng)用中可以使用“select list item”塊,并指定索引值(index)來訪問列表中指定的數(shù)據(jù)項。index代表了該數(shù)據(jù)項在列表中的位置。因此,如果列表中有三個數(shù)據(jù)項,就可以用索引值1、2、3來訪問這些項。圖19-5中顯示了選中列表第二項的塊。

{%}

圖 19-5 選擇列表中的第二項

使用選擇塊“select list item”需要提供兩項參數(shù),首先是要查詢的列表,將其插入選擇塊的第一個插槽中,其次是索引值index,將其插入選擇塊的第二個插槽中。圖19-5中的塊是告訴應(yīng)用從列表phoneNumber中選出第二個元素。如果列表的定義如表19-1的話,俺么選擇的結(jié)果就是“333-4444”。

從列表中選擇數(shù)據(jù)項,這僅僅是第一步,通過選擇可以實現(xiàn)各種操作,下面將舉例說明。

使用Index遍歷列表

許多應(yīng)用中,定義列表的目的是讓用戶可以遍歷(逐個查看)它。第8章總統(tǒng)測驗就是一個很好的例子:用戶點擊“下一題”按鈕,程序從問題劣幣哦啊中選擇下一道題并顯示出來。

但如何實現(xiàn)對下一項的選擇呢?圖19-5中選擇的是列表phoneNumber中的第二項,而遍歷列表時,每次選擇的項目序號是不同的,會根據(jù)當(dāng)前選中項在列表中的位置來確定。因此就需要定義一個變量來表示這個位置,通常用index來作為變量名,初始值通常設(shè)為1(列表中的第一個位置),如圖19-6所示。

{%}

圖 19-6 變量index的初始值為1

當(dāng)用戶設(shè)法移動到下一項時,可以在當(dāng)前的index值上加1來實現(xiàn)變量的遞增,并使用遞增后的值在列表中做選擇。圖19-7中顯示了實現(xiàn)這一點使用的塊。

{%}

圖 19-7 使index值遞增,并用遞增后的值選擇列表項

舉例:遍歷畫筆顏色列表

來看一個例子,用戶可以通過點擊按鈕來為他的房子選擇一種可能的粉刷顏色,每次點擊,按鈕的顏色都會變化。當(dāng)用戶查閱完全部顏色時,再重新回到第一種顏色。

例子中,可以使用基本色,也可以替換成任何一組顏色,關(guān)于顏色的更多信息,可以參見App Inventor文檔(http://appinventor.googlelabs.com/learn/reference/blocks/colors.html)。

第一步是定義一個顏色列表變量,并以顏色為列表項來初始化列表,如圖19-8中所示。

{%}

圖 19-8 用一組顏色為colors列表做初始化

接下來,定義變量index來跟蹤列表的當(dāng)前項位置,初始值為1??梢越o變量一個更有意義的名字,如currentColorIndex,但如果你的應(yīng)用中不需要處理其他更多的列表,用index就好。如圖19-9所示。

{%}

圖 19-9 使用index變量來跟蹤列表當(dāng)前項的位置,初始值為1

用戶通過點擊ColorButton從列表中瀏覽到下一項(顏色),此時,index值遞增,而按鈕的BackgroundColor變?yōu)楫?dāng)前選中的顏色,如圖19-10所示。

{%}

圖 19-10 用戶通過點擊按鈕瀏覽顏色列表——每次點擊都會改變按鈕顏色

先假設(shè)我們已經(jīng)在組件設(shè)計器中將按鈕的背景顏色設(shè)為紅色(Red),第一次點擊按鈕時,index值從初始的1變?yōu)?,按鈕顏色變?yōu)榱斜碇械牡诙棥G色;第二次點擊按鈕時,索引值從2變?yōu)?,按鈕變?yōu)樗{色。

想象一下,下一次的點擊會出現(xiàn)什么情況?

如果你說會出錯,那么你對了!index值將變成4,程序?qū)⒃噲D在列表中選擇第4項,但列表中只有3項,因此程序強行關(guān)閉,或退出,用戶將看到一條如圖19-11中所示的錯誤信息。

{%}

圖 19-11 當(dāng)試圖從一個只有三項的列表中選擇第四項時,程序?qū)⑻崾惧e誤信息

顯然,你不想讓用戶看到這樣的信息,為了避免出現(xiàn)這樣的問題,需要添加一個if塊來檢查是否到達了列表中的最后一項。如果是,將index值設(shè)回1,來顯示第一種顏色,如圖19-12所示。

{%}

圖 19-12 使用if塊檢查索引值index是否大于列表的長度,如果是,將index值重新設(shè)為1

用戶點擊按鈕時,index值遞增,然后檢查它的值是否過大。與index值進行比較的是“l(fā)ength of list”,而不是3,因此,即便是列表中添加了更多的項,程序也能正常運行。通過檢查index是否大于列表長度(而不是與固定的數(shù)字3進行比較),可以消除程序中的代碼相關(guān)性。所謂“代碼相關(guān)性”是一個編程術(shù)語,舉例來說,如果你的應(yīng)用中某些方面的程序?qū)懙眠^于具體,那么當(dāng)你想對某處做出修改時(如,列表的數(shù)據(jù)項),你不得不找到應(yīng)用中所有使用過這個list的地方,并對程序塊進行逐一修改。

正如你所想象得,這種相關(guān)性會讓程序在短時間內(nèi)變得混亂不堪,也會產(chǎn)生更多的錯誤等待你去排查。事實上,在“粉刷彩色房屋”應(yīng)用的設(shè)計中,就在我們剛剛完成的程序中,還存在另一個代碼相關(guān)性問題,你能找出是什么嗎?

如果將顏色列表中的第一項由紅色改為其他顏色,應(yīng)用的運行結(jié)果就不再正確,除非你能記得在組件設(shè)計器中修改ColorButton.BackgroundColor屬性的初始設(shè)定。消除這種代碼相關(guān)性的方法是,將ColorButton.BackgroundColor初始值設(shè)定為顏色列表中的第一項,而不是某個特定的顏色。由于這一修改涉及到程序啟動時的行為,因此需要在應(yīng)用啟動時調(diào)用的Screen.Initialize事件處理程序中進行這一設(shè)定。如圖19-13所示。

{%}

圖 19-13 應(yīng)用啟動時,將按鈕的背景色設(shè)置為顏色列表中的第一項

創(chuàng)建輸入表單及動態(tài)數(shù)據(jù)

前面的“粉刷彩色房屋”應(yīng)用涉及到一個靜態(tài)列表:程序員(也就是你)定義了列表中的元素,除非你親自動手,沒有人能修改這些列表項。不過,多數(shù)情況下,應(yīng)用中要處理動態(tài)列表:最終用戶輸入新的數(shù)據(jù)項而導(dǎo)致數(shù)據(jù)的變化,或者從數(shù)據(jù)庫或web信息源加載新數(shù)據(jù)。本節(jié)將討論一個“隨手記”應(yīng)用:用戶在應(yīng)用中,通過表單輸入筆記,并可預(yù)覽之前所有輸入過的內(nèi)容。

定義動態(tài)列表

如果希望創(chuàng)建一個空列表,可以使用“create empty list”塊來定義,例如,在“隨手記”應(yīng)用中,允許用戶輸入筆記,但在定義列表時,不應(yīng)該有預(yù)定義的數(shù)據(jù)項,具體的定義方法見圖19-14。

{%}

圖 19-14 動態(tài)列表的定義中不應(yīng)該含有任何預(yù)定義數(shù)據(jù)項

添加數(shù)據(jù)項

當(dāng)?shù)谝淮螁討?yīng)用時,notes列表是空的,當(dāng)用戶在表單中輸入數(shù)據(jù)并點擊“保存”按鈕時,新的筆記內(nèi)容將被添加到列表中。表單的設(shè)置非常簡單,如圖19-15所示。

{%}

圖 19-15 用輸入表單想筆記列表中添加新項

當(dāng)用戶輸入一段筆記并點擊“保存”按鈕,應(yīng)用將調(diào)用“add items to list”函數(shù)將新輸入的內(nèi)容添加到列表中,如圖19-16所示。

{%}

圖 19-16 用戶點擊“保存”按鈕時,調(diào)用“add items to list”向列表中添加新內(nèi)容

“add items to list”塊將新的數(shù)據(jù)追加到列表的結(jié)尾,用戶每次點擊“保存”,就添加一條新筆記,在Lists抽屜中可以找到這個塊。特別注意:還有另一個塊“append to list”,它的功能是向一個列表中追加另一個列表,很少會用到這個塊。

顯示列表

對用戶來說,列表變量notes的內(nèi)容是不可見的,還記得之前講過,應(yīng)用中的變量是用來保存那些不需要被用戶看到的信息。圖19-16中的塊實現(xiàn)了一點擊按鈕就添加新項的功能,但用戶看不到任何反饋,除非你在程序中添加顯示列表內(nèi)容的功能。

在應(yīng)用的用戶界面中顯示列表內(nèi)容最簡單的方法就是現(xiàn)實數(shù)字和文本的方法:將列表內(nèi)寫入Label組件的Text屬性,如圖19-17所示。

{%}

圖 19-17 用NotesListLabel的Text屬性顯示筆記列表

可惜這種簡單的顯示方法看起來不夠美觀,列表中所有的項被放置在一對小括號內(nèi),沒有分行,項之間用空格分隔。如圖19-18所示,用戶輸入了第一條筆記“忘記了讓筆記顯示出來”,然后又輸入第二條“顯示結(jié)果被一對括號包圍著!”。

{%}

圖 19-18 列表內(nèi)容的簡單顯示方法

如果學(xué)習(xí)過第13章的“亞馬遜掌上書店”,你對這個問題應(yīng)該熟悉。在第20章中,將學(xué)習(xí)如何用更加復(fù)雜的方式來顯示列表內(nèi)容。

刪除列表項

使用“remove list item”塊可以從列表中刪除某一項。如圖19-19所示。

{%}

圖 19-19 刪除列表項

圖19-19從列表notes中刪除了第2項,但通常我們不希望只刪除某個固定的項(如第2項),而是讓用戶來選擇需要刪除的項。

ListPicker是一個可以用于刪除列表項的用戶界面組件,它與一個按鈕關(guān)聯(lián),當(dāng)點擊按鈕時,ListPicker會顯示列表項,并允許用戶選擇其中的一項。當(dāng)用戶選中后,應(yīng)用就可以將其刪除。

ListPicker有兩個關(guān)鍵事件BeforePicking及AfterPicking,而且每個事件都有兩個重要屬性:Elements及Selection,如表19-2所示,只要理解了這兩個事件及其屬性,ListPicker組件的編程就很容易了。

表19-2 ListPicker組件的兩個關(guān)鍵事件及其屬性

|

事件

|

屬性

BeforePicking:點擊按鈕時觸發(fā)

|

Elements:選中的列表

AfterPicking:用戶做出選擇時觸發(fā)

|

Selection:用戶所選項

|

當(dāng)用戶點擊ListPicker的關(guān)聯(lián)按鈕時,觸發(fā)ListPicker.BeforePicking事件,此時用戶尚未選擇列表項;在ListPicker.BeforePicking事件處理程序中,可以將ListPicker.Elements屬性設(shè)置為一個列表變量,例如,在“隨手記”應(yīng)用中,將Elements屬性設(shè)置為列表notes,如圖19-20。

{%}

圖 19-20 ListPicker的Elements屬性被設(shè)置為列表變量notes

這些塊將列表notes的內(nèi)容顯示在ListPicker中,如果列表中有兩條筆記,其顯示如圖19-21所示。

{%}

圖 19-21 列表notes顯示在ListPicker組件中

當(dāng)用戶從列表中選擇一項時,將觸發(fā)ListPicker.AfterPicking事件,在該事件的處理程序中,可以利用ListPicker.Selection屬性來訪問用戶的所選項。

但是想到“remove item from list”塊需要的是索引值(列表中的位置),不是具體的項,而Selection屬性卻是實際數(shù)據(jù)(一條筆記),不是索引值,ListPicker組件不直接提供對列表索引值的訪問(在App Inventor的后續(xù)版本中將添加此功能)。

變通的方法是利用Lists抽屜中的另一個塊:“index in list”。對于給定的文本,該塊將返回列表中最先與該文本匹配的項的位置,使用“index in list”,ListPicker1.AfterPicking事件處理程序?qū)h除用戶選中的項。如圖19-22所示。

{%}

圖 19-22 使用“index in list”塊找出要刪除項的索引值

AfterPicking事件被觸發(fā)后,ListPicker1.Selection中包含了用戶選中的文本(如“忘記了讓筆記顯示出來”)。我們的目標是找到選中項在列表中的索引值,以便將其刪除。如果用戶選擇的是“忘記了讓筆記顯示出來”,則“index in list”塊將返回1,因為這段文本是列表中的第1項。將索引值保存到變量removeIndex中,并將它用作“remove list item”塊中的index值。

再繼續(xù)閱讀之前,先思考一個問題:這種方法是否總是有效呢?

回答是肯定的,但條件是列表中沒有重復(fù)的項。比如說,用戶輸入的第2條和第10條筆記都是“今天過得太好了!”。如果此時用戶點擊“刪除列表項”按鈕(其實是ListPicker),并選中了第10項,那么被刪除的將是第2項,而非第10項。“index in list”塊只能返回第一個匹配項,然后就停在那里,因此也就找不出應(yīng)該被刪掉的內(nèi)容相同的第10項。需要對列表進行遍歷,并使用適當(dāng)?shù)臈l件判斷(見第18章)來查看是否還有其他匹配項,并將其刪除。

列表中的列表

列表項可以使數(shù)字、文本、顏色、布爾值(true/false),也可以是數(shù)據(jù)(維基:在計算及數(shù)據(jù)處理中,數(shù)據(jù)往往表示一種結(jié)構(gòu),如表格[由行和列組成]、樹[一組有父子關(guān)系的節(jié)點]或者圖形[一組連接起來的節(jié)點]。數(shù)據(jù)通常是測量的結(jié)果,可以被可視化成圖形。),這是一種常見的數(shù)據(jù)結(jié)構(gòu)。例如,一個數(shù)據(jù)的列表可以將第8章總統(tǒng)測試轉(zhuǎn)變?yōu)橐粋€多選題測驗。我們來重溫一下總統(tǒng)測試中數(shù)據(jù)的基本結(jié)構(gòu):一個問題列表和一個答案列表,如圖19-23所示。

{%}

圖 19-23 一個問題列表和一個答案列表

每當(dāng)用戶回答完一個問題,程序通過與AnswerList中的當(dāng)前項進行對比來判斷回答是否正確。

為了實現(xiàn)多選測驗,需要為每個問題提供一個可供選擇答案的列表。多選列表可以表示為一個數(shù)據(jù)列表變量,將三個“make a list”塊放在一個外層“make a list”塊中,來定義這個變量,如圖19-24所示。

{%}

圖 19-24 通過在外層“make a list”塊中插入若干個“make a list”塊來構(gòu)造出一個數(shù)據(jù)列表

變量answerChoices中的每個數(shù)據(jù)項本身也是一個由三個數(shù)據(jù)項組成的列表,如果從answerChoices列表中選擇一項,選擇的結(jié)果將是一個列表?,F(xiàn)在填好多選答案的雙重列表,那么如何向用戶顯示這些數(shù)據(jù)呢?

在“隨手記”應(yīng)用中,使用了一個ListPicker來向用戶顯示選項。假如索引值為currentQuestionIndex,則事件處理程序ListPicker.BeforePicking將寫成圖19-25中顯示的樣子。

{%}

圖 19-25 使用ListPicker向用戶展示多選列表

這些塊將選取并顯示answerChoices中的當(dāng)前項對應(yīng)的子列表,供用戶選擇。如果currentQuestionIndex為1,ListPicker將顯示圖19-26中的列表。

{%}

圖 19-26 向用戶展示第1題的多選答案

用戶選擇之后,用圖19-27中的塊對答案進行檢查。

{%}

圖 19-27 檢查用戶選擇的答案是否正確

這些塊中,用戶從ListPicker中選擇的答案將與正確答案進行比較,而正確答案保存在另一個列表AnswerList中(注意answerChoices只提供選項而不代表答案)。

小結(jié)

你能想到的幾乎每個應(yīng)用中都會用到數(shù)據(jù),理解它們的運行機制是編程的基礎(chǔ),本章探索了一種最常用的編程模式:使用索引變量,從列表的第一項開始,通過變量的遞增實現(xiàn)對每個列表項的處理。如果能理解并在自己的程序中加以運用,那么你的確是一名程序員了。

然后我們講到了列表處理的其他方式,包括一個典型的讓用戶添加并刪除列表項的表單。如此的編程還需要另一個層次的抽象能力,你必須假想數(shù)據(jù)的存在,因為直到用戶輸入某些數(shù)據(jù)之前,這些數(shù)據(jù)都是空的。如果你能理解這一點,你甚至可以考慮辭掉現(xiàn)在的日常工作了。

最后我們介紹了復(fù)雜的數(shù)據(jù)結(jié)構(gòu)——數(shù)據(jù)列表。這顯然是一個不太容易理解的概念,但我們利用一些固定的數(shù)據(jù)對問題進行了探索:多選測驗中的可選擇答案列表。如果你對此以及本章的其余部分都有所掌握,那么你的期末考試題是:使用數(shù)據(jù)列表創(chuàng)建一個應(yīng)用,但要求使用動態(tài)數(shù)據(jù)!一個例子就是允許用戶在應(yīng)用中創(chuàng)建他們自己的多選測驗,這個功能甚至比第10章的出題應(yīng)用還要強大。祝你好運!

在你思考如何處理這些列表時,要知道我們的探索還沒有結(jié)束。在下一章中,我們將繼續(xù)討論并重點講解略有不同的列表循環(huán):對列表中的每一項實施一些列的操作。

以上內(nèi)容是否對您有幫助:
在線筆記
App下載
App下載

掃描二維碼

下載編程獅App

公眾號
微信公眾號

編程獅公眾號