โจทย์ Ruby #21

  • warning: realpath() [function.realpath]: SAFE MODE Restriction in effect. The script whose uid is 1005 is not allowed to access /tmp owned by uid 0 in /var/www/sites/sugree/codenone.com/subdomains/www/html/includes/file.inc on line 190.
  • warning: realpath() [function.realpath]: SAFE MODE Restriction in effect. The script whose uid is 1005 is not allowed to access /tmp owned by uid 0 in /var/www/sites/sugree/codenone.com/subdomains/www/html/includes/file.inc on line 190.

อ้างอิงจากโจทย์ Ruby #21

ผมทำไว้ 3 แบบ แบ่งตามระดับความโรคจิต

ปกติ ไม่ยาวไม่สั้น

def problem21_1(input,n):
    ret = []
    for i in range(0,len(input),n):
        ret.append(input[i:i+n])
    return ret

สั้นลงหน่อย

def problem21_2(input,n):
    return [input[i:i+n] for i in range(0,len(input),n)]

สั้นแบบโรคจิต

problem21_3 = lambda input,n: [input[i:i+n] for i in range(0,len(input),n)]

แล้วก็เอามารันเทียบกัน

input = range(1,10)
n = 3
for f in problem21_1,problem21_2,problem21_3:
    print f(input,n)

ผมนึกออกแค่นี้… หัวตื้อ

เล่นเฉลยซะหมด -_-"

เอาเวอร์ชั่นโรคจิตแบบไม่ใช้ lambda แล้วกัน เดี๋ยวมัน deprecate

def sep(i,n): return [i[j:j+n] for j  in range(0,len(i),n)]

range เป็นพระเอกใน solution นี้เลยแฮะ

เอาด้่วยคนสิ

def sep(list,n):
    if list==[]:
        return []
    else:
        return [list[0:n]] + sep(list[n:],n)

แต่แบบนี้พอสั่ง list[n:] มันจะ copy ใช่ป่ะครับ.... ช้าตายเลย
(อัีนแรก list[0:n] เนี่ยะ ยอมรับได้ เพราะว่าคิดเวลารวมก็เท่ากับวิ่งทั้ง list)
ทำไงไม่ให้ต้อง copy อ่ะครับ

sugree's picture

แอบเพิ่ม arg ตัวที่ 3 เอาไว้ระบุ index โดยที่ค่าเริ่มต้นเป็น 0

def sep(input,n,i=0):
    if i >= len(input):
        return []
    else:
        return [input[i:i+n]] + sep(input,n,i+n)

อืม... ทีนี้ พอสั่ง input[i:i+n] มันก็ต้องวิ่งตาม pointer ในลิสต์มาก่อนถึงจะ copy ได้ใช่ป่ะ?
(ลิสต์มันเก็บแบบนั้นเปล่า?) มีวิธีให้ไม่ต้องวิ่งป่ะ? แบบ อยากได้เช่น input[3:] เหมือนเป็น pointer ไปเริ่มที่ 3 เลย

เดี๋ยวเขียนของ ML ก่อง

sugree's picture

ผมไปดูในโค้ด C มาแล้วได้ความว่า list คือ array ที่ขยายขนาดได้ด้วยตัวเอง slice จะกระโดดไปที่ตำแหน่งเริ่มต้นแล้วค่อย copy ทีละตัว แปลว่าเขียนแบบข้างบนก็ใช้ได้ O(n) เหมือนกัน

แต่เขียน recursion แบบนี้มันทำ tail recursion ไม่ได้นี่นา....
ไว้ไปทำงานก่อนเดี๋ยวมาเขียนใหม่ครับ
(เขียนเป็นแต่ใน ML... เดี๋ยวไปลองหัด Haskell ก่อน รู้สึกจะเขียนเหมือน ๆ กัน)

(เวลา post เขียนเว้นย่อหน้ากันไงอ่ะครับ... ผมใช้ nbsp... แล้วมันยาวมากเลยครับ)

sugree's picture

ขอดูแบบ ML บ้างครับ

ถ้าเขียนด้วย ML จะยาวหน่อย เพราะว่าตรงกระโดดข้าม c ตัว ผมไม่รู้ว่ามีฟังก์ชันหรือเปล่า เลยเขียน skiphead เอามากระโดด มันจะอ่านเอาหัว c ตัวมา แล้วคืนคู่ลำดับของหัว แล้วก็หางที่เหลือ

