Cara termudah untuk membandingkan array di C #


180

Di Jawa, Arrays.equals()memungkinkan untuk dengan mudah membandingkan konten dua array dasar (kelebihan tersedia untuk semua tipe dasar).

Apakah ada hal seperti itu di C #? Apakah ada cara "ajaib" untuk membandingkan konten dua array di C #?


1
Menambahkan '.net' ke tag karena teknik ini dapat digunakan dalam bahasa berbasis .net yang serupa.
Evan Plaice

3
Untuk semua orang yang membaca ini, perlu diingat bahwa jawaban yang diterima menggunakan SequenceEqual. SequenceEqual tidak hanya memeriksa apakah mereka berisi data yang sama, tetapi juga jika mereka berisi data yang sama dalam urutan yang sama
John Demetriou

Jawaban:


262

Anda bisa menggunakannya Enumerable.SequenceEqual. Ini berfungsi untuk semua IEnumerable<T>, bukan hanya array.


Ini hanya berfungsi jika mereka berada dalam urutan yang sama
John Demetriou

1
SequenceEqualmungkin bukan pilihan kinerja yang baik, karena implementasi saat ini dapat sepenuhnya menyebutkan salah satu sumbernya jika mereka hanya berbeda panjangnya. Dengan array, kita dapat memeriksa Lengthkesetaraan terlebih dahulu, untuk menghindari penghitungan array yang berbeda panjang hanya untuk menghasilkan akhir false.
Frédéric

72

Gunakan Enumerable.SequenceEqualdi 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
Perlu diingat bahwa ini melempar argumen nol, jadi pastikan untuk tidak berasumsi bahwanew int[] {1}.SequenceEquals(null) == false
sara

30

Juga untuk array (dan tupel) Anda dapat menggunakan antarmuka baru dari .NET 4.0: IStructuralComparable dan IStructuralEquatable . Dengan menggunakannya, Anda tidak hanya dapat memeriksa persamaan array tetapi juga membandingkannya.

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
}

Maafkan saya, apakah itu angka 1 atau 0 a.StructuralCompare(b)?
mafu

Pada array tipe nilai besar, ada hit kinerja dalam menggunakan ini, karena implementasi mereka saat ini akan kotak setiap nilai untuk membandingkan.
Frédéric

18

Untuk .NET 4.0 dan lebih tinggi, Anda dapat membandingkan elemen dalam array atau tupel melalui penggunaan tipe 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)); 

Sunting: Berbicara terlalu cepat. Bisakah saya melakukan StructualEqualityCompare dengan IStructuralComparable? Saya ingin memanggil CompareTo dengan dua array objek untuk mencari tahu mana yang datang "pertama". Saya mencoba IStructuralComparable se1 = a1; Console.WriteLine (se1.CompareTo (a2, StructuralComparisons.StructuralEqualityComparer)); Mendapatkan: tidak dapat mengonversi dari 'System.Collections.IEqualityComparer' ke 'System.Collections.IComparer'
shindigo

1
OK - panggilan yang benar adalah: IStructuralComparable se1 = a1; Console.WriteLine (se1.CompareTo (a2, StructuralComparisons.StructuralComparer));
shindigo

15

SequenceEqual hanya akan mengembalikan true jika dua syarat atau terpenuhi.

  1. Mereka mengandung elemen yang sama.
  2. Elemen-elemennya berada dalam urutan yang sama.

Jika Anda hanya ingin memeriksa apakah mereka mengandung elemen yang sama terlepas dari pesanan mereka dan masalah Anda adalah tipe

Apakah values2 berisi semua nilai yang terkandung dalam values1?

Anda dapat menggunakan metode ekstensi LINQ Enumerable.Exceptdan kemudian memeriksa apakah hasilnya memiliki nilai. Ini sebuah contoh

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
}

Dan juga dengan menggunakan ini Anda mendapatkan item yang berbeda secara otomatis. Dua burung dengan satu batu.

Perlu diingat, jika Anda menjalankan kode Anda seperti ini

var result = values2.Except(values1);

Anda akan mendapatkan hasil yang berbeda.

