thongkorn โพสต์ 2018-7-10 13:04:03

[VB6/VB.NET] การตรวจสอบค่าที่ซ้ำกัน (Duplicate Value) แล้วเลือกคำตอบมาเพียงค่าเดียว

http://www.g2gnet.com/webboard/images/vbnet/DuplicateCode.png

ข้อมูลใน Array ประกอบด้วย เช่น 1, 2, 3, 2, 3, 5, 4, 1, 5, 6, 3, 8, 5, 9
ให้ทำการตรวจสอบค่าที่ซ้ำ แล้วตัดออกให้เหลือเพียงค่าเดียว ส่วนค่าไม่ซ้ำกันเลยก็เก็บไว้
ดังนั้นตัวอย่างนี้จะได้คำตอบคือ 1, 2, 3, 5, 4, 6, 8, 9 (โดยยังไม่ต้องมีการจัดเรียงจากน้อยไปมาก หรือ มากไปน้อย)

โจทย์ข้อนี้แอดมินจะ นำเสนอวิธีการแก้ปัญหา 2 รูปแบบ โดยแบบแรกจะเป็นการใช้กระบวนการคิดแบบเป็นขั้นเป็นตอน หรือที่เราเรียกว่าอัลกอริทึ่ม (Algorithm) ซึ่งแอดมินใช้ VB6 มาเป็นตัวหลักในการแก้โจทย์นี้ เนื่องจาก VB6 ไม่ได้มี Class ไฮโซเลิศหรู แต่ก็ยังสามารถหาคำตอบออกมาได้เหมือนกัน โดยอาศัยแค่คำสั่งพื้นฐานง่ายๆทั่วไป แบบที่ 2 แอดมินจะใช้ความเก่ง หรือความเป็นสำเร็จรูปของตัวแปลภาษา ... แน่นอนว่า แบบที่ 2 จะหาคำตอบได้อย่างรวดเร็วกว่าแบบที่ 1 แต่นี่มันแค่โจทย์การบ้านส่งครู เพราะในโลกแห่งความเป็นจริง เราจะได้เจอกับเงื่อนไขที่สลับซับซ้อนมากไปกว่านี้ ต้องเจอกับ Array หลายมิติ เช่น การเช็คเวลาเข้าทำงานของพนักงาน ต้องตัดค่าที่ซ้ำออกไป แล้วเลือกค่าแรกออกมา ส่วนเวลาออก ต้องตัดค่าซ้ำออกไป แล้วเลือกเวลาสุดท้ายออกมาเพื่อเป็นคำตอบ ... การใช้ความเก่งของตัวแปลภาษา จะไม่สามารถตอบโจทย์ให้เราทั้งหมดได้เลย ...
http://www.g2gnet.com/webboard/images/vbnet/DuplicateFlow.png
นี่คือวิธีการคิดแบบแรก โดยการนำเอาคำตอบมาเก็บไว้ที่เดิม หรือ ตัวแปร Array เดิมของมัน นั่นแหละครับ เพื่อประหยัดพื้นที่หน่วยความจำ ... แอดมินพยายามยกตัวอย่าง และทำผังขั้นตอนออกมาให้ดูแบบง่ายๆ ทั้งนี้หากท่านต้องการทำความเข้าใจให้ได้อย่างลึกซึ้งดื่มด่ำ ต้องทำการ Debugger จากโค้ดโปรแกรมด้วยตัวเองครับผม ...

หลักการคิด ... โดยเราใช้ตัวอย่างง่ายๆ เช่น (1, 2, 3, 1, 4)

- ใช้ Nested Loop วนรอบ 2 รอบ โดยรอบนอกวนตามจำนวนค่าอินพุทที่มี นั่นคือจาก 0 - 4 (จำนวน 5 ตัว) ... รอบในวนตามการนับค่าไม่ซ้ำ ซึ่งเรายังไม่รู้ค่าที่แน่นอน แต่ใช้ตัวแปร OutLen เริ่มต้น = 0 เพื่อเริ่มต้นการนับขึ้นทีละ 1 ซึ่งตัวแปร OutLen จะมีความสำคัญอย่างมาก ...

