web-dev-qa-db-fra.com

Meilleure façon de comparer les tableaux en C #

En Java, Arrays.equals () permet de comparer facilement le contenu de deux tableaux de base (des surcharges sont disponibles pour tous les types de base).

Existe-t-il une telle chose en C #? Existe-t-il un moyen "magique" de comparer le contenu de deux tableaux en C #?

130
asmo

Vous pouvez utiliser SequenceEqual . Cela fonctionne pour tout IEnumerable<T>, pas seulement les tableaux. 

201
Quartermeister

Utilisez SequenceEqual dans 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
48
John Buchanan

Vous pouvez également utiliser les nouvelles interfaces à partir de .NET 4.0 pour les tableaux (et les nuplets): IStructuralComparable et IStructuralEquatable . En les utilisant, vous pouvez non seulement vérifier l’égalité des tableaux, mais aussi les comparer.

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
}
25
desco

Pour .NET 4.0 et les versions ultérieures, vous pouvez comparer des éléments de tableaux ou de nuplets en utilisant StructuralComparisons type:

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)); 
15
Yuliia Ashomok

SequenceEqual ne retournera vrai que si deux conditions sont remplies.

  1. Ils contiennent les mêmes éléments. 
  2. Les éléments sont dans le même ordre.

Si vous voulez seulement vérifier s’ils contiennent les mêmes éléments quelle que soit leur ordre et que votre problème est du type

Valeurs2 contient-il toutes les valeurs contenues dans valeurs1?

vous pouvez utiliser la méthode d'extension LINQ Enumerable.Except et ensuite vérifier si le résultat a une valeur quelconque. Voici un exemple

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
}

Et aussi en utilisant cela, vous obtenez automatiquement les différents éléments. Deux oiseaux avec une pierre.

Gardez à l'esprit, si vous exécutez votre code comme ceci 

var result = values2.Except(values1);

vous obtiendrez des résultats différents.

Dans mon cas, j'ai une copie locale d'un tableau et je veux vérifier si quelque chose a été supprimé du tableau d'origine, donc j'utilise cette méthode.

11
John Demetriou

Pour les tests unitaires, vous pouvez utiliser CollectionAssert.AreEqual au lieu de Assert.AreEqual

C'est probablement le moyen le plus simple.

7
Paris Qian Sen

Si vous souhaitez gérer les entrées null avec élégance et ignorer l'ordre des éléments, essayez la solution suivante:

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

Le code de test ressemble à:

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.
    }
}
3
Harry He

Pour certaines applications peut être mieux:

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

Cette solution LINQ fonctionne, mais vous ne savez pas comment elle se compare en termes de performances à SequenceEquals. Mais il gère différentes longueurs de tableau et le .All se terminera sur le premier élément qui n'est pas égal sans itérer dans tout le tableau.

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

comparer élémentairement? qu'en est-il de 

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

Remplacez la condition (a == b) par tout ce que vous souhaitez comparer en a et b.

(cela combine deux exemples à partir de exemples Linq du développeur MSDN )

0
Goodies

En supposant que l'égalité des tableaux signifie que les deux tableaux ont des éléments égaux à des index égaux, il existe le SequenceEqual answer et le IStructuralEquatable answer .

Mais les deux ont des inconvénients, en termes de performances.

SequenceEqual l'implémentation actuelle ne sera pas raccourcie lorsque les tableaux auront des longueurs différentes. Elle peut donc en énumérer un entièrement, en comparant chacun de ses éléments.

IStructuralEquatable n'est pas générique et peut entraîner la mise en boîte de chaque valeur comparée. De plus, il n’est pas très simple à utiliser et appelle déjà à coder certaines méthodes d’aide qui le cachent.

Il peut être préférable, en termes de performances, d’utiliser quelque chose comme:

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;

Mais bien sûr, ce n’est pas non plus une "méthode magique" de vérification de l’égalité des tableaux.

Donc, actuellement, non, il n'y a pas vraiment d'équivalent de Java Arrays.equals() en .Net.

0
Frédéric

Je l'ai fait dans les studios visuels et cela a fonctionné parfaitement; comparer les tableaux index par index avec ce code court.

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

la sortie sera; Les chiffres correspondants sont 7 Les nombres non correspondants sont 3

0
lucy