programing

C#에서 어레이를 비교하는 가장 쉬운 방법

lovejava 2023. 5. 19. 23:53

C#에서 어레이를 비교하는 가장 쉬운 방법

자바에서는,Arrays.equals()두 개의 기본 배열의 내용을 쉽게 비교할 수 있습니다(모든 기본 유형에 대해 사용 가능).

C#에 그런 것이 있습니까?C#에서 두 배열의 내용을 비교할 수 있는 "마법적인" 방법이 있습니까?

당신은 할 수 있습니다.이 기능은 모든 사용자에게 적합합니다.IEnumerable<T>어레이뿐만이 아닙니다.

LINQ에서 사용합니다.

int[] arr1 = new int[] { 1,2,3};
int[] arr2 = new int[] { 3,2,1 };

Console.WriteLine(arr1.SequenceEqual(arr2)); // false
Console.WriteLine(arr1.Reverse().SequenceEqual(arr2)); // true

어레이(및 튜플)의 경우에도 .NET 4.0: I Structural Comparable 및 I StructuralEquatable의 새 인터페이스를 사용할 수 있습니다.이를 사용하면 배열의 동일성을 확인할 수 있을 뿐만 아니라 비교할 수도 있습니다.

static class StructuralExtensions
{
    public static bool StructuralEquals<T>(this T a, T b)
        where T : IStructuralEquatable
    {
        return a.Equals(b, StructuralComparisons.StructuralEqualityComparer);
    }

    public static int StructuralCompare<T>(this T a, T b)
        where T : IStructuralComparable
    {
        return a.CompareTo(b, StructuralComparisons.StructuralComparer);
    }
}

{
    var a = new[] { 1, 2, 3 };
    var b = new[] { 1, 2, 3 };
    Console.WriteLine(a.Equals(b)); // False
    Console.WriteLine(a.StructuralEquals(b)); // True
}
{
    var a = new[] { 1, 3, 3 };
    var b = new[] { 1, 2, 3 };
    Console.WriteLine(a.StructuralCompare(b)); // 1
}

SequenceEqual두 가지 조건이 충족되거나 충족된 경우에만 true가 반환됩니다.

  1. 동일한 요소를 포함합니다.
  2. 요소의 순서가 동일합니다.

주문에 관계없이 동일한 요소가 포함되어 있는지 여부만 확인하고 싶은 경우 문제가 유형입니다.

value2가 value1에 포함된 모든 값을 포함합니까?

LINQ 방법 LINQ를 할 수 .Enumerable.Except결과에 값이 있는지 확인합니다.예가 .

int[] values1 = { 1, 2, 3, 4 };
int[] values2 = { 1, 2, 5 };
var result = values1.Except(values2);
if(result.Count()==0)
{
   //They are the same
}
else
{
    //They are different
}

그리고 이것을 사용함으로써 다른 아이템들도 자동으로 얻을 수 있습니다.일석이조.

만약 당신이 코드를 이렇게 실행한다면, 명심하세요.

var result = values2.Except(values1);

당신은 다른 결과를 얻을 것입니다.

제 경우에는 배열의 로컬 복사본이 있는데 원래 배열에서 제거된 항목이 있는지 확인하고 싶어서 이 방법을 사용합니다.

.NET 4.0 이상의 경우 구조 비교 유형을 사용하여 배열 또는 튜플의 요소를 비교할 수 있습니다.

object[] a1 = { "string", 123, true };
object[] a2 = { "string", 123, true };

Console.WriteLine (a1 == a2);        // False (because arrays is reference types)
Console.WriteLine (a1.Equals (a2));  // False (because arrays is reference types)

IStructuralEquatable se1 = a1;
//Next returns True
Console.WriteLine (se1.Equals (a2, StructuralComparisons.StructuralEqualityComparer)); 

당신이 처리하고 싶다면,null입력은 우아하게 하고 항목 순서는 무시하고 다음 솔루션을 사용해 보십시오.

