#!/usr/bin/env python # coding: utf-8 # # วิธีทำงานโดยเปิดไฟล์แล้วอ่านทีละบรรทัด (ตอน 2) # เราสามารถใช้วิธี: # ```python # inputfile = open(filename) # for line in inputfile: # work_on_the_line # ``` # เช่นโค้ดข้างล่างเปิดไฟล์ `/usr/share/dict/words` แล้วอ่านทีละบรรทัด โดยที่แต่ละบรรทัดอยู่ในตัวแปร `word` ด้วยคำสั่ง `for word in inputfile:` # # # ### ตัวอย่าง: หาคำที่เป็น Palindrome (คำที่กลับหน้าหลังแล้วเหมือนเดิม) # # In[1]: #หาคำที่เป็น palindrome (คำที่กลับหน้าหลังแล้วเหมือนเดิม) inputfile = open('/usr/share/dict/words') #เปิดไฟล์ที่มีคำภาษาอังกฤษบรรทัดละหนึ่งคำ for word in inputfile: #อ่านเข้ามาทีละบรรทัด เก็บบรรทัดไว้ในตัวแปร word word = word.strip() #strip() จะลบตัวอักษรที่มองไม่เห็น (white spaces) ด้านหน้าและด้านหลังของคำ รวมถึงตัวอักษรขึ้นบรรทัดใหม่ (newline, \n) if len(word) <= 2: #ถ้าคำยาวไม่เกิน 2 ตัวอักษร เราจะไม่นับมันเป็น palindrome continue if word == word[::-1]: #word[::-1] หมายถึงการกลับหลังมาหน้า ดูส่วน "slices" ที่ https://snakify.org/en/lessons/lists/ print(word) # ### ตัวอย่าง: หาคำที่ยาวที่สุด # # # In[2]: inputfile = open('/usr/share/dict/words') max_word = "" #คำที่ยาวที่สุดที่เราเคยเห็น เนื่องจากตอนนี้ยังไม่เห็นสักคำ มันจึงเป็นคำว่างๆไม่มีตัวอักษรอะไร for word in inputfile: word = word.strip() if len(word) > len(max_word): #ถ้าคำที่พึ่งอ่านเข้ามายาวกว่าคำที่ยาวที่สุดที่เราเคยเห็น... max_word = word #...เราก็เปลี่ยนคำที่ยาวทีสุดที่เราเคยเห็นเป็นคำนี้ print(max_word, len(max_word)) #len(x) คือความยาวของ x ว่ามีกี่ตัวอักษร นอกจากนี้ len ยังใช้บอกจำนวนของใน list, dictionary, ฯลฯ ด้วย # เนื่องจากในโค้ดข้างบน เราเปรียบเทียบแบบ if len(word) > len(max_word): คือถ้าคำมีความยาวเท่าๆกัน เราจะจำเฉพาะคำแรกเท่านั้น เพราะเราจะเปลี่ยนคำที่จำก็ต่อเมื่อคำใหม่มีความยาวมากกว่าคำเก่า ถ้าจะหาคำทุกคำที่มีความยาว 24 ตัวอักษรเราก็สามารถหาแบบนี้ตรงๆได้: # In[3]: inputfile = open('/usr/share/dict/words') for word in inputfile: word = word.strip() if len(word) == 24: #ดูเฉพาะคำที่มี 24 ตัวอักษร print(word, len(word)) # บางทีเราอาจจะสนใจคำที่ยาวๆโดยไม่จำเป็นต้องยาวที่สุด เช่นถ้าอยากเห็นคำที่ยาวตั้งแต่ 20 ตัวอักษรขึ้นไปเราก็อาจทำอย่างนี้ได้: # In[4]: inputfile = open('/usr/share/dict/words') long_words = [] #สร้าง list ชื่อ long_words เพื่อเก็บคำยาวๆหลายๆคำ ถ้าไม่คุ้นเคยให้อ่านที่ https://snakify.org/en/lessons/lists/ for word in inputfile: word = word.strip() if len(word) >= 20: #ถ้าคำมี 20 ตัวอักษรขึ้นไป... long_words.append(word) #...ให้เอาคำนั้นไปใส่เพิ่มใน list ที่ชื่อ long_words print(long_words) # ถ้าเราอยากรู้ว่าคำที่มีตัวอักษร 1, 2, 3,..., 24 ตัว มีอย่างละกี่คำเราก็อาจทำตรงๆอย่างนี้ได้ แบบนี้จะมีการอ่านไฟล์ 24 ครั้ง: # In[5]: print("#letters\t#words") #พิมพ์่ชื่อคอลัมน์ให้คนอ่าน for letters in range(1,25): #letters คือจำนวนตัวอักษร เริ่มจาก 1 ไปถึง 25-1 = 24 เพราะเรารู้ว่าคำยาวสุดมี 24 อักษร count = 0 #จำนวนคำที่มี "letters" ตัวอักษร inputfile = open('/usr/share/dict/words') #อ่านรายการคำ หนึ่งบรรทัดมีหนึ่งคำ for word in inputfile: #อ่านไปทีละบรรทัด word = word.strip() #ลบตัวขึ้นบรรทัดใหม่ (\n หรือ new line) if word[0] in "abcdefghijklmnopqrstuvwxyz": #ดูเฉพาะคำที่ขึ้นต้นด้วยอักษรตัวเล็กเท่านั้น ไม่ดูพวกชื่อเฉพาะ if len(word) == letters: #ดูเฉพาะคำที่มีตัวอักษร letters ตัว แล้วเพิ่มจำนวนใน count count = count + 1 print(f"{letters}\t\t{count}") #แสดงผลด้วย f-string (ดู #3 ที่ https://realpython.com/python-string-formatting/) # ### ตัวอย่างฟังก์ชั่น # ฟังก์ชั่นจะทำหน้าที่ทำนองเดียวกับ Blocks ใน Scratch ถ้ายังไม่คุ้นเคยให้ไปดู[ที่นี่](https://snakify.org/en/lessons/functions) # # เราจะป้อนข้อมูล input เข้าไป แล้่วมันจะทำงานหรือสร้าง output ให้เรา # # ถ้าเราต้องทำอะไรยุ่งๆหรือซ้ำๆเราควรจะจัดรูปมันเป็นฟังก์ชั่นเสีย โปรแกรมเราจะได้อ่านง่ายๆ # # ดูตัวอย่างสองสามอันนี้เป็นไอเดีย # # In[6]: def double(x): "รับค่า x เข้าไปแล้วคำนวณค่า 2*x ให้" return(2*x) # In[7]: def is_even(x): "ดูว่า x เป็นเลขคู่หรือไม่" if x % 2 == 0: #ถ้าเศษจากการหารด้วย 2 เป็น 0 ก็แสดงว่าเป็นเลขคู่ return(True) else: return(False) # In[8]: def starts_with_small_letter(word): "ดูว่าตัวอักษรแรกใน word เป็นอักษรตัวเล็กหรือไม่" small_letters = "abcdefghijklmnopqrstuvwxyz" if word[0] in small_letters: return(True) else: return(False) #ถ้าตัวแรกไม่อยู่ใน a-z เราก็ถือว่าคำนั้นไม่ได้ขึ้นต้นด้วยอักษรตัวเล็ก # In[9]: def number_of_words_with_length(n, list_of_words): "ดูคำในไฟล์ list_of_words ว่ามีกี่คำที่มี n ตัวอักษร" inputfile = open(list_of_words) count = 0 for word in inputfile: word = word.strip() if starts_with_small_letter(word): if len(word) == n: count = count + 1 return(count) # In[10]: double(100) #ควรคำนวณออกมาเป็น 200 # In[11]: is_even(15) #ควรเป็น False เพราะ 15 ไม่ใช่เลขคู่ # In[12]: starts_with_small_letter("kangaroo") #ควรเป็น True เพราะ "kangaroo" ขึ้นต้นด้วยอักษรตัวเล็ก # In[13]: number_of_words_with_length(11, "/usr/share/dict/words") #ควรเป็น 23773 เมื่อเทียบกับด้านบน # ลองนับจำนวนคำที่มีตัวอักษรตั้งแต่ 1, 2, 3, ..., 24 อีกที โดยใช้ฟังก์ชั่น number_of_words_with_length() ด้านบน # # ทำแบบนี้โค้ดจะดูสั้นลง แต่ก็ยังอ่านไฟล์หลายรอบเหมือนกัน เราสามารถเขียนโค้ดให้อ่านไฟล์ครั้งเดียวแล้วทำอะไรให้เสร็จไปเลยดังที่จะเขียนต่อไปด้านล่าง # In[14]: #โค้ดดูสั้นลง แต่อ่านไฟล์ 24 ครั้งเหมือนเดิม เพราะทุกครั้งที่ฟังก์ชั่น number_of_words_with_length ทำงานจะมีการอ่านไฟล์ 1 ครั้ง print("#letters\t#words") for letters in range(1,25): count = number_of_words_with_length(letters, "/usr/share/dict/words") print(f"{letters}\t\t{count}") # ตัวอย่างนับคำที่ความยาวต่างๆโดยอ่านไฟล์ครั้งเดียว # In[15]: """ อ่านไฟล์ครั้งเดียว เก็บจำนวนคำที่มีความยาว n อักษรไว้ใน count[n] count ต้องยาว 25 แทนที่จะเป็น 24 เพราะเราต้องการ count[24] ด้วยเพราะคำที่ยาวที่สุดยาว 24 ตัวอักษร ทำแบบนี้เร็วกว่าแบบข้างบนที่อ่านไฟล์ 24 ครั้ง """ print("#letters\t#words") count = [0] * 25 #count เป็น list = [0, 0, 0, ..., 0] มี 0 25ตัว inputfile = open('/usr/share/dict/words') for word in inputfile: word = word.strip() if starts_with_small_letter(word): count[len(word)] += 1 for length in range(1,25): print(f"{length}\t\t{count[length]}") # เราสามารถเอาจำนวนคำใน count[] มาวาดกราฟได้ด้วย matplotlib ดังนี้ จะเห็นว่าคำยาว 9 ตัวอักษรมีจำนวนมากที่สุด: # In[16]: get_ipython().run_line_magic('matplotlib', 'inline') import matplotlib.pyplot as plt lengths = range(1,25) #ความยาวคำตั้งแต่ 1 ถึง 24 ตัวอักษร numwords = count[1:] #count[]เก็บจำนวนคำที่มีความยาว n อักษรไว้ใน count[n] plt.bar(lengths, numwords, align='center', alpha=0.5) plt.xticks(lengths, lengths) plt.title('Number of words vs. word length') plt.xlabel('Word length in characters') plt.ylabel('Number of words') plt.show() # In[ ]: