다음을 통해 공유


컬렉션 내에서 비교 및 정렬

클래스는 System.Collections 제거할 요소를 검색하거나 키 및 값 쌍의 값을 반환하는지 여부에 관계없이 컬렉션 관리와 관련된 거의 모든 프로세스에서 비교를 수행합니다.

컬렉션은 일반적으로 같음 비교자 및/또는 순서 비교자를 사용합니다. 비교에는 두 개의 구문이 사용됩니다.

동등성 확인

와 같은 ContainsIndexOfLastIndexOf메서드는 Remove 컬렉션 요소에 대해 같음 비교자를 사용합니다. 컬렉션이 제네릭이면 다음 지침에 따라 항목이 같음으로 비교됩니다.

  • T 형식이 제네릭 인터페이스 IEquatable<T>을(를) 구현할 경우, 해당 인터페이스의 Equals 메서드가 같음 비교자로 사용됩니다.

  • T 형식이 IEquatable<T>을(를) 구현하지 않으면 Object.Equals이(가) 사용됩니다.

또한 사전 컬렉션에 대한 일부 생성자 오버로드는 키의 동일성을 비교하기 위한 구현을 IEqualityComparer<T>로 허용합니다. 예를 들어 Dictionary<TKey,TValue> 생성자를 참조하십시오.

정렬 순서 결정

BinarySearchSort과 같은 메서드는 컬렉션 요소에 대한 순서 비교자를 사용합니다. 비교는 컬렉션의 요소 간 또는 요소와 지정된 값 사이일 수 있습니다. 개체를 비교할 때는 default comparer과/와 explicit comparer의 개념이 있습니다.

기본 비교자는 비교되는 개체 중 하나 이상을 사용하여 IComparable 인터페이스를 구현합니다. 목록 컬렉션의 값으로 사용되거나 사전 컬렉션의 키로 사용되는 모든 클래스에서 IComparable 을 구현하는 것이 좋습니다. 제네릭 컬렉션의 경우 같음 비교는 다음에 따라 결정됩니다.

  • T 형식이 제네릭 인터페이스를 System.IComparable<T> 구현하는 경우 기본 비교자는 해당 인터페이스의 IComparable<T>.CompareTo(T) 메서드입니다.

  • T 형식이 제네릭 System.IComparable 이 아닌 인터페이스를 구현하는 경우 기본 비교자는 해당 인터페이스의 IComparable.CompareTo(Object) 메서드입니다.

  • T 형식이 두 인터페이스 중 하나를 구현하지 않는 경우 기본 비교자가 없으며 비교자 또는 비교 대리자를 명시적으로 제공해야 합니다.

명시적 비교를 제공하기 위해 일부 메서드는 IComparer 구현을 매개 변수로 허용합니다. 예를 들어 메서드는 List<T>.Sort 구현을 System.Collections.Generic.IComparer<T> 허용합니다.

시스템의 현재 문화권 설정은 컬렉션 내의 비교 및 정렬에 영향을 줄 수 있습니다. 기본적으로 컬렉션 클래스의 비교 및 정렬은 문화권을 구분합니다. 문화권 설정을 무시하여 일관된 비교 및 정렬 결과를 얻으려면 InvariantCulture를 허용하는 멤버 오버로드와 함께 CultureInfo를 사용하십시오. 자세한 내용은 컬렉션에서 문화권을 구분하지 않는 문자열 작업 수행배열에서 문화권을 구분하지 않는 문자열 작업 수행을 참조하세요.

같음 및 정렬 예제

다음 코드에서는 간단한 비즈니스 개체의 IEquatable<T> 구현 및 IComparable<T> 구현을 보여 줍니다. 또한 개체가 목록에 저장되고 정렬될 때 Sort() 메서드를 호출하면, 형식 Part에 대한 기본 비교자를 사용하고 익명 메서드를 사용하여 구현된 Sort(Comparison<T>) 메서드를 볼 수 있습니다.

using System;
using System.Collections.Generic;