static class Extensions
{
    public static bool ItemsEqual<TSource>(this TSource[] array1, TSource[] array2)
    {
        if (array1 == null && array2 == null)
            return true;
        if (array1 == null || array2 == null)
            return false;
        if (array1.Count() != array2.Count())
            return false;
        return !array1.Except(array2).Any() && !array2.Except(array1).Any();
    }
}

테스트 코드는 다음과 같습니다.

public static void Main()
{
    int[] a1 = new int[] { 1, 2, 3 };
    int[] a2 = new int[] { 3, 2, 1 };
    int[] a3 = new int[] { 1, 3 };
    Console.WriteLine(a1.ItemsEqual(a2)); // Output: True.
    Console.WriteLine(a2.ItemsEqual(a3)); // Output: False.
    Console.WriteLine(a3.ItemsEqual(a2)); // Output: False.
   
    int[] a4 = new int[] { 1, 1 };
    int[] a5 = new int[] { 1, 2 };
    Console.WriteLine(a4.ItemsEqual(a5)); // Output: False 
    Console.WriteLine(a5.ItemsEqual(a4)); // Output: False 
    
    int[] a6 = null;
    int[] a7 = null;
    int[] a8 = new int[0];

    Console.WriteLine(a6.ItemsEqual(a7)); // Output: True. No Exception.
    Console.WriteLine(a8.ItemsEqual(a6)); // Output: False. No Exception.
    Console.WriteLine(a7.ItemsEqual(a8)); // Output: False. No Exception.
}

단위 검정의 경우 다음을 사용할 수 있습니다.CollectionAssert.AreEqualAssert.AreEqual.

그것이 아마도 가장 쉬운 방법일 것입니다.

일부 애플리케이션의 경우 다음과 같은 이점이 있습니다.

string.Join(",", arr1) == string.Join(",", arr2)

배열이 동일하다는 것은 두 배열이 동일한 인덱스에서 동일한 요소를 갖는다는 것을 의미한다고 가정하면 정답정답이 있습니다.

하지만 둘 다 성능 면에서 단점이 있습니다.

SequenceEqual에서의 하여 그 중할 수 있습니다.NetFramework는 배열의 길이가 다를 때 바로 가기를 사용하지 않으므로 각 요소를 비교하여 그 중 하나를 전체적으로 열거할 수 있습니다.
이것은 에 따라 다릅니다.순 맛(예: .).Net5), 단축될 수 있습니다. 이 설명을 참조하십시오.그래서 최신 정보를 위해서요.넷 프로젝트,SequenceEqual좋은 선택이 되어야 합니다.

IStructuralEquatable일반적이지 않으며 각 비교 값의 복싱을 유발할 수 있습니다.게다가 그것은 사용하기가 매우 간단하지 않고 이미 그것을 숨기는 몇몇 도우미 방법을 코딩해야 합니다.

다음과 같은 것을 사용하는 것이 성능 면에서 더 나을 수 있습니다.

bool ArrayEquals<T>(T[] first, T[] second)
{
    if (first == second)
        return true;
    if (first == null || second == null)
        return false;
    if (first.Length != second.Length)
        return false;
    for (var i = 0; i < first.Length; i++)
    {
        if (!first[i].Equals(second[i]))
            return false;
    }
    return true;
}

하지만 물론, 이것은 배열 동일성을 확인하는 "마법적인 방법"은 아닙니다.

그래서 현재, 아니요, 실제로 자바와 동등한 것은 없습니다.Arrays.equals()네트.

이 LINQ 솔루션은 작동하지만 Sequence Equals와 성능이 어떻게 비교되는지는 잘 모르겠습니다.그러나 다른 배열 길이 및 를 처리합니다.전체 배열을 반복하지 않고 동일하지 않은 첫 번째 항목에서 모두 종료됩니다.

private static bool arraysEqual<T>(IList<T> arr1, IList<T> arr2)
        =>
            ReferenceEquals(arr1, arr2) || (
                arr1 != null && arr2 != null &&
                arr1.Count == arr2.Count &&
                arr1.Select((a, i) => arr2[i].Equals(a)).All(i => i)
            );