- รอบที่ 1 ลูปนอก ให้นำค่าจากใน Array (เริ่มจาก Index = 0) ไปฝากไว้ตัวแปร CurValue ... (วงลูปใน) โดยที่รอบแรกจะต้องให้ค่านั้นมันอยู่ที่เดิม มีเทคนิคง่ายๆคือให้วงรอบ For เป็นเท็จ นั่นคือ
---- For j = 0 To (OutLen - 1) หรือ For j = 0 To -1 (เรานับขึ้นคือ Default จะเป็น Step +1) <-- เงื่อนไขเท็จ จะไม่เกิดการกระทำในลูป For
---- เพิ่มค่าให้กับ OutLen ขึ้นไป 1 ==> OutLen = 1

- รอบที่ 2 ลูปนอก ค่า i = 1, ดึงค่า 2 จาก Array ออกมา ไปเก็บไว้ที่ CurValue = 2 ... (วงลูปใน) จะทำการวนรอบ 1 รอบ เพราะ
---- For j = 0 To (OutLen - 1) หรือ For j = 0 To (1 - 1) ==> For j = 0 To (0) <-- เงื่อนไขจริง
---- If InputNumber(0) = CurValue Then หรือ If 1 = 2 Then <-- เงื่อนไขเท็จ ... จบการลูป เก็บ 2 ไว้ที่เดิม แล้วเพิ่มค่า OutLen ขึ้นไป +1 ==> OutLen = 2

- รอบที่ 3 ลูปนอก ค่า i = 2, ดึงค่า 3 จาก Array ออกมา ไปเก็บไว้ที่ CurValue = 3 ... (วงลูปใน) จะทำการวนรอบ 2 รอบ เพราะ
---- For j = 0 To (OutLen - 1) หรือ For j = 0 To (2 - 1) ==> For j = 0 To (1) <-- เงื่อนไขจริง
---- If InputNumber(0) = CurValue Then หรือ If 1 = 3 Then <-- เงื่อนไขเท็จ ... กลับไปวนลูปในอีกครั้ง ทำให้ j = 1
---- If InputNumber(1) = CurValue Then หรือ If 2 = 3 Then <-- เงื่อนไขเท็จ ... จบการลูป เก็บ 3 ไว้ที่เดิม แล้วเพิ่มค่า OutLen ขึ้นไป +1 ==> OutLen = 3

- รอบที่ 4 ลูปนอก ค่า i = 3, ดึงค่า 1 จาก Array ออกมา ไปเก็บไว้ที่ CurValue = 1 ... (วงลูปใน) จะทำการวนรอบ 3 รอบ เพราะ
---- For j = 0 To (OutLen - 1) หรือ For j = 0 To (3 - 1) ==> For j = 0 To (2) <-- เงื่อนไขจริง
---- If InputNumber(0) = CurValue Then หรือ If 1 = 1 Then <-- เงื่อนไขจริง คือมีการซ้ำ
-------- กำหนดให้ blnExist = True เพื่อไม่ให้เกิดการบวก OutLen ขึ้น 1 ตอนนี้ OutLen = 3 ตามเดิม
-------- จบการวนรอบลูปในด้วย Exit For ซึ่งภาษาอื่นไม่มีใช้ แต่เราใช้เทคนิคการบังคับให้จบลูปได้ด้วย
การให้เงื่อนไขเป็นเท็จ j = OutLen นั่นคือ 3 = 3 พอมันจะกลับขึ้นไปวนรอบทำให้ For j = 0 To (OutLen - 1) หรือ For 3 = (3 - 1) หรือ For 3 = (2) <-- เท็จ

