Just algorithm!
เขียน C# ง่าย ๆ สไตล์ Ruby

เดิมที ผมเขียน Blog นึง ไว้จัดการความรู้ของผม ที่ได้จากการเล่นเว็บ www.projecteuler.net
Blog ของผมชื่อ chaowchaow.blogspot.com ซึ่งเขียนเป็นภาษาอังกฤษ และใช้สำนวนมั่ว ๆ ของผมเอง
แต่พอดีได้ไปอ่าน Blog คุณศล เลยเกิดแรงบันดาลใจ จะเขียนเป็นภาษาไทยบ้าง เพื่อที่จะได้แบ่งปันความรู้กัน
โดยจะพยายามจะย้ายมาที่ละบทความนะครับ Smiley

รู้จัก Ruby กันมั๊ยครับ Smiley ?
Ruby เป็นภาษาสำหรับเขียน Program ที่เน้นความง่าย สั้น แต่ทำอะไรได้เยอะ
ภาษา Ruby สามารถเขียนได้กระชับมาก จนมีเว็บ สำหรับแข่งเขียน Code ให้สั้นที่สุดกัน

ผิดกับ C# ซึ่งเทียบกับ Ruby แล้ว C# ถือเป็นภาษาสุภาพ ต้องพูดตามไวยกรณ์ ความหมายชัดเจน Smiley
อย่างแรกคุณต้องประกาศชนิดของตัวแปรก่อน ถ้าเป็น Array ก็ต้องกำหนด Size ให้แน่นอน
จะกำหนดค่าให้ตัวแปร ก็ต้อง Check Type กันวุ่นวาย
อย่างนี้จะเขียน C# แบบสนุก ๆ ไม่ได้นะสิ ต้องเขียนแบบเป็นเรื่องเป็นราวใช่มั๊ย ?

ต้องไม่สิครับ เราจะมาทำรัฐประหารกัน Smiley
เราต้องทำให้ C# เขียนง่ายแบบไม่เคยรู้สึกมาก่อน
C# ออก Version ใหม่แล้วนะ Version 3.0 มี Features ใหม่มากมาย Smiley
ผมขออนุญาตไม่อธิบายรายอันว่า Features ต่าง ๆ ทำอะไรได้บ้างนะครับ

คือไอ้ C# ตัวใหม่เนี่ยมันทำอะไรที่เรียกว่า Extension Methods ได้
ปกติเวลาเราต้องการเพิ่มความสามารถให้ Class ๆ นึง
เราก็ต้องสร้าง Class ลูกแยกออกมาแล้วเพิ่ม Method ลงไป
แต่ถ้าทำอย่างนี้ Class ก็มีให้จำเพิ่มขึ้น แล้วก็ขี้เกียจเขียน Class ใหม่ด้วยใช่ไหมครับ Smiley

Extension Methods นี้มันมาแก้ปัญหานี้โดยเฉพาะ
มันเป็นการสร้าง Static Method ขึ้นมา แล้วก็กำหนดคำว่า this หน้า Parameter แรก
แค่นี้เราก็หลอก C# (กับหลอกตัวเอง) ได้ว่านี่คือ Method ใหม่ของ Type แรกใน Parameter นะ

เช่น เราสร้าง Static Method สำหรับแปลง String เป็น Int ขึ้นมา

public static int ToInt(this string source) {
    return int.Parse(source);
}


เท่านี้เราก็สามารถสร้าง Method ใหม่ ชื่อ ToInt ให้กับ String ได้
วิธีใช้ก็

int i = "123".ToInt();

เท่านี้ String ที่มีค่า "123" ซึ่งไม่เคยมี Method ชื่อ ToInt มาก่อน
ก็สามารถเรียก ToInt ได้

ทีนี้เรามาเปลี่ยน C# ให้เป็นคนใหม่กัน
เริ่มจากคำว่า foreach
foreach มีไว้แยก item แต่ละตัวใน Class ประเภท Enumerable
Enumerable คือ สามารถแตกย่อยออกมาได้ เช่น List, Array, Dictionary
วิธีเขียน foreach คือ

foreach (Object item in list)

ทีนี้มาเทียบกับ Ruby

list.each{|item| ...}

Ruby สั้นและเข้าใจง่ายกว่าใช่ไหมครับ
มีประธาน คือ list กริยาคือ each ส่วนในวงเล็บ { } คือ บอกว่าทำอะไร
แปลเป็นภาษาไทยคือ "List นี้ แตกออกมาแต่ละ item ทำ ..."