요소적으로 비교? 어때요?

public void Linq78a()
{
 int[] numbers1 = { 5, 4, 1, 3, 9, 8, 6, 7, 2, 0 };
 int[] numbers = { 5, 4, 1, 3, 9, 8, 6, 7, 2, 0 };
 bool bb = numbers.Zip(numbers1, (a, b) => (a == b)).Any(p => !p);
 if (!bb) Console.WriteLine("Lists are equal (bb)");
   else Console.WriteLine("Lists are not equal (bb)");
}

(a==b) 조건을 a와 b에서 비교할 항목으로 대체합니다.

(MSDN 개발자 Linq 샘플의 두 가지 예를 결합한 것입니다.)

저는 비주얼 스튜디오에서 이것을 했고 완벽하게 작동했습니다. 인덱스별 배열과 이 코드를 짧게 비교했습니다.

private void compareButton_Click(object sender, EventArgs e)
        {
            int[] answer = { 1, 3, 4, 6, 8, 9, 5, 4, 0, 6 };
            int[] exam = { 1, 2, 3, 6, 8, 9, 5, 4, 0, 7 };

            int correctAnswers = 0;
            int wrongAnswers = 0;

            for (int index = 0; index < answer.Length; index++)
            {
                if (answer[index] == exam[index])
                {
                    correctAnswers += 1;
                }
                else
                {
                    wrongAnswers += 1;
                }
            }

            outputLabel.Text = ("The matching numbers are " + correctAnswers +
                "\n" + "The non matching numbers are " + wrongAnswers);
        }

출력은 다음과 같습니다. 일치하는 숫자는 7입니다. 일치하지 않는 숫자는 3입니다.

사용할 수 있습니다.Enumerable.Intersect:

int[] array1 = new int[] { 1, 2, 3, 4,5 },
      array2 = new int[] {7,8};

if (array1.Intersect(array2).Any())
    Console.WriteLine("matched");
else
    Console.WriteLine("not matched");

