การจัดเรียงข้อมูล (Sorting)

เราสามารถจัดเรียงข้อมูลตามลำดับที่เราต้องการได้ง่ายๆด้วยคำสั่ง sorted() ในภาษา Python

ถ้าอ่านภาษาอังกฤษได้สามารถไปดูเพิ่มเติมที่ [https://docs.python.org/3/howto/sorting.html] นะครับ

สมมุติว่าเรามีข้อมูลรวมกันอยู่ในลิสต์ชื่อ a ดังนี้:

In [1]:
a = [3, 1, 4, 1, 5, 9, 2, 6, 5, 3]

เราสามารถจัดเรียงข้อมูลใน a แล้วเอาผลลัพธ์ไปใส่ไว้ในลิสต์ใหม่ชื่อ b แบบนี้:

In [2]:
b = sorted(a)

ข้อมูลใน b จะเรียงลำดับน้อยไปมากแบบนี้:

In [3]:
b
Out[3]:
[1, 1, 2, 3, 3, 4, 5, 5, 6, 9]

แต่ข้อมูลใน a ยังเหมือนเดิม:

In [4]:
a
Out[4]:
[3, 1, 4, 1, 5, 9, 2, 6, 5, 3]

เราสามารถเรียงจากมากไปน้อยด้วยใส่ reverse = True เข้าไปใน sorted ด้วย เช่นลิสต์ c ข้างล่างจะมีข้อมูลใน a เรียงลำดับจากมากไปน้อย:

In [5]:
c = sorted(a, reverse = True)
c
Out[5]:
[9, 6, 5, 5, 4, 3, 3, 2, 1, 1]

นอกจากตัวเลขแล้ว sorted() สามารถจัดเรียงข้อมูลประเภทต่างๆได้ เช่นเรียงตามตัวอักษร:

In [6]:
words = ["chicken", "ant", "zebra", "boa",  "cat", "panda", "dog"]
sorted(words)
Out[6]:
['ant', 'boa', 'cat', 'chicken', 'dog', 'panda', 'zebra']

เวลาเราใช้คำสั่ง sorted() เราสามารถใส่ key = ... เข้าไปเพื่อบอก sorted() ว่าควรเปรียบเทียบว่าอะไรควรอยู่หน้าอยู่หลัง โดยสิ่งทื่อยู่หลัง key = ควรเป็นฟังก์ชั่นที่ให้ค่าที่เอาไปเปรียบเทียบกันได้ ยกตัวอย่างเช่นเรามีข้อมูลนักเรียนที่อยู่ในรูป (ชื่อ, เดือนเกิด 1-12, ปีเกิดเป็นพ.ศ.) ดังนี้:

In [7]:
students = [("Chunli", 2, 2548), ("Tatia", 12, 2548), ("Jung", 9, 2547), ("Pitchee", 9, 2548), ("Song", 6, 2548), ("Sound", 6, 2548), ("Tangmo", 2, 2550)]
students
Out[7]:
[('Chunli', 2, 2548),
 ('Tatia', 12, 2548),
 ('Jung', 9, 2547),
 ('Pitchee', 9, 2548),
 ('Song', 6, 2548),
 ('Sound', 6, 2548),
 ('Tangmo', 2, 2550)]

ถ้าจะเรียงลำดับตามเดือนเกิด เราก็ควรสร้างฟังก์ชั่นที่บอกเดือนเกิดของนักเรียนแต่ละคนได้ ในที่นี้ฟังก์ชั่นต้องเอาตัวเลขเดือนเกิดตรงกลางออกมาให้:

In [8]:
def get_month(student_data):
    #student_data อยู่ในรูป (ชื่อ, เดือนเกิด 1-12, ปีเกิดเป็นพ.ศ.) 
    #student_data[0] คือชื่อ
    #student_data[1] คือเดือนเกิด
    #student_data[2] คือปีเกิด
    
    return (student_data[1]) #เอาเดือนเกิดมาให้

เราจะเรียก sorted() โดยใส่ key = get_month เพื่อจัดเรียงข้อมูลตามเดือนเกิด:

In [9]:
sorted(students, key = get_month)
Out[9]:
[('Chunli', 2, 2548),
 ('Tangmo', 2, 2550),
 ('Song', 6, 2548),
 ('Sound', 6, 2548),
 ('Jung', 9, 2547),
 ('Pitchee', 9, 2548),
 ('Tatia', 12, 2548)]

ถ้าจะเรียงตามเดือนเกิดจากมากไปน้อยก็สามารถใส่ reverse = True เข้าไปด้วย:

In [10]:
sorted(students, key = get_month, reverse = True)
Out[10]:
[('Tatia', 12, 2548),
 ('Jung', 9, 2547),
 ('Pitchee', 9, 2548),
 ('Song', 6, 2548),
 ('Sound', 6, 2548),
 ('Chunli', 2, 2548),
 ('Tangmo', 2, 2550)]

ถ้าจะเรียงลำดับตามความยาวของชื่อ เราก็ควรสร้างฟังก์ชั่นที่บอกความยาวของชื่อมาเพื่อเปรียบเทียบดังนี้:

In [11]:
def name_length(data):
    #student_data อยู่ในรูป (ชื่อ, เดือนเกิด 1-12, ปีเกิดเป็นพ.ศ.) 
    #student_data[0] คือชื่อ
    #student_data[1] คือเดือนเกิด
    #student_data[2] คือปีเกิด
    
    return(len(data[0])) #เอาความยาวชื่อมาให้

แล้วเราก็เรียก sorted() โดยใส่ key = name_length ดังนี้:

In [12]:
sorted(students, key = name_length)
Out[12]:
[('Jung', 9, 2547),
 ('Song', 6, 2548),
 ('Tatia', 12, 2548),
 ('Sound', 6, 2548),
 ('Chunli', 2, 2548),
 ('Tangmo', 2, 2550),
 ('Pitchee', 9, 2548)]

เราตรวจคำตอบเราได้โดยการพิมพ์ข้อมูลนักเรียนมาพร้อมๆกับความยาวชื่อได้แบบนี้:

In [13]:
for data in sorted(students, key = name_length):
    print(data, name_length(data)) #พิมพ์ข้อมูลนักเรียน ตามด้วยความยาวชื่อ
('Jung', 9, 2547) 4
('Song', 6, 2548) 4
('Tatia', 12, 2548) 5
('Sound', 6, 2548) 5
('Chunli', 2, 2548) 6
('Tangmo', 2, 2550) 6
('Pitchee', 9, 2548) 7

บางครั้งเราไม่อยากสร้างฟังก์ชั่นใหม่ๆแยกขึ้นมาต่างหากเพื่อไปใส่ key = ... เราสามารถใช้ฟังก์ชั่นนิรนามที่เรียกว่า lambda ได้

ฟังก์ชั่นนิรนาม lambda จะมีรูปแบบอย่างนี้:

lambda ตัวแปร: ผลลัพธ์

เราสามารถใช้ lambda แทนฟังก์ชั่น name_length ได้แบบนี้:

lambda data: len(data[0])

มาแทน

def name_length(data):
    #student_data อยู่ในรูป (ชื่อ, เดือนเกิด 1-12, ปีเกิดเป็นพ.ศ.) 
    #student_data[0] คือชื่อ
    #student_data[1] คือเดือนเกิด
    #student_data[2] คือปีเกิด

    return(len(data[0])) #เอาความยาวชื่อมาให้

โดยใส่เข้าไปใน sorted() อย่างนี้:

In [14]:
sorted(students, key = lambda data: len(data[0]))
Out[14]:
[('Jung', 9, 2547),
 ('Song', 6, 2548),
 ('Tatia', 12, 2548),
 ('Sound', 6, 2548),
 ('Chunli', 2, 2548),
 ('Tangmo', 2, 2550),
 ('Pitchee', 9, 2548)]

เราสามารถจัดเรียงตามเดือนเกิดได้โดยใช้ lambda แบบนี้:

In [15]:
sorted(students, key = lambda data: data[1])
Out[15]:
[('Chunli', 2, 2548),
 ('Tangmo', 2, 2550),
 ('Song', 6, 2548),
 ('Sound', 6, 2548),
 ('Jung', 9, 2547),
 ('Pitchee', 9, 2548),
 ('Tatia', 12, 2548)]

หรือถ้าจะจัดเรียงตามผลคูณของเดือนเกิดกับปีเกิดก็สามารถทำแบบนี้ได้:

In [16]:
sorted(students, key = lambda data: data[1]*data[2] )
Out[16]:
[('Chunli', 2, 2548),
 ('Tangmo', 2, 2550),
 ('Song', 6, 2548),
 ('Sound', 6, 2548),
 ('Jung', 9, 2547),
 ('Pitchee', 9, 2548),
 ('Tatia', 12, 2548)]

แบบฝึกหัด

แบบฝึกหัดที่ 1: หาคำในภาษาอังกฤษที่มีสระครบ 5 ตัว (a, e, i, o, u)

เราสามารถเปิดไฟล์ที่มีคำภาษาอังกฤษ แล้วตรวจดูว่าคำไหนมีสระครบทั้ง 5 ตัว เราสร้างฟังก์ชั่นไว้ตรวจเช็คดังนี้:

In [17]:
def has_all_vowels(word):
    """
    จะให้ค่า True ถ้า word มีสระครบทั้ง a, e, i, o, u
    จะให้ค่า False ถ้าไม่มีสระครบ
    """
    for vowel in "aeiou":
        if not vowel in word.lower(): #เรามี .lower() เพื่อเปลี่ยนตัวอักษรเป็นอักษรตัวเล็กก่อนไปดูว่ามี a, e, i, o, u ไหม
            return(False)
    return(True)
In [18]:
#ทดลองใช้
print(has_all_vowels("environment")) #False
print(has_all_vowels("facetious")) #True
print(has_all_vowels("FACETIOUS")) #True
False
True
True

แล้วเราก็สามารถใช้ฟังก์ชั่น has_all_vowels() เช็คคำในรายการคำของเราดังนี้

In [ ]:
wordlist = '/usr/share/dict/words' #รายการคำภาษาอังกฤษ หนึ่งคำต่อหนึ่งบรรทัด
inputfile = open(wordlist)
for word in inputfile:
    if has_all_vowels(word):
        print(word, end = "") #เราใส่ end =  "" เพื่อบอก print() ว่าไม่ต้องขึ้นบรรทัดใหม่ เพราะคำทุกคำมีตัวขึ้นบรรทัดใหม่ (\n) ติดมาด้วยแล้ว
inputfile.close()

ถ้าต้องการเก็บผลลัพธ์ไว้ในไฟล์ก็ใช้ .write(...) เขียนไฟล์ ในที่นี้เราเก็บไว้ในไฟล์ชื่อ allvowels.txt

In [19]:
wordlist = '/usr/share/dict/words' #ไฟล์ที่มีคำภาษาอังกฤษ 1 คำต่อบรรทัด
allvowels  = 'allvowels.txt' #เราเก็บผลลัพธ์เราไว้ในไฟล์นี้
inputfile = open(wordlist) #เปิดไฟล์เพื่ออ่าน
outputfile = open(allvowels, "w") #เปิดไฟล์เพื่อเขียน สังเกตว่ามี "w"
for word in inputfile: 
    if has_all_vowels(word):
        outputfile.write(word) 
outputfile.close()
inputfile.close()

แบบฝึกหัดที่ 2: หาคำภาษาอังกฤษที่มีสระครบ 5 ตัวและเรียงกันตั้งแต่ a ไปถึง u

เราสามารถแก้ปัญหาโดยเขียนฟังก์ชั่นที่ตรวจสอบว่าคำภาษาอังกฤษแต่ละคำมีสระครบห้าตัวไหม และเรียงกันไหม มีหลายวิธี วิธีหนึ่งก็อาจใช้ find() เพื่อหาดูตำแหน่งสระในคำ:

In [20]:
#ตัวอย่างการใช้ find() หาตำแหน่งตัวอักษร
word = "facetious"
print(word.find("a")) #ตำแหน่งของ a คือ 1 (อย่าลืมว่าตัวแรกคือตำแหน่งที่ 0)
print(word.find("e")) #ตำแหน่งของ e คือ 3
print(word.find("i")) #ตำแหน่งของ i คือ 5
print(word.find("o")) #ตำแหน่งของ o คือ 6
print(word.find("u")) #ตำแหน่งของ u คือ 7
print(word.find("x")) #ไม่มี x ในคำว่า facetious ดังนั้น find() จะส่งค่ามา = -1
1
3
5
6
7
-1

ถ้าคำที่เราสนใจมีสระครบห้าตัว และตำแหน่งของ a, e, i, o, u เพิ่มขึ้นเรื่อยๆ ก็แสดงว่าคำๆนั้นมีสระทุกตัวและอยู่ในลำดับเรียงกัน ถ้าเราเอาตำแหน่งทั้งหลายไปใส่ไว้ในลิสต์ ลิสต์นั้นเมื่อ sorted() แล้วจะเท่าตัวมันเอง

เราเขียนเป็นฟังก์ชั่นตรวจสอบได้ดังนี้:

In [21]:
def has_aeiou_in_order(word):
    """
    ตรวจว่า word มีสระ a, e, i, o, u ครบทั้งห้าตัว
    และ a มาก่อน e, e มาก่อน i, i มาก่อน o, และ o มาก่อน u
    จะให้ค่า True ถ้ามีสระครบและเรียงกัน
    ให้ค่า False ถ้าไม่ครบหรือไม่เรียง
    """
    if not has_all_vowels(word): 
        return(False)   #ถ้ามีสระไม่ครบห้าตัวก็ให้ค่า False แล้วออกจากฟังก์ชั่นเลย
    vowel_list = []     #ลิสต์ที่จะใส่ตำแหน่งสระแต่ละตัว
    for c in "aeiou":
        vowel_list.append(word.find(c)) #ใส่ตำแหน่งเข้าไปในลิสต์ที่เก็บ
    #print(vowel_list)
    return (sorted(vowel_list) == vowel_list) #ถ้าตำแหน่งเมื่อจัดเรียงจากมากไปน้อยแล้วยังเหมือนเดิมแสดงว่าสระเรียงถูกต้องแล้ว
In [22]:
#ทดสอบ has_aeiou_in_order()
print(has_aeiou_in_order("hello")) #False
print(has_aeiou_in_order("aliferous")) #False
print(has_aeiou_in_order("facetious")) #True
False
False
True

เราสามารถใช้ has_aeiou_in_order หาคำที่มีสระครบและเรียงกันได้อย่างนี้ครับ:

In [23]:
wordlist = '/usr/share/dict/words' #รายการคำภาษาอังกฤษ หนึ่งคำต่อหนึ่งบรรทัด
inputfile = open(wordlist)
for word in inputfile:
    if has_aeiou_in_order(word):
        print(word, end = "") #เราใส่ end =  "" เพื่อบอก print() ว่าไม่ต้องขึ้นบรรทัดใหม่ เพราะคำทุกคำมีตัวขึ้นบรรทัดใหม่ (\n) ติดมาด้วยแล้ว
inputfile.close()
abstemious
abstemiously
abstemiousness
abstentious
acetarious
acheilous
acheirous
acleistous
advectitious
adventitious
adventitiously
adventitiousness
adversarious
adversifolious
aeciotelium
aegithognathous
aeriferous
affectious
alternipetalous
alternisepalous
amberiferous
amentiferous
ampelidaceous
ampelideous
anepigraphous
annelidous
antenniferous
antheriferous
anthraceniferous
appendicious
appenditious
appetitious
arenarious
arenicolous
argentiferous
armeniaceous
arreptitious
arseniferous
arsenious
arteriopalmus
arterious
arteriovenous
asclepiadaceous
asclepiadeous
asperifolious
assentatious
athericerous
bacteriaceous
bacterioagglutinin
bacteriofluorescin
bacteriogenous
bacteriophagous
bacteriopurpurin
bacteriotherapeutic
bacterious
caesalpiniaceous
caesious
cavernicolous
chaetiferous
Chamaesiphonaceous
facetious
facetiously
facetiousness
flagellariaceous
flagelliferous
fracedinous
fragmentitious
frankeniaceous
garnetiferous
hamamelidaceous
krameriaceous
lamellicornous
lamelliferous
Lapeirousia
lateriflorous
laterifolious
lateritious
magnetiferous
majestious
malesherbiaceous
malleiferous
pancreaticoduodenal
pancreaticoduodenostomy
parallelinervous
parallepipedous
parmeliaceous
placentiferous
placentigerous
racemiferous
rafflesiaceous
ramentiferous
sarmentiferous
sarraceniaceous
satellitious
sphacelariaceous
sphaeriaceous
stapediovestibular
taeniosomous
trajectitious
valerianaceous

เราพบว่าคำบางคำข้างบนมีสระซ้ำๆกันมากกว่าหนึ่งตัว ถ้าเราต้องการสระห้าตัวที่ไม่ซ้ำเท่านั้นเราก็ต้องหาวิธีตรวจสอบใหม่ วิธีแบบหนึ่งก็คือ เอาตัวอักษรสระในคำออกมาเรียงกันในลิสต์ แล้วดูว่าลิสต์นั้นต้องหน้าตาเป็น ['a','e','i','o','u'] เท่านั้น

In [24]:
def has_aeiou_in_order_no_repeat(word):
    """
    ตรวจว่า word มีสระ a, e, i, o, u ครบทั้งห้าตัว
    และ a มาก่อน e, e มาก่อน i, i มาก่อน o, และ o มาก่อน u
    และสระแต่ละตัวเกิดขึ้นครั้งเดียวในคำ ไม่ซ้ำ
    จะให้ค่า True ถ้ามีสระครบ ไม่ซ้ำ และเรียงกัน
    ให้ค่า False ถ้าไม่ครบ หรือซ้ำ หรือไม่เรียง
    """
    if not has_all_vowels(word): 
        return(False)   #ถ้ามีสระไม่ครบห้าตัวก็ให้ค่า False แล้วออกจากฟังก์ชั่นเลย
    vowel_list = []     #ลิสต์ที่จะเก็บสระที่พบในคำที่จะตรวจ
    for c in word:      #ดูแต่ละตัวอักษรในคำที่จะตรวจ
        if c in 'aeiou': #ถ้าอักษรนั้นเป็นสระ ให้เก็บเข้าไปในลิสต์
            vowel_list.append(c) 
    #print(vowel_list)
    return (vowel_list ==  ['a','e','i','o','u']) #ถ้าสระมี 5 ตัวและเป็น a, e , i, o, u ก็ให้ค่า True ถ้าไม่ใช่ก็ให้ค่า False
In [25]:
#ทดสอบ has_aeiou_in_order_no_repeat()
print(has_aeiou_in_order_no_repeat("hello")) #False
print(has_aeiou_in_order_no_repeat("aliferous")) #False
print(has_aeiou_in_order_no_repeat("facetious")) #True
print(has_aeiou_in_order_no_repeat("valerianaceous")) #False
False
False
True
False

เราหาคำที่มีสระห้าตัว เรียงกัน และไม่ซ้ำ ด้วย has_aeiou_in_order_no_repeat() แบบนี้:

In [26]:
wordlist = '/usr/share/dict/words' #รายการคำภาษาอังกฤษ หนึ่งคำต่อหนึ่งบรรทัด
inputfile = open(wordlist)
for word in inputfile:
    if has_aeiou_in_order_no_repeat(word):
        print(word, end = "") #เราใส่ end =  "" เพื่อบอก print() ว่าไม่ต้องขึ้นบรรทัดใหม่ เพราะคำทุกคำมีตัวขึ้นบรรทัดใหม่ (\n) ติดมาด้วยแล้ว
inputfile.close()
abstemious
abstemiously
abstentious
acheilous
acheirous
acleistous
affectious
annelidous
arsenious
arterious
bacterious
caesious
facetious
facetiously
fracedinous
majestious

แบบฝึกหัดที่ 3: หา anagram หรือคำที่ประกอบด้วยอักษรชุดเดียวกัน

Anagram (อนาแกรม) คือคำที่ใช้อักษรชุดเดียวกันมาสะกดให้เป็นคำต่างๆกัน เช่น bat กับ tab เป็นอนาแกรมกัน brainy กับ binary เป็นอนาแกรมกัน

วิธีง่ายสุดที่จะจัดชุดอนาแกรมก็คือทำการจัดเรียงตัวอักษรในคำต่างๆให้เรียงเป็นลำดับ แล้วเปรียบเทียบชุดอักษรที่จัดเรียงแล้วนั้น เช่น sorted('bat') และ sorted('tab') จะได้ค่า ['a', 'b', 't'] เหมือนกัน

เราสามารถเก็บคำที่เป็นอนาแกรมกันไว้ด้วยกันด้วยสิ่งที่เรียกว่า dictionary ซึ่งคล้ายๆลิสต์แต่สามารถอ้างอิงตำแหน่งต่างๆได้ด้วยข้อความ (string) ได้

เด็กๆดูเพิ่มเติมเกี่ยวกับ dictionary ได้ที่ [https://docs.python.org/3.7/tutorial/datastructures.html#dictionaries] และ [https://snakify.org/en/lessons/dictionaries_dicts/] ครับ

วิธีหนึงของการหาอนาแกรมทำได้ดังนี้:

In [ ]:
wordlist = '/usr/share/dict/words' #รายการคำภาษาอังกฤษ หนึ่งคำต่อหนึ่งบรรทัด
inputfile = open(wordlist)
anagrams = {}  #dictionary ที่เราจะเก็บคำที่เป็นอนาแกรมกัน
for word in inputfile:
    word = word.strip() #เราลบ \n (newline หรือตัวขึ้นบรรทัดใหม่) ที่อยู่ท้ายแต่ละคำ
    if len(word) < 2:   #เราจะดูเฉพาะคำที่มีสองตัวอักษรขึินไปเท่านั้น
        continue       
    key = "".join(sorted(word)) #สร้างข้อความอ้างอิงโดยจัดเรียงอักษรในคำเป็นลำดับด้วย sorted(word) การใช้ "".join(...) คือเอาแต่ละตัวอักษรในลิสต์มารวมกันเป็นข้อความอ้างอิงคำเดียว
    key = key.lower()  #ทำข้อความอ้างอิงเป็นอักษรตัวเล็ก
    if key in anagrams:  #ถ้าข้อความอ้างอิงเคยถูกใส่่ไว้ใน dictionary แล้ว ให้เพิ่มเติมคำ word ต่อเข้าไปในลิสต์ของคำที่เป็นอนาแกรมกัน
        anagrams[key].append(word)
    else:
        anagrams[key] = [] #ถ้าข้อความอ้างอิงไม่เคยมีใน dictionary เอาใส่่คำ word เป็นคำแรกของลิสต์ของคำที่เป็นอนาแกรมกัน
        anagrams[key].append(word)
inputfile.close()

for key, values in anagrams.items(): #วิธีไล่ว่าใน dictionary มีข้อมูลอะไรบ้าง ทำอย่างนี้ key คือข้อความอ้างอิง values คือลิสต์ของคำที่เป็นอนาแกรมกัน
    if len(values) > 1:  #เราแสดงผลเฉพาะตั้งแต่สองคำขึ้นไปที่เป็นอนาแกรมกัน
        print(", ".join(values))  #  ", ".join(values) คือเอาคำต่างๆที่อยู่ในลิสต์ values มาต่อๆกันโดยมีคอมม่าคั่น

ถ้าต้องการเก็บรายการคำที่เป็นอนาแกรมไว้ในไฟล์ ก็สามารถใช้ file.write() ได้

In [27]:
wordlist = '/usr/share/dict/words' #รายการคำภาษาอังกฤษ หนึ่งคำต่อหนึ่งบรรทัด
anagramlist = 'anagrams.txt'       #ชื่อไฟล์ที่จะเก็บอนาแกรมต่างๆไว้
inputfile = open(wordlist)
outputfile = open(anagramlist, "w") #เปิดไฟล์เพื่อเขียนโดยการใส่ "w" ไว้ใน open() 
anagrams = {}  #dictionary ที่เราจะเก็บคำที่เป็นอนาแกรมกัน
for word in inputfile:
    word = word.strip() #เราลบ \n (newline หรือตัวขึ้นบรรทัดใหม่) ที่อยู่ท้ายแต่ละคำ
    if len(word) < 2:   #เราจะดูเฉพาะคำที่มีสองตัวอักษรขึินไปเท่านั้น
        continue
    key = "".join(sorted(word)) #สร้างข้อความอ้างอิงโดยจัดเรียงอักษรในคำเป็นลำดับด้วย sorted(word) การใช้ "".join(...) คือเอาแต่ละตัวอักษรในลิสต์มารวมกันเป็นข้อความอ้างอิงคำเดียว
    key = key.lower()  #ทำข้อความอ้างอิงเป็นอักษรตัวเล็ก    
    if key in anagrams:  #ถ้าข้อความอ้างอิงเคยถูกใส่่ไว้ใน dictionary แล้ว ให้เพิ่มเติมคำ word ต่อเข้าไปในลิสต์ของคำที่เป็นอนาแกรมกัน
        anagrams[key].append(word)
    else:
        anagrams[key] = [] #ถ้าข้อความอ้างอิงไม่เคยมีใน dictionary เอาใส่่คำ word เป็นคำแรกของลิสต์ของคำที่เป็นอนาแกรมกัน
        anagrams[key].append(word)
inputfile.close()

for key, values in anagrams.items(): #วิธีไล่ว่าใน dictionary มีข้อมูลอะไรบ้าง ทำอย่างนี้ key คือข้อความอ้างอิง values คือลิสต์ของคำที่เป็นอนาแกรมกัน
    if len(values) > 1:  #เราแสดงผลเฉพาะตั้งแต่สองคำขึ้นไปที่เป็นอนาแกรมกัน
        outputfile.write(", ".join(values))  #  ", ".join(values) คือเอาคำต่างๆที่อยู่ในลิสต์ values มาต่อๆกันโดยมีคอมม่าคั่น
        outputfile.write("\n")   #ขึ้นบรรทัดใหม่ด้วย
outputfile.close()        

ถ้าไม่ใช้ dictionary เราสามารถเก็บข้อมูลด้วยลิสต์ก็ได้ครับ ทำได้แบบนี้:

In [30]:
wordlist = '/usr/share/dict/words' #รายการคำภาษาอังกฤษ หนึ่งคำต่อหนึ่งบรรทัด
anagramlist = 'anagrams_list.txt'       #ชื่อไฟล์ที่จะเก็บอนาแกรมต่างๆไว้
inputfile = open(wordlist)
outputfile = open(anagramlist, "w") #เปิดไฟล์เพื่อเขียนโดยการใส่ "w" ไว้ใน open() 
anagrams = []  #ลิสต์ที่เราจะเก็บคำที่เป็นอนาแกรมกัน
for word in inputfile:
    word = word.strip() #เราลบ \n (newline หรือตัวขึ้นบรรทัดใหม่) ที่อยู่ท้ายแต่ละคำ
    if len(word) < 2:   #เราจะดูเฉพาะคำที่มีสองตัวอักษรขึิ้นไปเท่านั้น
        continue
    key = "".join(sorted(word)) #สร้างข้อความอ้างอิงโดยจัดเรียงอักษรในคำเป็นลำดับด้วย sorted(word) การใช้ "".join(...) คือเอาแต่ละตัวอักษรในลิสต์มารวมกันเป็นข้อความอ้างอิงคำเดียว
    key = key.lower()  #ทำข้อความอ้างอิงเป็นอักษรตัวเล็ก    
    anagrams.append((key, word))  #เก็บคำและข้อความอ่้างอิงไว้ด้วยกันเป็นคู่ลำดับ ตอนหลังเราจะมาดูว่าคำไหนมีข้อความอ้างอิงเหมือนกันก็จะเป็นอนาแกรมกัน
inputfile.close()

anagrams = sorted(anagrams)  #ทำการจัดเรียงข้อมูลตามข้อความอ้างอิง คราวนี้คำที่เป็นอนาแกรมกันจะอยู่ติดๆกันในลิสต์ anagrams

current_key = ""  #ข้อความอ้างอิงปัจจุบันคืออะไร
word_list = []    #ลิสต์ที่จะเก็บคำที่เป็นอนาแกรมไว้ด้วยกัน
for item in anagrams:  
    key, word = item   #ดูคู่ลำดับ (ข้อความอ้างอิง, คำ) ที่ละอัน
        
    if current_key == key:  #ถ้าข้อความอ้างอิงยังไม่เปลี่ยนก็เพิ่มคำเข้าไปในกลุ่มอนาแกรมเดียวกัน
        word_list.append(word)
    else:              #แต่ถ้าข้อความอ้างอิงเปลี่ยนแล้ว ก็บันทึกกลุ่มอนาแกรม(ถ้ามี)ลงไฟล์ แล้วเตรียมรวบรวมกลุ่มอนาแกรมสำหรับข้อความอ้างอิงอันใหม่
        if len(word_list) > 1:
            outputfile.write(", ".join(word_list))
            outputfile.write("\n")
        current_key = key
        word_list = []
        word_list.append(word)
    
outputfile.close()