ทีนี้เรามาสร้าง Extension Methods กัน
ก่อนอื่นคุณต้องสร้าง Static Class ขึ้นมา หนึ่งอัน ชื่ออะไรก็ได้
แล้ว Copy Code ข้างล่าง ไปใส่ใน Static Class นั้น

public static void ForEach<T>(this IEnumerable<T> source, Action<T> action) {
    foreach (T item in source)
        action(item);
}

public static void ForEach<T>(this IEnumerable<T> source, Action<T, int> action) {
    int i = 0;

    foreach (T item in source)
        action(item, i++);
}


เวลาคุณจะต้องการให้ C# รู้จัก Extension Methods ที่สร้างมาใหม่
คุณต้องกำหนด "using" ตามด้วย Namespace ของ Static Class ไว้ด้านบนสุด ของ Class
ที่เราต้องการใช้ Extension Method ด้วยนะครับ
ซึ่งถ้าทำเสร็จแล้ว เราจะสามารถเขียนแบบนี้ได้

list.ForEach(item => ...);
list.ForEach((item,index)=> ...);

งงไหมครับ ไปดูตัวอย่างกัน

string[] persons = new string[] {"Jack", "Lisa", "Ryan"};
persons.ForEach(person => Console.WriteLine("Hello {0}!", person));
//Hello Jack!
//Hello Lisa!
//Hello Ryan!


persons.ForEach((person, index) => Console.WriteLine("{0}. {1}", index + 1, person));
//1. Jack
//2. Lisa
//3. Ryan


ไอ้เครื่องหมาย => เค้าเรียกว่า Lambda Expression
มันคือ Anonymous Method หรือ Method ย่อยนั่นเอง
ด้านซ้ายของ => คือ Parameter ถ้ามี Parameter เดียว ไม่ต้องมีวงเล็บก็ได้
และหน้าตัวแปร ไม่ต้องประกาศชนิดของตัวแปรก็ได้
ด้านขวาของ => คือ ตัว Body ของ Method ย่อย

ในที่นี้ Code ด้านบน Code แรก มี Parameter เดียว คือ person
person คือ item ที่แตกออกมาจาก persons และมีคำสั่งให้ Console เขียนคำว่า Hello แล้วตามด้วยชื่อ
ผลลัพธ์คือ Console จะเขียนคำว่า Hello และชื่อ สำหรับทุก ๆ ชื่อใน persons

Code ที่ 2 มี 2 Parameters อันแรกคือ item อันที่ 2 คือ index
index นี้จะเริ่มจาก 0 แล้วรันตัวเลขไปเรื่อย ๆ ทุก ๆ item
ผลลัพธ์เลยทำให้เวลา Console เขียนออกมาแล้วรัน 1,2,3 ได้

พอเข้าใจไหมครับ ไม่เข้าใจตรงไหนถามได้ครับ
ต่อมา คือ คำสั่ง for นะครับ
เวลาเราจะรันตัวเลขใน C# เราเขียน

for (int i = 0; i <= 2; i++)

แต่ Ruby ง่ายกว่าครับ แค่ประกาศ Range 0-2

0..2

หรือมีอีกทางนึงเลย คือบอกว่าทำ 3 รอบ

3.times{|x| ..}

ไอ้ค่า x ด้านบนก็จะเป็น 0-2 ให้อัตโนมัติ
อิจฉา Ruby มันรึยังครับ? ถ้าอิจฉาเอา Code ด้านล่าง ไปแปะที่ Static Class ที่คุณไว้รวม Extension Methods

public static IEnumerable<int> To(this int from, int to) {
    for (int x = from; x <= to; x++)
        yield return x;
}
public static IEnumerable<int> DownTo(this int from, int to) {
    for (int x = from; x >= to; x--)
        yield return x;
}
public static IEnumerable<int> StepTo(this int from, int to, int step) {
    if (step > 0) {
        for (int x = from; x <= to; x += step)
            yield return x;
    } else if (step < 0) {
        for (int x = from; x >= to; x += step)
            yield return x;
    } else {
        throw new ArgumentException("Step cannot be zero.", "step");
    }
}
public static void Times(this int num, Action<int> action) {
    for (int x = 0; x < num; x++)
        action(x);
}


มีหลายคำสั่งนะครับ เวลาเอาไปใช้จะได้ตามนี้

