C # dizilerini karşılaştırmanın en kolay yolu


180

Java'da, Arrays.equals()iki temel dizinin içeriğini kolayca karşılaştırmaya izin verir (tüm temel türler için aşırı yükler mevcuttur).

C # 'da böyle bir şey var mı? C # iki dizinin içeriğini karşılaştırmak için herhangi bir "sihirli" yolu var mı?


1
Bu teknik diğer benzer .net tabanlı dillerde kullanılabileceğinden etiketlere '.net' eklendi.
Evan Plaice

3
Bunu okuyan herkes için, kabul edilen cevabın SequenceEqual kullandığını unutmayın. SequenceEqual sadece aynı verileri içerip içermediklerini kontrol etmekle kalmaz, aynı verileri aynı sırada içerip içermediklerini de kontrol eder
John Demetriou

Yanıtlar:


262

Kullanabilirsin Enumerable.SequenceEqual. Bu IEnumerable<T>sadece diziler için değil, her dizide işe yarar.


Bu sadece aynı sırada olmaları durumunda işe yarar
John Demetriou

1
SequenceEqualakıllıca bir iyi performans performansı olmayabilir, çünkü mevcut uygulaması kaynaklarından birini yalnızca uzunluk olarak farklılık gösterirse tam olarak numaralandırabilir. LengthDizilerle, farklı uzunluklardaki dizilerin sadece sonuç vermesi için numaralandırılmasından kaçınmak için önce eşitliği kontrol edebiliriz false.
Frédéric

72

Kullanım Enumerable.SequenceEqualiçinde 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

1
Bunun boş argümanlar için atıldığını unutmayın, bu yüzden bunu varsaymamaya dikkat edinnew int[] {1}.SequenceEquals(null) == false
sara

30

Ayrıca diziler (ve tuples) için .NET 4.0'dan yeni arabirimler kullanabilirsiniz: IStructuralComparable ve IStructuralEquatable . Bunları kullanarak sadece dizilerin eşitliğini kontrol etmekle kalmaz, aynı zamanda onları da karşılaştırabilirsiniz.

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
}

Affedersiniz, bu 1 veya 0 inç olmalı a.StructuralCompare(b)mı?
mafu

Büyük değer türü dizilerde, bunların kullanılmasında bir performans isabeti vardır, çünkü mevcut uygulamaları karşılaştırmak için her değeri kutulayacaktır.
Frédéric

18

İçin .NET 4.0 ve üzeri kullanmakta aracılığıyla dizideki eleman veya dizilerini karşılaştırabilirsiniz StructuralComparisons türü:

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

Düzenleme: Çok erken konuştu. StructualEqualityCompareble ile IStructuralComparable yapabilir miyim? Hangisinin "önce" geldiğini bulmak için CompareTo iki nesne dizisi ile aramak istiyorum. IStructuralComparable se1 = a1'i denedim; Console.WriteLine (se1.CompareTo (a2, StructuralComparisons.StructuralEqualityComparer)); Alma: 'System.Collections.IEqualityComparer'
öğesinden

1
Tamam - doğru çağrı: IStructuralComparable se1 = a1; Console.WriteLine (se1.CompareTo (a2, StructuralComparisons.StructuralComparer));
shindigo

15

SequenceEqual yalnızca iki koşul veya karşılandığında doğru dönecektir.

  1. Aynı elementleri içerirler.
  2. Öğeler aynı sırada.

Sadece siparişlerine bakılmaksızın aynı öğeleri içerip içermediklerini kontrol etmek istiyorsanız ve sorununuz türü

Değer2, değerler1'de yer alan tüm değerleri içeriyor mu?

LINQ genişletme yöntemini kullanabilir Enumerable.Exceptve ardından sonucun herhangi bir değeri olup olmadığını kontrol edebilirsiniz. İşte bir örnek

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
}

Ayrıca bunu kullanarak farklı öğeleri otomatik olarak da alabilirsiniz. Bir taşla iki kuş.

Kodunuzu bu şekilde yürütürseniz unutmayın

var result = values2.Except(values1);

farklı sonuçlar elde edersiniz.