- รอบที่ 5 ลูปนอก ค่า i = 4, ดึงค่า 4 จาก Array ออกมา ไปเก็บไว้ที่ CurValue = 4 ... (วงลูปใน) จะทำการวนรอบ 3 รอบ เพราะ OutLen = 3
---- For j = 0 To (OutLen - 1) หรือ For j = 0 To (3 - 1) ==> For j = 0 To (2) <-- เงื่อนไขจริง
---- If InputNumber(0) = CurValue Then หรือ If 1 = 4 Then <-- เงื่อนไขเท็จ ... กลับไปวนลูปในอีกครั้ง ทำให้ j = 1
---- If InputNumber(1) = CurValue Then หรือ If 2 = 4 Then <-- เงื่อนไขเท็จ ... กลับไปวนลูปในอีกครั้ง ทำให้ j = 2
---- If InputNumber(2) = CurValue Then หรือ If 3 = 4 Then <-- เงื่อนไขเท็จ ... จบการลูปจะทำการวนรอบ 3 รอบ แต่เก็บ 4 ไว้ที่ค่าอินเด็กซ์ OutLen กำหนด คือ OutLen = 3 ซึ่งเดิมช่องนี้เก็บค่า 1 ที่ซ้ำเอาไว้ ... ก่อนจบ OutLen + 1 ทำให้ได้ค่า OutLen = 4

ดังนั้นเวลาเราเอาคำตอบออกมาจาก Array เดิม จะทำให้เหลือเพียง 4 ค่า นั่นคือ (1, 2, 3, 4) แต่อย่าลืมว่าเราเก็บค่าลง Array เริ่มต้นที่ค่าอินเด็กซ์ชี้ที่ 0 ดังนั้นเมื่อ OutLen = 4 ...OutLen - 1 = 4 - 1 = 3 หรือให้นับจากอินเด็กซ์ 0 ถึง 3 หรือ For i = 0 To 3 ... จบ

มาดูโค้ดในส่วนของ VB6 ...
' / --------------------------------------------------------------------------------
' / Developer : Mr.Surapon Yodsanga (Thongkorn Tubtimkrob)
' / eMail : thongkorn@hotmail.com
' / URL: http://www.g2gnet.com (Khon Kaen - Thailand)
' / Facebook: https://www.facebook.com/g2gnet (For Thailand)
' / Facebook: https://www.facebook.com/commonindy (Worldwide)
' / Purpose : Check for duplicate values.
' / Microsoft Visual Basic 6.0 (SP6)

' / This is open source code under @CopyLeft by Thongkorn Tubtimkrob.
' / You can modify and/or distribute without to inform the developer.
' / --------------------------------------------------------------------------------
Option Explicit