string[] persons = new string[] { "Jack", "Lisa", "Ryan" };
0.To(2).ForEach(i => Console.WriteLine(persons[i]));
//Jack
//Lisa
//Ryan

2.DownTo(0).ForEach(i => Console.WriteLine(persons[i]));
//Ryan
//Lisa
//Jack

0.StepTo(2, 2).ForEach(i => Console.WriteLine(persons[i]));
//Ryan
//Jack

3.Times(i => Console.WriteLine(persons[i]));
//Jack
//Lisa
//Ryan


คำสั่ง 0.To(2) หมายถึง การสร้าง Range เริ่มจาก 0, 1, 2
แต่ถ้าเป็น 2.To(0) Range นี้จะว่างเปล่าเพราะคำสั่งนี้รันจากน้อยไปมากเท่านั้น

คำสั่ง 2.DownTo(0) คือการทำ Range จากมากไปน้อย
ในที่นี้จะเริ่มจาก 2, 1, 0

คำสั่ง 0.StepTo(2, 2) คือ การสร้าง Range แบบกระโดด
Parameter แรกคือ ตัวเลขสิ้นสุด Parameter ที่ 2 คือ ระยะของแต่ละตัวเลข
เช่น ถ้าเป็น 1.StepTo(5, 2) คือ การรันเริ่มจาก 1, 3, 5
และกระโดดถอยหลังได้ โดยใส่ระยะเป็นติดลบ เช่น 5.StepTo(1, -2) คือการรันจาก 5, 3, 1
ระยะใส่เป็น 0 ไม่ได้นะครับ เช่น 1.StepTo(2, 0) จะ Error

คำสั่งสุดท้าย 3.Times อันนี้จะเป็นการทำซ้ำ 3 ครั้ง
โดยต้องโยน Lambda Expression เข้าไป
Parameter แรกของ Lambda คือ index ของรอบการรัน เริ่มจาก 0

ที่เขียนมาทั้งหมด ก็เพื่อทำโจทย์ข้อแรกของ projecteuler.net เองนะครับ
Add all the natural numbers below 1000 that are multiples of 3 or 5.
แปลเป็นไทยคือ บวกจำนวนนับ 1 - 999 ทุกจำนวนที่เป็นผลคูณของเลข 3 หรือ 5
เขียนได้ตามนี้ครับ

Console.WriteLine(1.To(999).Where(x => (x % 3 == 0) || (x % 5 == 0)).Sum());
//233168


เคยคิดไหมครับว่า C# จะแก้ปัญหาด้านบนด้วย Code บรรทัดเดียว!
แค่ลองเปลี่ยนสไตล์ C# ของเราวัยรุ่นขึ้นเยอะเลยจริงไหมครับ Smiley

* อ่านจบแล้ว กรุณา Comment ด้วยครับ เพื่อเป็น Feedback และเป็นกำลังใจ
* บทความนี้คัดลอกได้ แต่ต้องมี Link หรือ Url กลับมาที่หน้านี้ และเมื่อคัดลอกแล้วกรุณา Comment แจ้งด้วยครับ




Create Date : 21 มิถุนายน 2551
Last Update : 9 สิงหาคม 2551 14:46:40 น. 19 comments
Counter : 5438 Pageviews.

 
ขอบคุณ มากครับ จะลองทำดูมั้ง


โดย: ต้อง IP: 124.120.100.126 วันที่: 25 มิถุนายน 2551 เวลา:15:57:06 น.  

 
แต่ว่าเป็น blog ที่ดีนะครับให้ความรู้ผมชอบมาก ผมอยากเป็นโปแกรมแต่ว่ายังไม่เก่ง

ใครใจบุญช่วยนะนำหน่อยนะครับ
skyone_23@hotmail.com


โดย: ไม่รู้เรื่องทั้งสองภาษา IP: 203.121.167.243 วันที่: 26 มิถุนายน 2551 เวลา:11:35:21 น.  

 
เจ๋ง ดีครับ ขอบคุณมาก ๆ ที่ช่วยเพิ่มความรู้ให้นะครับ


โดย: PureSnow IP: 124.120.207.247 วันที่: 27 มิถุนายน 2551 เวลา:17:46:58 น.  

 
ขอบคุณค่ะ ความรู้ใหม่เลยค่ะ


โดย: Ran IP: 203.170.247.50 วันที่: 7 ตุลาคม 2551 เวลา:15:50:38 น.  

 
ขอบคุณทุกท่านที่เข้ามาอ่านเช่นกันครับ