fun skiphead([],c) = ([],[])
  | skiphead(list,0) = ([],list)
  | skiphead(x::xs,c) = let
	val (h,r) = skiphead(xs,c-1)
    in
	(x::h,r)
    end
			    
fun sep([],n) = []
  | sep(list,n) = let
	val (h,rest) = skiphead(list,n)
    in
	h::sep(rest,n)
    end

(สังเกตว่าฟังก์ชันนี้ทำงานกับลิสต์ความยาว n ในเวลา O(n))

เดี๋ยวไปเขียน version ที่เป็น tail recursion ด้วย อิอิ หนุกๆ (แต่มาอยู่ใน forum python ได้เปล่าเนี่ยะ?)

มาป่วนใน python ด้วย
ลองเขียนเป็น haskell หน้าตาออกมาเหมือนอาจารย์มะนาวเลย
(ไม่ได้ลอกนะ บังเอิญ)

haskell มี function ที่ชื่อ splitAt
หน้าตาเหมือน skiphead ของอาจารย์มะนาวเลย

splitAt               :: Int -> [a] -> ([a], [a])
splitAt 0 xs           = ([],xs)
splitAt _ []           = ([],[])
splitAt n (x:xs) | n>0 = (x:xs',xs'') where (xs',xs'') = splitAt (n-1) xs

เลยเอามาช่วย

part :: [a] -> Int -> [[a]]
part [] _ = []
part xs size = hs : part rest size
    where 
      (hs, rest) = splitAt size xs

อัดเจ้ย เหมือนกันเลย....
แต่ดูแล้วชอบ where นะครับ.... ดูอ่านง่ายกว่า let ... in ... end

veer's picture

จริงๆ แล้วผมก็อ่านไม่ค่อยรู้เรื่องทั้งคู่ แต่รู้สึกมีหวังที่จะอ่าน ML รู้เรื่องมากกว่าอะครับ Haskell พยายามอ่านหลายรอบแล้ว ก็เศร้าๆ เหมือนเดิม

bpitk's picture

lew : เอาเวอร์ชั่นโรคจิตแบบไม่ใช้ lambda แล้วกัน เดี๋ยวมัน deprecate

ใช้lambdaแล้ว deprecate ตั้งแต่ Python versionไหนครับ
แล้ว deprecate ทุกแบบของ lambda เลยหรือเปล่า
(คือไม่ค่อยได้ติดตามข่าว CPython น่ะครับ)

sugree's picture

ตกลงว่า lambda จะยังอยู่เหมือนเดิมนี่ครับ ตอนแรก GvR ว่าจะเอาออกโดยหาทางเลือกอื่นที่ดีกว่า แต่สุดท้ายก็หาไม่เจอ เลยสรุปว่ามันดีที่สุดแล้ว ก็เก็บไว้ ใน Py3K ก็จะยังมี

ไปไล่อ่านบล็อกของ GvR อีกรอบ มันกลับมาแล้วจริงๆ แฮะ ตกไปได้ไงเนี่ย

sugree's picture

เห็น Ruby เค้าวัดความเร็วกันเลยวัดบ้าง #1-#4 อยู่ที่หน้านี้ส่วน #5 อยู่ที่โจทย์

          user    system     total (      real)
#1    0.048003  0.000000  0.048003 (  0.051759)
#2    0.016001  0.000000  0.016001 (  0.018169)
#3    0.020001  0.000000  0.020001 (  0.021784)
#4    0.036002  0.000000  0.036002 (  0.033115)
#5    0.012001  0.000000  0.012001 (  0.013377)

ผลออกมาทำนองเดียวกัน แสดงว่าการสร้าง การก๊อปปี้ มีผลมากเหมือนกันนะเนี่ย ดูๆ ไป inline for นี่มันทำออกมาดีกว่า for ปกติซะอีก

ย้าย Codenone

ประกาศย้าย Codenone ไปใช้ Forum ของ Blognone แทนครับ ตามไปตั้งกระทู้ต่อได้ที่ Codenone Forum (รายละเอียดอ่านจากกระทู้ ย้าย Codenone ไปรวมกับ Blognone)

กระทู้เก่าๆ จะย้ายตามไปในภายหลัง ตอนนี้ปิดการโพสต์กระทู้ไว้ เหลือไว้เฉพาะอ้างอิงเท่านั้น