C #에서 배열을 비교하는 가장 쉬운 방법


180

Java에서는 Arrays.equals()두 가지 기본 배열의 내용을 쉽게 비교할 수 있습니다 (모든 기본 유형에 대해 과부하를 사용할 수 있음).

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


1
이 기술은 다른 유사한 .net 기반 언어에서 사용될 수 있으므로 태그에 '.net'이 추가되었습니다.
Evan Plaice

3
이 내용을 읽는 모든 사람에게 허용되는 답변은 SequenceEqual을 사용하고 있음을 명심하십시오. SequenceEqual은 동일한 데이터가 포함되어 있는지 확인하고 동일한 데이터가 동일한 순서로 포함되어 있는지 확인합니다.
John Demetriou

답변:


262

사용할 수 있습니다 Enumerable.SequenceEqual. 이것은 IEnumerable<T>배열뿐만 아니라 모든 에 적용됩니다.


비록 같은 순서 일 경우에만 작동합니다
John Demetriou

1
SequenceEqual현재 구현은 길이 만 다르면 소스 중 하나를 완전히 열거 할 수 있기 때문에 성능면에서 현명한 선택이 아닐 수 있습니다. 배열을 사용하면, Length항복 항복을 위해 길이가 다른 배열을 열거하는 것을 피하기 위해 등식을 먼저 확인할 수 있습니다 false.
Frédéric

72

LINQEnumerable.SequenceEqual 에서 사용하십시오 .

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

1
이 경우 null 인수가 발생하므로 다음과 같이 가정하지 마십시오.new int[] {1}.SequenceEquals(null) == false
sara dec

30

또한 배열 (및 튜플)의 경우 .NET 4.0의 새로운 인터페이스 IStructuralComparableIStructuralEquatable을 사용할 수 있습니다 . 그것들을 사용하면 배열의 동등성을 확인할 수있을뿐만 아니라 비교할 수도 있습니다.

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
}

용서하십시오, 1 또는 0이어야 a.StructuralCompare(b)합니까?
mafu

큰 값 유형 배열의 경우 현재 구현에서 비교할 각 값을 상자로 묶기 때문에이를 사용하면 성능이 저하됩니다.
프레데릭

18

들어 .NET 4.0 이상 당신은 사용을 통해 배열의 요소 또는 튜플을 비교할 수 StructuralComparisons의 종류 :

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)); 

편집 : 너무 빨리 스포크. StructualEqualityCompare를 IStructuralComparable과 함께 사용할 수 있습니까? 두 개의 객체 배열을 사용하여 CompareTo를 호출하여 어느 것이 "먼저"인지 알아 내고 싶습니다. IStructuralComparable se1 = a1을 시도했습니다. Console.WriteLine (se1.CompareTo (a2, StructuralComparisons.StructuralEqualityComparer)); 점점 : 'System.Collections.IEqualityComparer'에서 'System.Collections.IComparer'로 변환 할 수 없음
shindigo

1
확인-올바른 호출은 다음과 같습니다. IStructuralComparable se1 = a1; Console.WriteLine (se1.CompareTo (a2, StructuralComparisons.StructuralComparer));
shindigo

15

SequenceEqual 두 조건을 충족하거나 충족하는 경우에만 true를 반환합니다.

  1. 그것들은 같은 요소를 포함합니다.
  2. 요소의 순서는 같습니다.

순서에 관계없이 동일한 요소를 포함하고 있는지 확인하고 문제의 유형이

values2에 values1에 포함 된 모든 값이 포함되어 있습니까?

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);

다른 결과를 얻을 수 있습니다.

필자의 경우 배열의 로컬 사본이 있고 원래 배열에서 제거 된 것이 있는지 확인 하고이 방법을 사용하려고합니다.


2
다른 순서로 동일한 값을 포함하는 배열은 단순히 같지 않습니다. 'Demetriou'== 'uoirtemeD'입니까?
edc65