// Simple business object. A PartId is used to identify the
// type of part but the part name can change.
public class Part : IEquatable<Part>, IComparable<Part>
{
    public string PartName { get; set; }

    public int PartId { get; set; }

    public override string ToString() => 
        $"ID: {PartId}   Name: {PartName}";

    public override bool Equals(object obj) => 
        (obj is Part part)
                ? Equals(part)
                : false;

    public int SortByNameAscending(string name1, string name2) => 
        name1?.CompareTo(name2) ?? 1;

    // Default comparer for Part type.
    // A null value means that this object is greater.
    public int CompareTo(Part comparePart) =>
        comparePart == null ? 1 : PartId.CompareTo(comparePart.PartId);

    public override int GetHashCode() => PartId;

    public bool Equals(Part other) =>
        other is null ? false : PartId.Equals(other.PartId);

    // Should also override == and != operators.
}

public class Example
{
    public static void Main()
    {
        // Create a list of parts.
        var parts = new List<Part>
        {
            // Add parts to the list.
            new Part { PartName = "regular seat", PartId = 1434 },
            new Part { PartName = "crank arm", PartId = 1234 },
            new Part { PartName = "shift lever", PartId = 1634 },
            // Name intentionally left null.
            new Part { PartId = 1334 },
            new Part { PartName = "banana seat", PartId = 1444 },
            new Part { PartName = "cassette", PartId = 1534 }
        };
        
        // Write out the parts in the list. This will call the overridden
        // ToString method in the Part class.
        Console.WriteLine("\nBefore sort:");
        parts.ForEach(Console.WriteLine);

        // Call Sort on the list. This will use the
        // default comparer, which is the Compare method
        // implemented on Part.
        parts.Sort();

        Console.WriteLine("\nAfter sort by part number:");
        parts.ForEach(Console.WriteLine);

        // This shows calling the Sort(Comparison<T> comparison) overload using
        // a lambda expression as the Comparison<T> delegate.
        // This method treats null as the lesser of two values.
        parts.Sort((Part x, Part y) => 
            x.PartName == null && y.PartName == null
                ? 0
                : x.PartName == null
                    ? -1
                    : y.PartName == null
                        ? 1
                        : x.PartName.CompareTo(y.PartName));

        Console.WriteLine("\nAfter sort by name:");
        parts.ForEach(Console.WriteLine);

        /*

            Before sort:
        ID: 1434   Name: regular seat
        ID: 1234   Name: crank arm
        ID: 1634   Name: shift lever
        ID: 1334   Name:
        ID: 1444   Name: banana seat
        ID: 1534   Name: cassette

        After sort by part number:
        ID: 1234   Name: crank arm
        ID: 1334   Name:
        ID: 1434   Name: regular seat
        ID: 1444   Name: banana seat
        ID: 1534   Name: cassette
        ID: 1634   Name: shift lever

        After sort by name:
        ID: 1334   Name:
        ID: 1444   Name: banana seat
        ID: 1534   Name: cassette
        ID: 1234   Name: crank arm
        ID: 1434   Name: regular seat
        ID: 1634   Name: shift lever

         */
    }
}
Imports System.Collections.Generic

