ผมรู้สึกว่าการกรอกคะแนนนักศึกษาเป็นเรื่องยุ่งยาก โดยเฉพาะคะแนนการบ้านกับควิซ ที่เก็บมาแบบไม่ได้เรียงตามลำดับรหัสนักศึกษา ไม่รู้ว่าอาจารย์คนอื่นเขาทำกันยังไง (โดยเฉพาะวิชาที่สอนกัน 200-300 คน) เดิมผมมักจะเอากระดาษมาเรียงตามรหัสนักศึกษา แล้วค่อยไล่กรอกลง spreadsheet แต่มันก็ยุ่งยาก ขี้เกียจอีก
ความขี้เกียจนี้ส่งผลให้ผมไม่ค่อยได้คืนควิชหรือการบ้านกลับให้นักศึกษา แล้วก็จะมาหัวหมุนเอาตอนปลายเทอม เพราะต้องกรอกทุกอย่างให้เสร็จก่อนจะตัดเกรด
วันก่อนก็เลยเขียนโปรแกรมเล็กๆ เอาไว้กรอกคะแนนควิซโดยเฉพาะ ฟีเจอร์หลักๆ ที่ต้องการก็คือ อยากใส่แค่รหัสนักศึกษาบางส่วน (3-4 ตัวก็พอ) ถ้าไม่ซ้ำก็กรอกคะแนนไปได้เลย ถ้าซ้ำก็แสดงตัวเลือกให้หน่อย แล้วค่อยกรอกคะแนน ตอนแรกก็อยากจะทำเป็น GUI สวยงาม มี textbox ให้กรอกรหัส แล้วจะแสดงตัวเลือกเหมือนพวก autocomplete อะไรทำนองนั้น แต่ก็ดูยุ่งยาก ขี้เกียจอีก (จะเห็นว่าขี้เกียจกันทุกขั้นตอน) แต่สุดท้ายเลยได้โปรแกรม python แบบ command-line มาอันหนึ่ง รับข้อมูลเป็น text file มีแต่รหัสนักศึกษา ใช้ regular expression สำหรับเทียบรหัสกรอกเข้ามา แล้วก็ให้เลือกได้ ถ้ามีรหัสตรงหลายอัน จากนั้นก็กรอกคะแนนลงไปได้ เรียบร้อย ใช้ได้ดี ตามข้างล่างนี้ (แต่ไม่รับประกันความผิดพลาดถ้าจะเอาไปใช้ เพราะขี้เกียจเช็ค input error บางกรณีอีก) โปรดลองใช้กันได้ตามอัตภาพ ![]()
(more…)
Tags: input, python, score, teaching. programming
ไม่ได้เขียนอะไรใหม่ๆ ที่นี่มาเกือบครึ่งปี เพราะงานยุ่ง แล้วก็ยังเสพติด twitter และ facebook งอมแงมอีกต่างหาก วันนี้มีเวลาว่าง (จริงๆ ก็ไม่ว่างหรอก แต่ขี้เกียจทำงานที่ควรจะทำ) เลยเอา Go Programming Language ที่พัฒนาโดย Google มาลองเล่นดู เนื่องจากผมใช้ Mac OS X ซึ่งเป็นแพลตฟอร์มที่สนับสนุนอยู่แล้ว ก็เลยติดตั้งไม่ยาก แค่มี XCode อยู่ แล้วลง mercurial เพิ่ม ก็สามารถโหลดซอร์สโค้ดคอมไพเลอร์ของ Go มาคอมไพล์เองได้เลย ใช้เวลาคอมไพล์ตัวคอมไพเลอร์สั้นมาก แป๊บเดียวเสร็จ ประทับใจพอสมควร
จากนั้นก็เลยลองเขียนโปรแกรมแบบมั่วๆ (เพราะยังงงกับ syntax อยู่) เพื่อแก้ปัญหา N-Queens แบบง่ายๆ (ใช้ backtracking search ด้วย recursive ดื้อๆ เอานี่แหละ) โดยใช้ Go:
package main import "fmt" var N int = 10 func nqueens(board []int, filled int) int { var attack bool = false; if filled == N-1 { for i:=0; i<N; i++ { fmt.Printf("%d\t", board[i]) } fmt.Printf("\n"); return 1 } filled += 1; for i:=0; i<N; i++ { board[filled] = i; attack = false; for j:=0; j<filled; j++ { dy := board[j]-board[filled]; dx := j - filled; if (board[j] == board[filled]) || (dy/dx == 1 || dy/dx == -1) && (dy%dx == 0) { attack = true; break } } if !attack { nqueens(board, filled) } } return 0 } func main() { var board []int = make([]int, N); nqueens(board, -1); }
ด้วยความอยากรู้ ก็เลยลองเอาโปรแกรมนี้เอามาแปลงเป็นภาษา C แบบตรงๆ บรรทัดต่อบรรทัด
#include<stdio.h> #include<stdlib.h> const int N=10; int nqueens(int *board, int filled) { int i,j,attack,dy,dx; if (filled == N-1) { for(i=0; i<N; i++) printf("%d\t", board[i]); printf("\n"); return 1; } filled++; for(i=0; i<N; i++) { board[filled] = i; attack = 0; for(j=0; j<filled; j++) { dy = board[j]-board[filled]; dx = j - filled; if ((board[j] == board[filled]) || ((dy/dx == 1 || dy/dx == -1) && (dy%dx == 0))){ attack = 1; break; } } if (!attack) nqueens(board, filled); } return 0; } main() { int *board = (int *)malloc(sizeof(int)*N); nqueens(board, -1); }
เสร็จแล้วก็ลองเขียน Python อีกโปรแกรมหนึ่ง
def nqueens(board, filled): global N if filled == N-1: for i in board: print "%d\t" % board[i], print return True filled+=1 for i in xrange(0, N): board[filled] = i attack = False for j in xrange(0, filled): dy = board[j]-board[filled] dx = j - filled if board[j] == board[filled] or ((dy/dx == 1 or dy/dx == -1) and dy%dx==0): attack = True break if not attack: nqueens(board, filled) return 0 N=10 board = [0]*N nqueens(board, -1)
ทดลองรัน (ด้วย N=10) แล้วจับเวลาง่ายๆ ด้วย time ก็จะได้ผลเป็น
| Go | C | Python | |
|---|---|---|---|
| real | 0m0.165s | 0m0.041s | 0m1.048s |
| user | 0m0.116s | 0m0.029s | 0m1.028s |
| sys | 0m0.040s | 0m0.002s | 0m0.015s |
ประสิทธิภาพแบบคร่าวๆ ก็ถือว่าใช้ได้ทีเดียว ไม่ได้แย่กว่า C นัก แต่ไม่รู้ว่าผมชินกับภาษา C มากเกินไปหรือเปล่า ทำให้ผมรู้สึกแปลกๆ งงๆ กับ syntax ของ Go มันดูไม่ค่อยสวยงามยังไงไม่รู้ บอกไม่ถูก เหมือนแค่เอา C มาตัดบางส่วนออก เพราะกลัวจะพิมพ์เยอะเกินไป มันเลยดูขัดๆ อีกอย่าง Go ก็ไม่ได้เขียนสั้นๆ ง่ายๆ ได้เหมือน Python ผมว่าโครงสร้าง syntax ของ C กับ Python สวยงามกว่าเยอะ แต่ผมก็ยังไม่ลอง concurrent programming ที่เป็นจุดขายของ Go เหมือนกัน เอาไว้หนีงานมาลองใหม่คราวหน้าละกัน
Tags: C, go, programming, python
หลังจากถูกถล่มด้วยงานต่างๆ ทำให้ไม่ได้มาเขียนสองเดือนกว่าๆ พอดีช่วงนี้ช่วยจัดงาน PAKDD2009 อยู่ และมีงานที่เกี่ยวข้องที่ต้องใช้สคริปต์ เลยเอามาจดไว้ที่นี่หน่อยกันลืม
เรื่องของเรื่องก็คือผมต้องการส่งอีเมลไปยังคนหลายๆ คน โดยมีเนื้อหาที่แตกต่างกันเล็กน้อย ผมเลยเริ่มจากเปิด OpenOffice.org Spreadsheet ขึ้นมาเขียนข้อมูลต่างๆ ที่ต้องการแปะลงไปในจดหมาย แล้วเก็บเป็นไฟล์ CSV (Comma-Separated Value) ที่เป็นสำหรับเก็บข้อมูลแบบง่ายที่สุด แต่ละบรรทัดแทนข้อมูลแต่ละเรคอร์ด และใช้เครื่องหมาย “,” คั่นระหว่างข้อมูลแต่ละฟิลด์ จากนั้นก็เขียนสคริปต์ Python เพื่ออ่านข้อมูลจากไฟล์ CSV ที่ทำไว้ เอาไปแปะในเทมเพลตที่เตรียมไว้ โดย Python จะมีคลาสสำหรับอ่านเขียนไฟล์ CSV เป็นคลาสมาตรฐานอยู่แล้ว ก็เลยสามารถทำงานได้สะดวกมาก
วิธีใช้คลาส csv เพื่ออ่านข้อมูล จะทำอย่างนี้
import csv data = csv.reader(open('myfile.csv'), delimiter=',', quotechar='"') for row in data: print row[0]
csv.reader เป็นคลาสสำหรับจัดการอ่านข้อมูลแบบ CSV รับอาร์กิวเมนต์เป็นไฟล์ เครื่องหมายที่ใช้คั่นระหว่างฟิลด์ และเครื่องหมายที่ใช้เป็น quote ครอบข้อมูลแต่ละฟิลด์ เมื่อสร้างออพเจคต์ของ csv.reader ขึ้นมาแล้ว ก็สามารถวนรอบเพื่ออ่านไฟล์ขึ้นมาทีละเรคอร์ดได้เลย โดยข้อมูลที่อ่านขึ้นมาจะเก็บไว้ในรูปอาเรย์ อย่างกรณีนี้ row[0] ก็คือข้อมูลในฟิลด์แรกสุด
หลังจากนี้เราก็ต้องเตรียมเทมเพลต ซึ่งก็คือกำหนดตัวแปรสตริงเท่านั้นเอง เช่น
template = """
Dear {r[0]},
I would like to send you the following information:
{r[1]}
Best Regards,
Cholwich
"""จะเห็นว่าสตริงนี้มีสัญลักษณ์พิเศษ ระบุข้อมูลที่เราต้องการจะเอาไปแทรก {r[0]} หมายถึงสมาชิกตัวแรกของตัวแปร r ที่ส่งมาเป็นพารามิเตอร์ อันนี้เป็นฟีเจอร์ String Formatting ของ Python อยู่แล้ว เมื่อกำหนดเทมเพลตเสร็จ สั่งให้ Python แทรกข้อมูลโดย
output = template.format(r=row)
จะได้ผลลัพธ์ที่ผสานข้อมูลเข้าไปแล้ว เป็นสตริงเก็บไว้ที่ตัวแปรชื่อ output จากนั้นผมก็สามารถเอาไปส่งเมล์ หรือเอาไปเขียนลงไฟล์เก็บไว้ได้ พอเอาทั้งหมดมารวมกันก็จะได้
import csv template = """ Dear {r[0]}, I would like to send you the following information: {r[1]} Best Regards, Cholwich. """ data = csv.reader(open('myfile.csv'), delimiter=',', quotechar='"') for row in data: output = template.format(r=row) f = open(row[2], 'w') f.write(output) f.close()
สุดท้ายก็จะได้สคริปต์ง่ายๆ สำหรับทำ mail merge ที่ได้ output เป็นไฟล์แยกกัน โดยระบุชื่อไฟล์ไว้ที่ row[2]
อ้างอิง:
Tags: programming, python