Cách dễ nhất để so sánh các mảng trong C #


180

Trong Java, Arrays.equals()cho phép dễ dàng so sánh nội dung của hai mảng cơ bản (quá tải có sẵn cho tất cả các loại cơ bản).

Có một điều như vậy trong C #? Có cách nào "kỳ diệu" để so sánh nội dung của hai mảng trong C # không?


1
Đã thêm '.net' vào các thẻ vì kỹ thuật này có thể được sử dụng trong các ngôn ngữ dựa trên .net tương tự khác.
Evan Plaice

3
Đối với mọi người đọc điều này, hãy nhớ rằng câu trả lời được chấp nhận đang sử dụng SequenceEqual. SequenceEqual không chỉ kiểm tra xem chúng có chứa cùng một dữ liệu hay không, mà còn nếu chúng chứa cùng một dữ liệu theo cùng một thứ tự
John Demetriou

Câu trả lời:


262

Bạn có thể sử dụng Enumerable.SequenceEqual. Điều này làm việc cho bất kỳ IEnumerable<T>, không chỉ mảng.


Điều này chỉ hoạt động nếu chúng theo cùng một thứ tự
John Demetriou

1
SequenceEqualcó thể không phải là một lựa chọn tốt về hiệu suất, vì việc triển khai hiện tại của nó có thể liệt kê đầy đủ một trong các nguồn của nó nếu chúng chỉ khác nhau theo độ dài. Với các mảng, chúng ta có thể kiểm tra Lengthsự bằng nhau trước tiên, để tránh liệt kê các mảng có độ dài khác nhau chỉ để đạt năng suất cuối cùng false.
Frédéric

72

Sử dụng Enumerable.SequenceEqualtrong 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
Hãy nhớ rằng điều này ném cho các đối số null, vì vậy hãy đảm bảo không cho rằngnew int[] {1}.SequenceEquals(null) == false
sara

30

Ngoài ra, đối với các mảng (và bộ dữ liệu), bạn có thể sử dụng các giao diện mới từ .NET 4.0: IStructuralComparableIStructuralEquitable . Sử dụng chúng, bạn không chỉ kiểm tra sự bằng nhau của mảng mà còn so sánh chúng.

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
}

Xin lỗi, tôi nên là 1 hay 0 trong a.StructuralCompare(b)?
mafu

Trên các mảng loại giá trị lớn, có một hiệu năng đạt được khi sử dụng các mảng này, bởi vì việc triển khai hiện tại của chúng sẽ đóng hộp từng giá trị để so sánh.
Frédéric

18

Đối với .NET 4.0 và cao hơn bạn có thể so sánh các yếu tố trong mảng hoặc tuples qua sử dụng StructuralComparisons loại:

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

Chỉnh sửa: Nói quá sớm. Tôi có thể thực hiện StructualEqualityCompare với IStructuralComparable không? Tôi muốn gọi so sánh với hai mảng đối tượng để tìm ra cái nào đến "đầu tiên". Tôi đã thử IStructuralComparable se1 = a1; Console.WriteLine (se1.CompareTo (a2, ArchitecturalComparisons.SturationuralEqualityComparer)); Bắt: không thể chuyển đổi từ 'System.Collections.IEqualityComparer' sang 'System.Collections.IComparer'
shindigo

1
OK - cuộc gọi chính xác là: IStructuralComparable se1 = a1; Console.WriteLine (se1.CompareTo (a2, ArchitecturalComparisons.SturationuralComparer));
shindigo 22/03/2016

15

SequenceEqual sẽ chỉ trả về đúng nếu hai điều kiện hoặc đáp ứng.

  1. Chúng chứa các yếu tố tương tự.
  2. Các yếu tố theo cùng một thứ tự.

Nếu bạn chỉ muốn kiểm tra xem chúng có chứa các phần tử giống nhau không phụ thuộc vào thứ tự của chúng và vấn đề của bạn thuộc loại

Giá trị2 có chứa tất cả các giá trị có trong giá trị1 không?

bạn có thể sử dụng phương pháp mở rộng LINQ Enumerable.Exceptvà sau đó kiểm tra xem kết quả có giá trị nào không. Đây là một ví dụ

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
}

Và cũng bằng cách sử dụng này, bạn sẽ nhận được các mặt hàng khác nhau cũng tự động. Hai con chim với một đá.

Hãy ghi nhớ, nếu bạn thực thi mã của mình như thế này

var result = values2.Except(values1);

bạn sẽ nhận được kết quả khác nhau.