' Simple business object. A PartId is used to identify the type of part 
' but the part name can change. 
Public Class Part
    Implements IEquatable(Of Part)
    Implements IComparable(Of Part)
    Public Property PartName() As String
        Get
            Return m_PartName
        End Get
        Set(value As String)
            m_PartName = Value
        End Set
    End Property
    Private m_PartName As String

    Public Property PartId() As Integer
        Get
            Return m_PartId
        End Get
        Set(value As Integer)
            m_PartId = Value
        End Set
    End Property
    Private m_PartId As Integer

    Public Overrides Function ToString() As String
        Return "ID: " & PartId & "   Name: " & PartName
    End Function

    Public Overrides Function Equals(obj As Object) As Boolean
        If obj Is Nothing Then
            Return False
        End If
        Dim objAsPart As Part = TryCast(obj, Part)
        If objAsPart Is Nothing Then
            Return False
        Else
            Return Equals(objAsPart)
        End If
    End Function

    Public Function SortByNameAscending(name1 As String, name2 As String) As Integer

        Return name1.CompareTo(name2)
    End Function

    ' Default comparer for Part.
    Public Function CompareTo(comparePart As Part) As Integer _
            Implements IComparable(Of ListSortVB.Part).CompareTo
        ' A null value means that this object is greater.
        If comparePart Is Nothing Then
            Return 1
        Else

            Return Me.PartId.CompareTo(comparePart.PartId)
        End If
    End Function
    Public Overrides Function GetHashCode() As Integer
        Return PartId
    End Function
    Public Overloads Function Equals(other As Part) As Boolean Implements IEquatable(Of ListSortVB.Part).Equals
        If other Is Nothing Then
            Return False
        End If
        Return (Me.PartId.Equals(other.PartId))
    End Function
    ' Should also override == and != operators.

End Class
Public Class Example
    Public Shared Sub Main()
        ' Create a list of parts.
        Dim parts As New List(Of Part)()

        ' Add parts to the list.
        parts.Add(New Part() With { _
             .PartName = "regular seat", _
             .PartId = 1434 _
        })
        parts.Add(New Part() With { _
             .PartName = "crank arm", _
             .PartId = 1234 _
        })
        parts.Add(New Part() With { _
             .PartName = "shift lever", _
             .PartId = 1634 _
        })


        ' Name intentionally left null.
        parts.Add(New Part() With { _
             .PartId = 1334 _
        })
        parts.Add(New Part() With { _
             .PartName = "banana seat", _
             .PartId = 1444 _
        })
        parts.Add(New Part() With { _
             .PartName = "cassette", _
             .PartId = 1534 _
        })


        ' Write out the parts in the list. This will call the overridden 
        ' ToString method in the Part class.
        Console.WriteLine(vbLf & "Before sort:")
        For Each aPart As Part In parts
            Console.WriteLine(aPart)
        Next


        ' Call Sort on the list. This will use the 
        ' default comparer, which is the Compare method 
        ' implemented on Part.
        parts.Sort()


        Console.WriteLine(vbLf & "After sort by part number:")
        For Each aPart As Part In parts
            Console.WriteLine(aPart)
        Next

        ' This shows calling the Sort(Comparison(T) overload using 
        ' an anonymous delegate method. 
        ' This method treats null as the lesser of two values.
        parts.Sort(Function(x As Part, y As Part)
                       If x.PartName Is Nothing AndAlso y.PartName Is Nothing Then
                           Return 0
                       ElseIf x.PartName Is Nothing Then
                           Return -1
                       ElseIf y.PartName Is Nothing Then
                           Return 1
                       Else
                           Return x.PartName.CompareTo(y.PartName)
                       End If
                   End Function)


        Console.WriteLine(vbLf & "After sort by name:")
        For Each aPart As Part In parts
            Console.WriteLine(aPart)
        Next

        '
        '        
        '            Before sort:
        '            ID: 1434   Name: regular seat
        '            ID: 1234   Name: crank arm
        '            ID: 1634   Name: shift lever
        '            ID: 1334   Name:
        '            ID: 1444   Name: banana seat
        '            ID: 1534   Name: cassette
        '
        '            After sort by part number:
        '            ID: 1234   Name: crank arm
        '            ID: 1334   Name:
        '            ID: 1434   Name: regular seat
        '            ID: 1444   Name: banana seat
        '            ID: 1534   Name: cassette
        '            ID: 1634   Name: shift lever
        '
        '            After sort by name:
        '            ID: 1334   Name:
        '            ID: 1444   Name: banana seat
        '            ID: 1534   Name: cassette
        '            ID: 1234   Name: crank arm
        '            ID: 1434   Name: regular seat
        '            ID: 1634   Name: shift lever

    End Sub
End Class

참고하십시오