โดย: chaowman วันที่: 19 พฤศจิกายน 2551 เวลา:10:28:58 น.  

 
ขอบคุณมัก ๆ คับ
สุดยอดเลยคับ code ได้ เท่มาก


โดย: เต้ IP: 61.7.157.133 วันที่: 6 กุมภาพันธ์ 2552 เวลา:16:30:09 น.  

 
เยี่ยมมากเลยคับ ขอบคุณมาก


โดย: bin IP: 114.128.227.101 วันที่: 16 กุมภาพันธ์ 2552 เวลา:22:10:59 น.  

 
อยากได้โค้ดลบ
ช่วยหน่อยค่ะ
ขอบคุณค่ะ


โดย: As IP: 202.29.22.253 วันที่: 4 มีนาคม 2552 เวลา:19:32:03 น.  

 
เจ๋งๆๆ คับ

ขอเอาไปให้เพื่อนวิทย์คอมรามอ่านหน่อยนะคับ


โดย: myeste IP: 58.64.51.26 วันที่: 12 เมษายน 2552 เวลา:10:28:41 น.  

 
ช่างทำไปได้ เป็นผมคงหลายลูป -0-


โดย: gmax IP: 125.26.39.254 วันที่: 1 พฤษภาคม 2552 เวลา:1:42:56 น.  

 
แจ๋วเลยพี่ แต่ชอบ java อิอิ


โดย: tony IP: 125.25.46.133 วันที่: 1 สิงหาคม 2552 เวลา:9:30:06 น.  

 
คำว่ายอดเยี่ยม ยกให้เลยครับ

ขอบคุณที่แบ่งปันครับ


โดย: Herudoy IP: 118.174.33.144 วันที่: 26 กันยายน 2552 เวลา:18:00:59 น.  

 
เป็นความรู้ที่ดี และมีตัวอย่างให้ลองอีกด้วย
ดีมากมาย
ขอบคุณมากๆ ที่แบ่งปัน สนับสนุนๆ


โดย: LittleHobbis IP: 125.24.126.212 วันที่: 26 มกราคม 2553 เวลา:20:37:41 น.  

 
สุดยอดมากเลยครับ ความรู้ที่ดีแบบนี้ไม่หาได้ง่ายๆ ขอบคุณมากๆครับ


โดย: ิิbeer.sting IP: 58.8.61.215 วันที่: 3 พฤษภาคม 2553 เวลา:20:36:11 น.  

 
เยียมมากเลยครับ ทำให้ผมได้ความรู้ใหม่ขึ้นมาเพียบ เลย เดี๋ยวว่าจะไล่ติดตามอ่าน blog ของคุณเชาว์ให้หมดเลยครับ

ขอบคุณสำหรับการแบ่งปันครับ


โดย: embarus IP: 203.146.117.163 วันที่: 3 มีนาคม 2554 เวลา:14:49:32 น.  

 
ขอบคุณมากครับ^^"


โดย: badzbadz IP: 125.24.255.202 วันที่: 12 กันยายน 2554 เวลา:4:43:57 น.  

 
ขอให้ท่าน chaowman มีความรู้แตกฉาน เฉลียวฉลาดตลอดไปครับ

ขอบคุณที่อุตส่าห์แบ่งปันความรู้ครับ


โดย: ganggahia IP: 192.168.181.158, 183.88.249.22 วันที่: 1 กรกฎาคม 2555 เวลา:16:54:33 น.  

 
ขอบคุณมากครับ อ่านแล้วได้ความรู้ใหม่เยอะเลยครับ


โดย: Thit Than IP: 124.122.91.73 วันที่: 11 ตุลาคม 2555 เวลา:16:56:35 น.  

 


โดย: smicx' IP: 190.204.71.122 วันที่: 2 มกราคม 2565 เวลา:4:44:44 น.  

ชื่อ :
Comment :
  *ใช้ code html ตกแต่งข้อความได้เฉพาะสมาชิก
 

chaowman
Location :
กรุงเทพฯ Thailand

[Profile ทั้งหมด]

ฝากข้อความหลังไมค์
Rss Feed
Smember
ผู้ติดตามบล็อก : 8 คน [?]





New Comments
Group Blog
 
All Blogs
 
Friends' blogs
[Add chaowman's blog to your web]
Links
 

 Pantip.com | PantipMarket.com | Pantown.com | © 2004 BlogGang.com allrights reserved.