Trong trường hợp của tôi, tôi có một bản sao cục bộ của một mảng và muốn kiểm tra xem có gì đã bị xóa khỏi mảng ban đầu hay không nên tôi sử dụng phương thức này.


2
Mảng chứa các giá trị giống nhau theo thứ tự khác nhau, đơn giản là KHÔNG CẦN THIẾT. Bạn có điều 'Demetriou' == 'uoirtemeD'?
edc65

Mà phụ thuộc. Nếu bạn đang sử dụng các mảng dưới dạng các bộ sưu tập không có thứ tự và chỉ cần kiểm tra xem chúng có chứa các phần tử giống nhau không (ví dụ: các giá trị từ cơ sở dữ liệu đối với danh sách cấu hình), thì đây là cách dễ nhất tôi tìm thấy. Nếu thứ tự không quan trọng (ví dụ: một chuỗi), thì bạn sẽ sử dụng SequenceEqual.
Armando

11

Đối với các bài kiểm tra đơn vị, bạn có thể sử dụng CollectionAssert.AreEqualthay vì Assert.AreEqual.

Nó có lẽ là cách dễ nhất.


11

Nếu bạn muốn xử lý các nullđầu vào một cách duyên dáng và bỏ qua thứ tự của các mục, hãy thử giải pháp sau:

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

Mã kiểm tra trông như:

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

Điều này hữu ích cho tôi, nhưng nếu a1 = { 1, 1 }a2 = { 1, 2 }, thì thử nghiệm đầu tiên trả về kết quả sai. Tuyên bố trở lại phải làreturn array1.Count() == array2.Count() && !array1.Except(array2).Any() && !array2.Except(array1).Any();
Polshgiant

2

Đối với một số ứng dụng có thể tốt hơn:

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

2

Giải pháp LINQ này hoạt động, không chắc nó so sánh hiệu năng với SequenceEquals như thế nào. Nhưng nó xử lý các độ dài mảng khác nhau và. ALL sẽ thoát trên mục đầu tiên không bằng mà không lặp qua toàn bộ mảng.

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

so sánh nguyên tố? Thế còn

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

Thay thế điều kiện (a == b) bằng bất cứ điều gì bạn muốn so sánh trong a và b.

(điều này kết hợp hai ví dụ từ các mẫu Linq của nhà phát triển MSDN )


1
Nó không xử lý các mảng có độ dài khác nhau (có thể mang lại không chính xác true) và nullmảng (sẽ sụp đổ).
Frédéric

1

Tôi đã làm điều này trong các studio hình ảnh và nó hoạt động hoàn hảo; so sánh chỉ số mảng theo chỉ số với mã ngắn này.

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

đầu ra sẽ là; Các số phù hợp là 7 Các số không khớp là 3


2
Nó không xử lý các mảng có độ dài khác nhau (sẽ sụp đổ), nullmảng (cũng sẽ sụp đổ) và nó làm một cái gì đó khác với những gì OP yêu cầu. Ông chỉ yêu cầu được biết bình đẳng, mà không tính có bao nhiêu mặt hàng khác nhau hoặc phù hợp.
Frédéric

0

Giả sử bình đẳng mảng có nghĩa là cả hai mảng có các phần tử bằng nhau ở các chỉ mục bằng nhau, có SequenceEqualcâu trả lờiIStructuralEquatablecâu trả lời .

Nhưng cả hai đều có nhược điểm, hiệu suất khôn ngoan.

SequenceEqual việc thực hiện hiện tại sẽ không tắt khi các mảng có độ dài khác nhau và do đó, nó có thể liệt kê hoàn toàn một trong số chúng, so sánh từng yếu tố của nó.

IStructuralEquatablekhông chung chung và có thể gây ra quyền anh của từng giá trị so sánh. Hơn nữa, nó không đơn giản để sử dụng và đã yêu cầu mã hóa một số phương thức trợ giúp để ẩn nó đi.

Nó có thể tốt hơn, hiệu suất khôn ngoan, để sử dụng một cái gì đó như:

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

Nhưng tất nhiên, đó không phải là một "cách kỳ diệu" để kiểm tra sự bằng nhau của mảng.

Vì vậy, hiện tại, không, thực sự không có tương đương với Java Arrays.equals()trong .Net.


Cả hai thứ nhất và thứ hai đều không có kết quả đúng? null == null, phải không?
Jesse Williams

1
Thử nghiệm đầu tiên sẽ trả về đúng nếu cả hai đều null. Quan điểm của bạn là gì?
Frédéric

1
if (first [i]! = second [i]) sẽ không hoạt động với generic. Bạn phải sử dụng if (! First [i] .Equals (second [i])).
Jack Griffin
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.