Benim durumumda bir dizinin yerel bir kopyası var ve bu yöntemi kullanmak için bir şey orijinal diziden kaldırılmış olup olmadığını kontrol etmek istiyorum.


2
Aynı değerleri farklı sırayla içeren diziler EQUAL DEĞİLDİR. 'Demetriou' == 'uoirtemeD' var mı?
edc65

Bu bağlıdır. Dizileri sırasız koleksiyonlar olarak kullanıyorsanız ve yalnızca aynı öğeleri (ör. Bir yapılandırma listesine karşı veritabanındaki değerler) içerip içermediklerini kontrol etmeniz gerekiyorsa, bulduğum en kolay yol budur. Sipariş önemliyse (örneğin, bir dize), o zaman kullanırsınız SequenceEqual.
Armando

11

Birim testleri için CollectionAssert.AreEqualyerine kullanabilirsiniz Assert.AreEqual.

Muhtemelen en kolay yol budur.


11

nullGirdileri zarif bir şekilde işlemek ve öğelerin sırasını yoksaymak istiyorsanız , aşağıdaki çözümü deneyin:

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

Test kodu şuna benzer:

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.
    }
}

Bu benim için yararlı oldu, ancak eğer a1 = { 1, 1 }ve a2 = { 1, 2 }sonra ilk test yanlış sonucu döndürür. İade beyanı şu olmalıdırreturn array1.Count() == array2.Count() && !array1.Except(array2).Any() && !array2.Except(array1).Any();
Polshgiant

2

Bazı uygulamalar için daha iyi olabilir:

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

2

Bu LINQ çözümü, performansta SequenceEquals ile nasıl karşılaştırılacağından emin değildir. Ancak farklı dizi uzunluklarını işler ve .All tüm dizi boyunca yineleme yapmadan eşit olmayan ilk öğeden çıkar.

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

elementwise karşılaştırmak? ne dersin

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) koşulunu a ve b'de karşılaştırmak istediğiniz herhangi bir şeyle değiştirin.

(bu, MSDN geliştiricisi Linq örneklerinden iki örneği birleştirir )


1
Farklı uzunluktaki dizileri ( yanlış verilebilir true) ve nulldizileri (çökecek) işlemez .
Frédéric

1

Bunu görsel stüdyolarda yaptım ve mükemmel çalıştı; dizinin dizine göre dizini bu kodla karşılaştırır.

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

çıktı; Eşleşen sayılar 7'dir Eşleşmeyen sayılar 3'tür


2
Farklı uzunluktaki nulldizileri ( çökecek), dizileri (çok çökecek) işlemez ve OP'nin istediklerinden başka bir şey yapar. Kaç öğenin farklı olduğunu veya eşleştiğini saymadan sadece eşitliği bilmek istedi.
Frédéric

0

İki dizide aynı dizinler eşit elemanları dizisi eşitlik aracı varsayarsak, orada SequenceEqualcevap ve IStructuralEquatablecevap .

Ancak her ikisinin de performans açısından dezavantajları vardır.

SequenceEqual mevcut uygulama, dizilerin farklı uzunluklara sahip olduğu durumlarda kısayol oluşturmaz ve bu nedenle, öğelerinden her birini karşılaştırarak bunlardan birini tamamen numaralandırabilir.

IStructuralEquatablejenerik değildir ve karşılaştırılan her değerin boksuna neden olabilir. Dahası, kullanımı çok kolay değildir ve zaten onu gizleyen bazı yardımcı yöntemleri kodlamayı gerektirir.

Performans açısından akıllıca bir şey kullanmak daha iyi olabilir:

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

Ama tabii ki, bu dizi eşitliğini kontrol etmenin "sihirli yolu" da değil.

Yani, şu anda, Arrays.equals().Net'teki Java'ya gerçekten eşdeğer değil .


Birinci ve ikinci her ikisi de null olmak doğru olmaz mı? null == null, değil mi?
Jesse Williams

1
İlk test her ikisi de doğruysa geri döner null. Amacın ne?
Frédéric

1
if (first [i]! = second [i]) jeneriklerle çalışmazsa. İf (! First [i] .Equals (second [i])) öğesini kullanmalısınız.
Jack Griffin
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.