조건에 따라서. 정렬되지 않은 컬렉션으로 배열을 사용하고 있으며 동일한 구성 요소 (예 : 구성 목록에 대한 데이터베이스 값)가 포함되어 있는지 확인 해야하는 경우 이것이 내가 찾은 가장 쉬운 방법입니다. 순서가 중요하면 (예 : 문자열)을 사용 SequenceEqual합니다.
Armando

11

단위 테스트의 경우 CollectionAssert.AreEqual대신 사용할 수 있습니다 Assert.AreEqual.

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


11

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;
        return array1.Count() == array2.Count() && !array1.Except(array2).Any();
    }
}

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

class Program
{
    static void Main(string[] args)
    {
        int[] a1 = new int[] { 1, 2, 3 };
        int[] a2 = new int[] { 3, 2, 1 };
        int[] a3 = new int[] { 1, 3 };
        int[] a4 = null;
        int[] a5 = null;
        int[] a6 = new int[0];

        Console.WriteLine(a1.ItemsEqual(a2)); // Output: True.
        Console.WriteLine(a2.ItemsEqual(a3)); // Output: False.
        Console.WriteLine(a4.ItemsEqual(a5)); // Output: True. No Exception.
        Console.WriteLine(a4.ItemsEqual(a3)); // Output: False. No Exception.
        Console.WriteLine(a5.ItemsEqual(a6)); // Output: False. No Exception.
    }
}

이것은 나에게 도움이되었지만 a1 = { 1, 1 }and a2 = { 1, 2 }이면 첫 번째 테스트에서 잘못된 결과를 반환합니다. 반환 진술서는return array1.Count() == array2.Count() && !array1.Except(array2).Any() && !array2.Except(array1).Any();
Polshgiant

2

일부 응용 프로그램의 경우 더 좋습니다.

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

2

이 LINQ 솔루션은 성능이 SequenceEquals와 어떻게 비교되는지 확실하지 않습니다. 그러나 다른 배열 길이를 처리하며 .All은 전체 배열을 반복하지 않고 동일하지 않은 첫 번째 항목에서 종료됩니다.

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)
            );

1

요소 별 비교? 이건 어떤가요

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 샘플의 두 가지 예를 결합 합니다 )


1
길이가 다른 배열 ( 잘못 생성 될 수 있음 true)과 null배열 (충돌)을 처리하지 않습니다 .
Frédéric

1

비주얼 스튜디오에서이 작업을 수행했으며 완벽하게 작동했습니다. 이 코드를 사용하여 배열 인덱스를 인덱스별로 비교합니다.

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입니다.


2
길이가 다른 null배열 ( 충돌), 배열 ( 충돌)도 처리하지 않으며 OP가 요청한 것 이외의 작업을 수행합니다. 그는 얼마나 많은 항목이 다르거 나 일치하는지 세지 않고 평등을 알도록 요청했습니다.
프레데릭

0

두 어레이는 동일한 인덱스의 동일 요소 어레이의 등가 수단을 가지고 가정하면,가 SequenceEqual답변 하고 IStructuralEquatable않음 .

그러나 둘 다 성능면에서 단점이 있습니다.

SequenceEqual 현재 구현은 배열의 길이가 다른 경우 단축되지 않으므로 각 요소를 비교하여 배열 중 하나를 완전히 열거 할 수 있습니다.

IStructuralEquatable일반적이 아니며 각 비교 값의 boxing이 발생할 수 있습니다. 또한 사용하기가 쉽지 않고 이미 숨겨져있는 도우미 메서드를 코딩해야합니다.

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

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] != second[i])
            return false;
    }
    return true;
}

그러나 물론 이것은 배열 평등을 확인하는 "마법적인 방법"이 아닙니다.

따라서 현재 아니요 Arrays.equals(). .Net의 Java와 실제로 동등한 것은 아닙니다 .


첫 번째와 두 번째가 모두 null이 아닌 경우 true가됩니까? null == null, 그렇지 않습니까?
Jesse Williams

1
첫 번째 테스트는 둘 다 인 경우 true를 반환합니다 null. 요점이 뭐야?
프레데릭

1
if (first [i]! = second [i])는 제네릭에서 작동하지 않습니다. if (! first [i] .Equals (second [i]))를 사용해야합니다.
잭 그리핀
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.