陣列的複製
- Python的陣列跟java類似,直接用「=」只是復製了位置(即call by reference)
- 若要進行複製要使用copy()的函數
- Python的陣列跟java的ArrayList一樣,可以放入不同型態的資料
listone = [{'a':"oneData" , "two":"twoData"} , 1 ,2 ,3 , “abc”]
- 上圖的例子,在陣列裡有字典的資料[0]、integer[1,2,3],string[4]
- 若直接用 listtwo = listone 只複製了參考,即兩個陣列的資料是共用的(記憶體位置相同)
- 而python的copy()分成淺度跟深度兩種
- 淺度copy
- 使用copy()或[:]的語法
listtwo = listone.copy()
listtwo = listone[:]
- 此種做法,對於一般的int或string就會把值copy一份出來,但字典({'a':"oneData" , "two":"twoData"})仍是只複製參考
- 深度copy
- 需import copy,使用copy的函式 deepcopy
import copy;
copy.deepcopy(listone)
- 此種做法,連字典({'a':"oneData" , "two":"twoData"})都會複製一份出來
陣列的排序
- Python在陣列資料的sort上已經提供了基本的sort和sorted函式,包含一般的數值、字串的排序
- 然而,在字串的排序上,它是使用ASCII碼,意即會有大小寫的問題
listone = ["abc" , "btest" , "Btest", "ctest"]
兩種方法皆有相同結果
1. listone.sort()
2. sorted(listone);
//其它應用(直接輸入數值)
sorted((5,9,1,3))
- 上述陣列經過sort前後的結果如下
- 若要無關大小寫進行排序,sorted()函式有提供此作法,只要傳入參數「key=str.lower」即可
listone = sorted(listone, str.lower)
- 而sorter的第二個參數 「key=」還有很多用法,可在參照網路資料謝謝 :D
亂數(Random)
- Random函數提供相當多的用法,例如隨機亂數、隨機浮點數、隨機選擇字元(串)、洗牌等功能
- 需要import random
- 隨機亂數 (可額外加上print印出結果)
- 隨機挑選0~100的偶數
random.randrange(0,100,2)
>>>48
- 隨機浮點數
- 隨機產生0~10的浮點數
random. uniform (0,10)
>>9.148038516794944
- 隨機選擇字元(串)
- 可從一個串列中隨機選擇一個結果
random.choice("abcdefg")
>>>b
listone = ["abc" , "btest" , "Btest", "ctest"]
random.choice(listone)
>>>abc
- 隨機選擇並重組
- 從一個串列中選擇指定數量的內容,並重新組成新串列
listone = ["abc" , "btest" , "Btest", "ctest"]
random.sample(listone,2)
>>>["btest" ,"ctest"]
- 亂數重組陣列內容(洗牌)
- 將串列所有的內容重新排序
listone = ["abc" , "btest" , "Btest", "ctest"]
random.shuffle(listone)
>>>[" Btest " , " abc " , "btest", "ctest"]
定義新的資料結構
- 對於資料結構當中,python都已經提供許多好用的結構(ex:字典key-value、陣列等)
- 若這些結構已經符合您的需求,不應在額外自行建立新的資料結構(違反了python快速開發的精神)
- 若對一些特別的需求,在使用上較不方便(例如堆疊Stack),可依目前的資料結構產生一個簡單的堆疊class(類似在java中用ArrayList做出堆疊的功能)
- 如此可以增加程式可讀性,也可使用內建的資料結構
- 以上僅僅是舉例,因為在新版的python中,list就有提供pop的功能,直接使用append和pop就能做到堆疊的資料結構
存取檔案的方法
- 通常使用open(filename, mode)來開啟檔案
- mode代表要用何種模式開啟檔案,r(唯讀)、w(可寫入)、a(要在檔案尾加東西)、r+(可讀可寫),default為r
- 在windows的系統上,mode多了b(二元檔),表示要以二元模式(binary mode)開啟檔案
- 文字檔的終止字元(end of line)在檔案讀寫時會被修改,對於一般的ASCII文字檔沒有影響,但若是像JPEG或*.exe之類的二元檔就會產生問題
- 讀寫檔案的方式
f = open("testnote.txt","r")
- read(int) 輸入參數為要讀取的字元數,若不輸入數值,會將檔案所有內容轉換成string出來,要小心檔案內容過大的問題
- readline() 則是將檔案內容一行行的讀取出來
- write(string) 是將string寫入到檔案的最後面
- 存取檔案就像是一個指標在file裡遊走,目前指標的位置在那,之後進行的操作(write、read)都會在此處進行
- tell() 可以得知目前指標位在file何處
- seek(int) 可以改變目前指標的位置
- 記得使用完檔案後,需呼叫close()來關閉檔案
存取檔案的方法 Part 2
- 在python的檔案處理,有三個sys.stdin、sys.stdout、sys.stderr,分別代表標準輸入、輸出與錯誤
- 印出檔案內容前3行與後3行
- 計算單詞”python”在文件的出現次數
content = f.read()
print (content.count("python"))
- 透過sys.argv取得傳入的參數,藉此來得到要處理的檔案名稱
inputFileName = sys.argv
print (inputFileName)
- 由上述程式可得到傳入參數的陣列,可藉此得到要處理的文件名稱(切記,傳入的參數index從1開始,0是執行的python *.py檔名)
存取檔案的方法 (fileinput)
- fileinput可更簡單的進行檔案的操作,它可以尋訪檔案所有的內容,不同點在於他不是將所有內容讀取成list,而是產生了readlines的物件
- 常用的函式如下
- fileinput.input(path) ,找到可存取的檔案對象,若沒有輸入參數,會從輸入的參數中找資料
- fileinput .filename(),印出檔案的名稱
- fileinput .lineno(),印出目前指標所在的行數
- fileinput .file lineno (),印出檔案所有的行數
- fileinput .isfirstline(),判斷指標是否在第一行
- 若沒有在input()輸入參數,會去抓執行python所輸入的參數(下述程式,會執行testnote.txt與testnote_2.txt兩個檔案)
C:\> Python fileProcessing.pytestnote.txttestnote_2.txt
資料夾與檔案的處理
- 若程式需要讀取一資料夾下所有的檔案,可用以下程式處理
- os.listdir(str) 會回傳指定路徑下所有的檔案
- os.curdir 是一個參數,會回傳當下的路徑
- 上述程式用兩種方式呼叫
Glob(用於匹配多個檔案)
- 採用上述的方法,只能輸入特定的檔案,若要匹配多個檔案(ex:*.txt),便無法達成
- 透過glob,便可以尋找大量相似的資料
- 上述程式除了使用glob之外,還用到三個重要的概念,reduce、map與filter
reduce
- 可以重覆進行函式呼叫的操作,其函式定義如下
reduce(func_handler, value_list, init_value)
- func_handler :要重覆呼叫的function (像是指標函式的概念,把函式傳進去)
- value_list :要處理的list資料
- init_value :初始值
- 如上所述,reduce會依序取出list前兩個參數,並執行函式的動作,並回傳一新的結果,再與下一個值繼續處理。
- 例:現在有一個陣列有1~10的值,要求出陣列內值的總合
- 最基本的做法,就是用for迴圈將值全部讀取出來,並用一變數加其總合
- 而採用reduce,可以把加總這個重覆的動作寫成函式,來處理上述的動作
- 處理流程:
- 會依序取出list前兩個參數 => sum(0,1)
- 回傳得到新結果=> sum(0,1) = 1
- 再與下一個值繼續處理 => sum(1, 2) ,1是前一次的結果
- 例:現在有一組資料[(1,”a”,3),(2,”b”,6),(3,”c”,9),(4,”d”,12)],我們要將資料處理並得到(1+2+3+4, ”abcd”, 3*6*9*12)結果,程式可寫成如下
- 處理流程:
- 會依序取出list前兩個參數 => sum( (1,”a”,3) , (2,”b”,6) )
- 回傳得到新結果=> sum( (1,”a”,3) , (2,”b”,6) ) = (3,”ab”,18)
- 再與下一個值繼續處理 => sum((3,”ab”,18), (3,”c”,9)),(3,”ab”,18),是前一次的結果
- 因此,若看到程式需要重覆呼叫某個函式來計算結果的話,可以改用reduce來簡化程式碼
map
- 與reduce差別在於,每一次的結果獨立,會回傳一個list(要用list(…)轉回來)
map(func_handler, value_list)
func_handler :要重覆呼叫的function (像是指標函式的概念,把函式傳進去)
value_list :要處理的list資料(可傳多個list)
- Reduce傳進去的function之所以有兩個參數,是因為會把上一次結果和下一個值做處理
- 而map本身結果都是獨立的,因此參數僅需一個(也可一個以上,那map就必需多傳一個list進去才有辦法處理)
- 例:現在有二組資料[(1,3),(2,6),(3,9),(4,12)]、[1,10,100,1000],我們要將資料處理讓兩組對應的資料相加與相乘的結果[(1+1,1*1), (2+10, 2*10) , (3+100, 3*100) , (4+1000, 4*1000)]
- map(...)處理完的結果,記得要用list(…)將結果轉回list的格式
filter
- 會將list的所有參數丟進function裡判斷,並回傳符合條件的結果,並組成list
map(func_handler, value_list…)
func_handler :要重覆呼叫的function (需要回傳boolean的function)
value_list :要處理的list資料(可傳多個list)
- 例:現在有一個陣列有1~10的值,要找出有大於5的值並傳回list
- 回到一開始的程式,見下面程式結果
- 傳進reduce的operator.add 其實只是python預先定義好的加總函式,其動作如下
- 而glob.glob的目的,就是依輸入的內容,找出符合其條件的所以檔案名稱,因此輸入的參數為「*.txt」,則glob.glob就會依此條件找出所有的txt檔案
- 因此上述的程式流程
- 經由map(glob.glob, sys.argv)將輸入的參數依續值行glob.glob函式,找出符合的檔案名稱
- 在經由reduce(operator.add , map(…))將map的結果轉回list
- 此行程式改用list(map(…))也有相同結果
進階檔案處理
- 將檔案內容拆成key-value
- 假設原始檔案內容如下,要將它拆開成一個key-value的list
- 程式碼如下,透過string的split功能,透過關鍵字「,」將一行字串拆成兩部份
