В Java Arrays.equals() позволяет легко сравнивать содержимое двух основных массивов (перегрузки доступны для всех основных типов).
Есть ли такая вещь в С#? Есть ли "волшебный" способ сравнения содержимого двух массивов в С#?
В Java Arrays.equals() позволяет легко сравнивать содержимое двух основных массивов (перегрузки доступны для всех основных типов).
Есть ли такая вещь в С#? Есть ли "волшебный" способ сравнения содержимого двух массивов в С#?
Вы можете использовать SequenceEqual. Это работает для любого IEnumerable<T>
, а не только для массивов.
Используйте SequenceEqual в 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
Также для массивов (и кортежей) вы можете использовать новые интерфейсы из .NET 4.0: IStructuralComparable и IStructuralEquatable. Используя их, вы можете не только проверить равенство массивов, но и сравнить их.
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
}
Для .NET 4.0 и выше вы можете сравнивать элементы в массиве или кортежах с помощью Структурных сопоставлений:
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));
SequenceEqual
будет возвращать только true, если два условия или встретились.
Если вы хотите проверить, содержат ли они одни и те же элементы независимо от их порядка, и ваша проблема относится к типу
Имеют ли значения2 все значения, содержащиеся в значениях1?
вы можете использовать метод расширения 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);
вы получите разные результаты.
В моем случае у меня есть локальная копия массива и вы хотите проверить, было ли что-либо удалено из исходного массива, поэтому я использую этот метод.
Для модульных тестов вы можете использовать CollectionAssert.AreEqual
вместо Assert.AreEqual
.
Это, наверное, самый простой способ.
Если вы хотите обработать элементы 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.
}
}
Для некоторых приложений может быть лучше:
string.Join(",", arr1) == string.Join(",", arr2)
поэлементно сравнить? как насчет
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)
Я сделал это в визуальных студиях, и он отлично работал; сравнивая индекс массивов по индексу с коротким кодом.
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
Предполагая, что равенство массивов означает, что оба массива имеют одинаковые элементы с одинаковыми индексами, существует ответ SequenceEqual
ответ IStructuralEquatable
.
Но у обоих есть недостатки, с точки зрения производительности.
Текущая реализация SequenceEqual
не будет использовать ярлыки, когда массивы имеют разную длину, и поэтому может полностью перечислить один из них, сравнивая каждый из его элементов.
IStructuralEquatable
не является универсальным и может вызывать упаковку каждого сравниваемого значения. Более того, он не очень прост в использовании и уже требует кодирования некоторых вспомогательных методов, скрывая его.
С точки зрения производительности может быть лучше использовать что-то вроде:
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;
}
Но, конечно, это не какой-то "магический способ" проверки равенства массивов.
Так что в настоящее время нет, в действительности нет эквивалента Java Arrays.equals()
в .Net.
Это решение 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)
);
Здесь странная реализация.
static bool ArraysEqual<T>(T[] a, T[] b)
{
int k = 0;
return a.All(x => x.Equals(b[k++]));
}