Dalam kasus saya, saya memiliki salinan lokal array dan ingin memeriksa apakah ada yang telah dihapus dari array asli jadi saya menggunakan metode ini.


2
Array berisi nilai yang sama dalam urutan yang berbeda, hanya BUKAN SAMA. Apakah Anda menganggap 'Demetriou' == 'uoirtemeD'?
edc65

Itu tergantung. Jika Anda menggunakan array sebagai koleksi yang tidak berurutan dan perlu memeriksa hanya bahwa mereka mengandung elemen yang sama (misalnya, nilai dari database terhadap daftar konfigurasi), maka ini adalah cara termudah yang saya temukan. Jika pesanan itu penting (mis. String), maka Anda akan menggunakannya SequenceEqual.
Armando

11

Untuk pengujian unit, Anda dapat menggunakan CollectionAssert.AreEqualsebagai ganti Assert.AreEqual.

Ini mungkin cara termudah.


11

Jika Anda ingin menangani nullinput dengan anggun, dan mengabaikan urutan item, coba solusi berikut:

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

Kode tes terlihat seperti:

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

Ini bermanfaat bagi saya, tetapi jika a1 = { 1, 1 }dan a2 = { 1, 2 }, maka tes pertama mengembalikan hasil yang salah. Pernyataan pengembalian harusreturn array1.Count() == array2.Count() && !array1.Except(array2).Any() && !array2.Except(array1).Any();
Polshgiant

2

Untuk beberapa aplikasi mungkin lebih baik:

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

2

Solusi LINQ ini berfungsi, tidak yakin bagaimana ia membandingkan kinerja dengan SequenceEquals. Tapi ia menangani panjang array yang berbeda dan. Semua akan keluar pada item pertama yang tidak sama tanpa mengulangi seluruh array.

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

membandingkan elemen? bagaimana dengan

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

Ganti kondisi (a == b) dengan apa pun yang ingin Anda bandingkan dalam a dan b.

(ini menggabungkan dua contoh dari sampel Linq pengembang MSDN )


1
Ini tidak menangani array dengan panjang yang berbeda (mungkin tidak benar menghasilkan true) dan nullarray (akan crash).
Frédéric

1

Saya melakukan ini di studio visual dan bekerja dengan sempurna; membandingkan array indeks dengan indeks dengan pendek kode ini.

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

hasilnya adalah; Angka yang cocok adalah 7 Angka yang tidak cocok adalah 3


2
Itu tidak menangani array dengan panjang yang berbeda (akan crash), nullarray (akan crash juga), dan ia melakukan sesuatu yang lain dari apa yang diminta OP. Dia hanya meminta untuk mengetahui kesetaraan, tanpa menghitung berapa banyak item yang berbeda atau cocok.
Frédéric

0

Dengan asumsi persamaan array berarti kedua array memiliki elemen yang sama pada indeks yang sama, ada SequenceEqualjawabannya dan IStructuralEquatablejawabannya .

Tetapi keduanya memiliki kelemahan, kinerja bijaksana.

SequenceEqual implementasi saat ini tidak akan memendek ketika array memiliki panjang yang berbeda, dan karena itu dapat menghitung satu dari mereka sepenuhnya, membandingkan masing-masing elemen.

IStructuralEquatabletidak generik dan dapat menyebabkan tinju dari setiap nilai yang dibandingkan. Selain itu tidak terlalu mudah untuk digunakan dan sudah memanggil untuk pengkodean beberapa metode pembantu menyembunyikannya.

Mungkin lebih baik, kinerja bijaksana, untuk menggunakan sesuatu seperti:

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

Tapi tentu saja, itu bukan "cara ajaib" untuk memeriksa persamaan array.

Jadi saat ini, tidak, sebenarnya tidak ada yang setara dengan Java Arrays.equals()di .Net.


Bukankah pertama dan kedua sama-sama menghasilkan nol benar? null == null, bukan?
Jesse Williams

1
Tes pertama akan kembali benar jika keduanya null. Apa maksudmu
Frédéric

1
if (first [i]! = second [i]) tidak akan berfungsi dengan obat generik. Anda harus menggunakan if (! Pertama [i]. Setara (kedua [i])).
Jack Griffin
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.