저는 두 세트가 어떤 순서로든 같은 내용을 가지고 있는지 확인하려고 했습니다., 각 두 값을 것입니다. 즉, 집 A의 합 각 대 모 집 두 에 서 두 값 해 가 요 의 소 수 의 다 가 것 합 니 미 같 는 을 다 진 을 당 합 해 에 소 요 ▁that ▁with ▁a , 집 ▁of 즉 ▁in ▁sets 의 ▁that ▁there ▁numbers ▁were ▁set ▁in ▁meant ▁value 다 합 ▁for ▁equal ,중복 항목을 설명하고 싶었습니다(그래서{1,2,2,3}그리고.{1,2,3,3}"동일"로 간주해서는 안 됩니다.

이것이 제가 생각해 낸 것입니다(IsNullOrEmpty는 열거형이 null이거나 요소가 0인 경우 true를 반환하는 또 다른 정적 확장 메서드입니다).

    public static bool HasSameContentsAs<T>(this IEnumerable<T> source, IEnumerable<T> target) 
        where T : IComparable
    {
        //If our source is null or empty, then it's just a matter of whether or not the target is too
        if (source.IsNullOrEmpty())
            return target.IsNullOrEmpty();

        //Otherwise, if the target is null/emtpy, they can't be equal
        if (target.IsNullOrEmpty())
            return false;

        //Neither is null or empty, so we'll compare contents.  To account for multiples of 
        //a given value (ex. 1,2,2,3 and 1,1,2,3 are not equal) we'll group the first set
        foreach (var group in source.GroupBy(s => s))
        {
            //If there are a different number of elements in the target set, they don't match
            if (target.Count(t => t.Equals(group.Key)) != group.Count())
                return false;
        }

        //If we got this far, they have the same contents
        return true;
    }

사용할 수도 있습니다.array1.ToList().All(x => array2.Contains(x))가 동일하지 아배을 비야하 는경우 해교동 열닌서가▁which경

주문을 비교하고 싶지 않지만 null 값 처리를 포함하여 각 항목의 개수를 비교하려면 확장 방법을 작성했습니다.

예를 들어 다음과 같은 결과를 제공합니다.

new int?[]{  }.IgnoreOrderComparison(new int?{ });                            // true
new int?[]{ 1 }.IgnoreOrderComparison(new int?{ });                           // false
new int?[]{ }.IgnoreOrderComparison(new int?{ 1 });                           // false
new int?[]{ 1 }.IgnoreOrderComparison(new int?{ 1 });                         // true
new int?[]{ 1, 2 }.IgnoreOrderComparison(new int?{ 2, 1 });                   // true
new int?[]{ 1, 2, null }.IgnoreOrderComparison(new int?{ 2, 1 });             // false
new int?[]{ 1, 2, null }.IgnoreOrderComparison(new int?{ null, 2, 1 });       // true
new int?[]{ 1, 2, null, null }.IgnoreOrderComparison(new int?{ null, 2, 1 }); // false
new int?[]{ 2 }.IgnoreOrderComparison(new int?{ 2, 2 });                      // false
new int?[]{ 2, 2 }.IgnoreOrderComparison(new int?{ 2, 2 });                   // true

코드는 다음과 같습니다.

public static class ArrayComparisonExtensions
{
    public static bool IgnoreOrderComparison<TSource>(this IEnumerable<TSource> first, IEnumerable<TSource> second) =>
        IgnoreOrderComparison(first, second, EqualityComparer<TSource>.Default);

    public static bool IgnoreOrderComparison<TSource>(this IEnumerable<TSource> first, IEnumerable<TSource> second, IEqualityComparer<TSource> comparer)
    {
        var a = ToDictionary(first, out var firstNullCount);
        var b = ToDictionary(second, out var secondNullCount);

        if (a.Count != b.Count)
            return false;

        if (firstNullCount != secondNullCount)
            return false;

        foreach (var item in a)
        {
            if (b.TryGetValue(item.Key, out var count) && item.Value == count)
                continue;
            return false;
        }


        return true;

        Dictionary<TSource, int> ToDictionary(IEnumerable<TSource> items, out int nullCount)
        {
            nullCount = 0;
            var result = new Dictionary<TSource, int>(comparer);
            foreach (var item in items)
            {
                if (item is null)
                    nullCount++;
                else if (result.TryGetValue(item, out var count))
                    result[item] = count + 1;
                else
                    result[item] = 1;
            }

            return result;
        }
    }
}

각 열거형을 한 번만 열거하지만 각 열거형에 대한 사전을 만들고 이러한 사전도 한 번 반복합니다.저는 이것을 개선할 수 있는 방법에 관심이 있습니다.

배열 중 하나를 다음으로 변환하는 이 스레드에 대한 답을 확인합니다.HashSet 및용을 합니다.SetEquals다른 배열과 비교할 수 있습니다.그러나 이렇게 하면 주문 또는 중복이 확인되지 않습니다.

목록 패턴은 C#11에 추가되었습니다.네트 7 RC2.

int[] numbers = { 1, 2, 3 };

Console.WriteLine(numbers is [1, 2, 3]);  // True
Console.WriteLine(numbers is [1, 2, 4]);  // False
        int[] a = { 2, 1, 3, 4, 5, 2 };

        int[] b = { 2, 1, 3, 4, 5, 2 };

        bool ans = true;

        if(a.Length != b.Length)
        {
            ans = false;
        }
        else
        {
            for (int i = 0; i < a.Length; i++)
            {
                if( a[i] != b[i])
                {
                    ans = false;
                }
            }
        }

        string str = "";

        if(ans == true)
        {
            str = "Two Arrays are Equal";
        }

        if (ans == false)
        {
            str = "Two Arrays are not Equal";
        }

       //--------------Or You can write One line of Code-------------

        var ArrayEquals = a.SequenceEqual(b);   // returns true

언급URL : https://stackoverflow.com/questions/3232744/easiest-way-to-compare-arrays-in-c-sharp