Sub DuplicateValueAlgorithm()
      '// ชุดข้อมูลตัวเลขอินพุท
      Dim InputNumber(7) As Integer
      InputNumber(0) = 1
      InputNumber(1) = 2
      InputNumber(2) = 3
      InputNumber(3) = 1
      InputNumber(4) = 3
      InputNumber(5) = 9
      InputNumber(6) = 4
      '// นับตามจำนวนคำตอบที่ได้
      Dim OutLen As Integer
      OutLen = 0
      
      Dim i As Integer
      Dim j As Integer

      '// ลูปตามจำนวนของอินพุท (ลบ 1 เพราะเราเริ่มนับจาก 0)
      For i = 0 To UBound(InputNumber) - 1
            '// หากมีค่าซ้ำกันให้เปลี่ยนเป็น True
            Dim blnExist As Boolean
            blnExist = False
            '// นำค่าตัวเลขอินพุทแต่ละตัวเข้ามา ฝากไว้ในตัวแปร
            Dim CurValue As Integer
            CurValue = InputNumber(i)

            '// ลูปตามจำนวน InputNumber (ลบ 1 เพราะเราเริ่มนับจาก 0)
            '/ รอบแรกจะข้ามไป เพราะว่า j = 0 และ OutLen = 0 คือการเอาค่าแรกของมันมาเปรียบเทียบกันมันก็ต้องซ้ำอยู่แล้ว
            For j = 0 To OutLen - 1
                '// เปรียบเทียบว่ามีค่าตรงกับค่าเดิมหรือไม่
                If InputNumber(j) = CurValue Then
                  '// พบการซ้ำ ก็ต้องออกจากลูป
                  blnExist = True
                  '// ออกจากลูปเมื่อกำหนดให้ j = OutLen (เทคนิคของการบังคับออกจากลูป For โดยไม่ใช้ Exit For)
                  j = OutLen '// หรือใช้ Exit For
                  'Exit For
                End If
            Next

            '// หากไม่พบการซ้ำกัน ให้ใส่ค่าที่ตรวจสอบกลับเข้าไปใน Array ของตัวแปรเดิม (แต่ตำแหน่ง OutLen จะอยู่คนละที่กันแล้ว)
            If Not blnExist Then
                '// เพิ่มตัวเลขที่พบกลับลงไปใน InputNumber
                InputNumber(OutLen) = CurValue
                '// เลื่อนตำแหน่งขึ้นไปอีก 1
                OutLen = OutLen + 1
            End If
      Next

      '// แสดงผล
      Dim s As String
      s = ""
      For i = 0 To OutLen - 1
            s = s & InputNumber(i) & vbCrLf
      Next
      MsgBox (s)
    End Sub

Private Sub Form_Load()
    Call DuplicateValueAlgorithm
    End
End Sub
มาดูโค้ดของ VB .NET (2010) ...
' / --------------------------------------------------------------------------------
' / Developer : Mr.Surapon Yodsanga (Thongkorn Tubtimkrob)
' / eMail : thongkorn@hotmail.com
' / URL: http://www.g2gnet.com (Khon Kaen - Thailand)
' / Facebook: https://www.facebook.com/g2gnet (For Thailand)
' / Facebook: https://www.facebook.com/commonindy (Worldwide)
' / Purpose : Check for duplicate values with two methods.
' / Microsoft Visual Basic .NET (2010) SP1

' / This is open source code under @CopyLeft by Thongkorn Tubtimkrob.
' / You can modify and/or distribute without to inform the developer.
' / --------------------------------------------------------------------------------

Public Class Form1

    Private Sub Form1_Load(sender As System.Object, e As System.EventArgs) Handles MyBase.Load
      Call DuplicateValueAlgorithm()
      Call DuplicateValueLanguage()
      End
    End Sub

    ' / --------------------------------------------------------------------------------
    ' / การใช้ทักษะพื้นฐานทางด้านโปรแกรมมิ่ง และกระบวนการคิด (Algorithm)
    ' / โดยเราจะเอาคำตอบกลับมาเก็บไว้ที่อินพุทแบบ Array ตามเดิม
    Sub DuplicateValueAlgorithm()
      '// ชุดข้อมูลตัวเลขอินพุท (เวลาทดสอบจริงไม่ต้องยาวก็ได้ เช่น {1, 2, 3, 1, 4})
      'Dim InputNumber() As Integer = {1, 2, 3, 1, 4}
      Dim InputNumber() As Integer = {1, 2, 3, 2, 3, 5, 4, 1, 5, 6, 3, 8, 5, 9}
      '// นับตามจำนวนคำตอบที่ได้
      Dim OutLen As Integer = 0

      '// ลูปตามจำนวนของอินพุท (ลบ 1 เพราะเราเริ่มนับจาก 0)
      For i As Integer = 0 To InputNumber.Length - 1
            '// หากมีค่าซ้ำกันให้เปลี่ยนเป็น True
            Dim blnExist As Boolean = False
            '// นำค่าตัวเลขอินพุทแต่ละตัวเข้ามา ฝากไว้ในตัวแปร
            Dim CurValue As Integer = InputNumber(i)

            '// ลูปตามจำนวน InputNumber (ลบ 1 เพราะเราเริ่มนับจาก 0)
            '/ รอบแรกจะข้ามไป เพราะว่า j = 0 และ OutLen = 0 คือการเอาค่าแรกของมันมาเปรียบเทียบกันมันก็ต้องซ้ำอยู่แล้ว
            For j As Integer = 0 To OutLen - 1
                '// เปรียบเทียบว่ามีค่าตรงกับค่าเดิมหรือไม่
                If InputNumber(j) = CurValue Then
                  '// พบการซ้ำ ก็ต้องออกจากลูป
                  blnExist = True
                  '// ออกจากลูปเมื่อกำหนดให้ j = OutLen (เทคนิคของการบังคับออกจากลูป For โดยไม่ใช้ Exit For)
                  j = OutLen '// หรือใช้ Exit For
                End If
            Next

            '// หากไม่พบการซ้ำกัน ให้ใส่ค่าที่ตรวจสอบกลับเข้าไปใน Array ของตัวแปรเดิม (แต่ตำแหน่ง OutLen จะอยู่คนละที่กันแล้ว)
            If Not blnExist Then
                '// เพิ่มตัวเลขที่พบกลับลงไปใน InputNumber
                InputNumber(OutLen) = CurValue
                '// เลื่อนตำแหน่งขึ้นไปอีก 1
                OutLen += 1
            End If
      Next

      '// แสดงผล
      Dim s As String = String.Empty
      For i As Integer = 0 To OutLen - 1
            s = s & InputNumber(i) & vbCrLf
      Next
      MsgBox(s)
    End Sub

    ' / --------------------------------------------------------------------------------
    ' / การใช้ความเก่งของตัวแปลภาษา
    Sub DuplicateValueLanguage()
      '// สร้าง List และข้อมูลตัวอย่าง
      Dim InList As New List(Of Integer)(New Integer() {1, 2, 3, 2, 3, 5, 4, 1, 5, 6, 3, 8, 5, 9})
      '// กรองข้อมูลที่ซ้ำ (Distinct) แล้วเอามันกลับไปเก็บไว้ใน List
      Dim OutList As List(Of Integer) = InList.Distinct().ToList
      '// แสดงผล
      Dim s As String = String.Empty
      For Each CurValue As Integer In OutList
            s = s & CurValue & vbCrLf
      Next
      MsgBox(s)
    End Sub
End Class
Conclusion: หลายคนอาจจะมองว่าโค้ดสั้นๆมันมี Performance ที่สูงกว่า ลดบั๊กหรือความผิดพลาดลงไปได้เยอะ แต่เชื่อแอดมินเถอะครับ กับงานจริงๆเราไม่ได้หาคำตอบง่ายๆแบบนี้ออกมา เพราะมันจะมีเงื่อนไข ตรรกะ จุกจิกอีกเยอะแยะมากมาย สำหรับคนที่พึ่งเริ่มฝึกเขียนโปรแกรม ก็จงพยายามคิดก่อนที่จะเขียนโปรแกรม ดังวิธีการคิดในแบบแรก เราไม่จำเป็นต้องเปิดหนังสือ และไม่ต้องไปค้นหาในเน็ต แต่ใช้กระบวนการคิดแบบเป็นขั้นเป็นตอน และที่สำคัญคือ วิธีการคิดแบบนี้ไม่ขึ้นกับภาษาใดๆ ... สวัสดี

ดาวน์โหลดโค้ดต้นฉบับ VB6 และ VB .NET (2010) ได้ที่นี่ ...
หน้า: [1]
ดูในรูปแบบกติ: [VB6/VB.NET] การตรวจสอบค่าที่ซ้ำกัน (Duplicate Value) แล้วเลือกคำตอบมาเพียงค่าเดียว