In Java, Arrays.equals() allows to easily compare the content of two basic arrays (overloads are available for all the basic types).
Is there such a thing in C#? Is there any "magic" way of comparing the content of two arrays in C#?
You could use Enumerable.SequenceEqual. This works for any IEnumerable<T>, not just arrays.
Use Enumerable.SequenceEqual in 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
Also for arrays (and tuples) you can use new interfaces from .NET 4.0: IStructuralComparable and IStructuralEquatable. Using them you can not only check equality of arrays but also compare them.
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
}
SequenceEqual will only return true if two conditions or met.
They contain the same elements.
The elements are in the same order.
If you only want to check if they contain the same elements regardless of their order and your problem is of the type
Does values2 contain all the values contained in values1?
you can use LINQ extension method Enumerable.Except and then check if the result has any value. Here's an example
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
}
And also by using this you get the different items as well automatically. Two birds with one stone.
Keep in mind, if you execute your code like this
var result = values2.Except(values1);
you will get different results.
In my case I have a local copy of an array and want to check if anything has been removed from the original array so I use this method.
For .NET 4.0 and higher you can compare elements in array or tuples via using 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));
If you would like to handle null inputs gracefully, and ignore the order of items, try the following solution:
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;
if (array1.Count() != array2.Count())
return false;
return !array1.Except(array2).Any() && !array2.Except(array1).Any();
}
}
The test code looks like:
public static void Main()
{
int[] a1 = new int[] { 1, 2, 3 };
int[] a2 = new int[] { 3, 2, 1 };
int[] a3 = new int[] { 1, 3 };
Console.WriteLine(a1.ItemsEqual(a2)); // Output: True.
Console.WriteLine(a2.ItemsEqual(a3)); // Output: False.
Console.WriteLine(a3.ItemsEqual(a2)); // Output: False.
int[] a4 = new int[] { 1, 1 };
int[] a5 = new int[] { 1, 2 };
Console.WriteLine(a4.ItemsEqual(a5)); // Output: False
Console.WriteLine(a5.ItemsEqual(a4)); // Output: False
int[] a6 = null;
int[] a7 = null;
int[] a8 = new int[0];
Console.WriteLine(a6.ItemsEqual(a7)); // Output: True. No Exception.
Console.WriteLine(a8.ItemsEqual(a6)); // Output: False. No Exception.
Console.WriteLine(a7.ItemsEqual(a8)); // Output: False. No Exception.
}
For unit tests, you can use CollectionAssert.AreEqual instead of Assert.AreEqual.
It is probably the easiest way.
For some applications may be better:
string.Join(",", arr1) == string.Join(",", arr2)
Assuming array equality means both arrays have equal elements at equal indexes, there is the SequenceEqual answer and the IStructuralEquatable answer.
But both have drawbacks, performance wise.
SequenceEqual implementation in .Net Framework will not shortcut when the arrays have different lengths, and so it may enumerate one of them entirely, comparing each of its elements.
This said, depending on the .Net flavor (like .Net5), it may shortcut, see this comment. So for an up-to-date .Net project, SequenceEqual should be a good choice.
IStructuralEquatable is not generic and may cause boxing of each compared value. Moreover it is not very straightforward to use and already calls for coding some helper methods hiding it away.
It may be better, performance wise, to use something like:
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].Equals(second[i]))
return false;
}
return true;
}
But of course, that is not either some "magic way" of checking array equality.
So currently, no, there is not really an equivalent to Java Arrays.equals() in .Net.
This LINQ solution works, not sure how it compares in performance to SequenceEquals. But it handles different array lengths and the .All will exit on the first item that is not equal without iterating through the whole 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)
);
elementwise compare ? what about
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)");
}
Replace the (a==b) condition by anything you'd like to compare in a and b.
(this combines two examples from MSDN developer Linq samples)
I did this in visual studios and it worked perfectly; comparing arrays index by index with short this code.
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);
}
the output will be; The matching numbers are 7
The non matching numbers are 3
You can use Enumerable.Intersect:
int[] array1 = new int[] { 1, 2, 3, 4,5 },
array2 = new int[] {7,8};
if (array1.Intersect(array2).Any())
Console.WriteLine("matched");
else
Console.WriteLine("not matched");
I was looking to determine if two sets had equivalent contents, in any order. That meant that, for each element in set A there were equal numbers of elements with that value in both sets. I wanted to account for duplicates (so {1,2,2,3} and {1,2,3,3} should not be considered "the same").
This is what I came up with (note that IsNullOrEmpty is another static extension method that returns true if the enumerable is null or has 0 elements):
public static bool HasSameContentsAs<T>(this IEnumerable<T> source, IEnumerable<T> target)
where T : IComparable
{
//If our source is null or empty, then it's just a matter of whether or not the target is too
if (source.IsNullOrEmpty())
return target.IsNullOrEmpty();
//Otherwise, if the target is null/emtpy, they can't be equal
if (target.IsNullOrEmpty())
return false;
//Neither is null or empty, so we'll compare contents. To account for multiples of
//a given value (ex. 1,2,2,3 and 1,1,2,3 are not equal) we'll group the first set
foreach (var group in source.GroupBy(s => s))
{
//If there are a different number of elements in the target set, they don't match
if (target.Count(t => t.Equals(group.Key)) != group.Count())
return false;
}
//If we got this far, they have the same contents
return true;
}
If you don't want to compare the order but you do want to compare the count of each item, including handling null values, then I've written an extension method for this.
It gives for example the following results:
new int?[]{ }.IgnoreOrderComparison(new int?{ }); // true
new int?[]{ 1 }.IgnoreOrderComparison(new int?{ }); // false
new int?[]{ }.IgnoreOrderComparison(new int?{ 1 }); // false
new int?[]{ 1 }.IgnoreOrderComparison(new int?{ 1 }); // true
new int?[]{ 1, 2 }.IgnoreOrderComparison(new int?{ 2, 1 }); // true
new int?[]{ 1, 2, null }.IgnoreOrderComparison(new int?{ 2, 1 }); // false
new int?[]{ 1, 2, null }.IgnoreOrderComparison(new int?{ null, 2, 1 }); // true
new int?[]{ 1, 2, null, null }.IgnoreOrderComparison(new int?{ null, 2, 1 }); // false
new int?[]{ 2 }.IgnoreOrderComparison(new int?{ 2, 2 }); // false
new int?[]{ 2, 2 }.IgnoreOrderComparison(new int?{ 2, 2 }); // true
Here is the code:
public static class ArrayComparisonExtensions
{
public static bool IgnoreOrderComparison<TSource>(this IEnumerable<TSource> first, IEnumerable<TSource> second) =>
IgnoreOrderComparison(first, second, EqualityComparer<TSource>.Default);
public static bool IgnoreOrderComparison<TSource>(this IEnumerable<TSource> first, IEnumerable<TSource> second, IEqualityComparer<TSource> comparer)
{
var a = ToDictionary(first, out var firstNullCount);
var b = ToDictionary(second, out var secondNullCount);
if (a.Count != b.Count)
return false;
if (firstNullCount != secondNullCount)
return false;
foreach (var item in a)
{
if (b.TryGetValue(item.Key, out var count) && item.Value == count)
continue;
return false;
}
return true;
Dictionary<TSource, int> ToDictionary(IEnumerable<TSource> items, out int nullCount)
{
nullCount = 0;
var result = new Dictionary<TSource, int>(comparer);
foreach (var item in items)
{
if (item is null)
nullCount++;
else if (result.TryGetValue(item, out var count))
result[item] = count + 1;
else
result[item] = 1;
}
return result;
}
}
}
It only enumerates each enumerable once, but it does create a dictionary for each enumerable and iterates those once too. I'd be interested in ways to improve this.
You can also use array1.ToList().All(x => array2.Contains(x)) if you need to compare arrays which have not the same order
Check the answer to this thread which converts one of the array to a HashSet and uses SetEquals for comparison with the other array.
Note however that this does not check for order or duplicates.
List Patterns is added in C#11 .Net 7 RC2.
int[] numbers = { 1, 2, 3 };
Console.WriteLine(numbers is [1, 2, 3]); // True
Console.WriteLine(numbers is [1, 2, 4]); // False
int[] a = { 2, 1, 3, 4, 5, 2 };
int[] b = { 2, 1, 3, 4, 5, 2 };
bool ans = true;
if(a.Length != b.Length)
{
ans = false;
}
else
{
for (int i = 0; i < a.Length; i++)
{
if( a[i] != b[i])
{
ans = false;
}
}
}
string str = "";
if(ans == true)
{
str = "Two Arrays are Equal";
}
if (ans == false)
{
str = "Two Arrays are not Equal";
}
//--------------Or You can write One line of Code-------------
var ArrayEquals = a.SequenceEqual(b); // returns true
Related
Currently, I compare it this way (from here):
bool foo<T>(T expected, T actual) {
return EqualityComparer<T>.Default.Equals(expected, actual);
}
It works for basic types but not for IEnumerable<T>. How can I make it work for IEnumerable<T> like SequenceEqual?
EDIT: I tried the version of David L but it doesn't work either with arrays or with lists.
While there is nothing that prevents you from calling SequenceEquals directly, you can certainly wrap that call in helper methods. Note that SequenceEquals will compare index by index. You can also pass it an IEqualityComparer<T> instance if you want to override how the comparison is handled.
bool foo<T>(IEnumerable<T> expected, IEnumerable<T> actual)
{
return expected.SequenceEqual(actual);
}
bool foo<T>(List<T> expected, List<T> actual)
{
return expected.SequenceEqual(actual);
}
bool foo<T>(T[] expected, T[] actual)
{
return expected.SequenceEqual(actual);
}
bool foo<T>(IEnumerable<T> expected, IEnumerable<T> actual,
IEqualityComparer<T> comparer)
{
return expected.SequenceEqual(actual, comparer);
}
Testing with the following returns true as expected:
IEnumerable<int> expected = new List<int> { 1, 2, 3 };
IEnumerable<int> actual = new List<int> { 1, 2, 3 };
List<int> expected2 = new List<int> { 1, 2, 3 };
List<int> actual2 = new List<int> { 1, 2, 3 };
int[] expected3 = new int[] { 1, 2, 3 };
int[] actual3 = new int[] { 1, 2, 3 };
Console.WriteLine(foo(expected, actual));
Console.WriteLine(foo(expected2, actual2));
Console.WriteLine(foo(expected3, actual3));
and returns false for the following:
IEnumerable<int> expected = new List<int> { 1, 2, 3 };
IEnumerable<int> actual = new List<int> { 1, 3, 2 };
The benefit of the above approach is that you get compile-time overloads for each collection type that you want to explicitly support. However, if you want to implicitly support all collection types, you can expand your current boo foo<T> method as follows:
bool foo<T>(T expected, T actual)
{
// check that both T parameters implement IEnumerable
// (meaning they are a collection)
if (expected is IEnumerable expectedEnumerable &&
actual is IEnumerable actualEnumerable)
{
var expectedEnumerator = expectedEnumerable.GetEnumerator();
var actualEnumerator = actualEnumerable.GetEnumerator();
while (true)
{
// Determine if the enumerators have a next element
var hasExpected = expectedEnumerator.MoveNext();
var hasActual = actualEnumerator.MoveNext();
// Either we have no elements or successfully iterated both
if (!hasExpected && !hasActual)
{
return true;
}
// One of the enumerators has a value while the other does not.
if ((hasExpected && !hasActual) || (!hasExpected && hasActual))
{
return false;
}
// check the equality of the two current elements
if (!expectedEnumerator.Current.Equals(actualEnumerator.Current))
{
return false;
}
}
}
// fall back to your original equality comparison because
// one or both parameters do not implement IEnumerable
return EqualityComparer<T>.Default.Equals(expected, actual);
}
This again returns true for the three collection cases I listed above, and false for the following test cases:
IEnumerable<int> expected4 = new List<int> { 1, 2, 3 };
IEnumerable<int> actual4 = new List<int> { 1, 3, 2 };
List<int> expected5 = new List<int> { 1, 2, 3, 4 };
List<int> actual5 = new List<int> { 1, 2, 3 };
int[] expected6 = new int[] { 2, 3 };
int[] actual6 = new int[] { 1, 2, 3 };
Console.WriteLine(foo(expected4, actual4));
Console.WriteLine(foo(expected5, actual5));
Console.WriteLine(foo(expected6, actual6));
I have some problems. I have 2 list such as:
List<int> firstList = new List<int> { 1, 2, 2, 3, 5};
List<int> secondList = new List<int> { 2, 3, 1 };
⇒ True result is: {1, 3, 0}
I would like to get the first index of numbers in secondList that exists in firstList. I used list.BinarySearch() but the result was {2, 3, 0}.
List<int> firstList = new List<int> { 1, 2, 2, 3, 5};
List<int> secondList = new List<int> { 2, 3, 1 };
var output = secondList.Select(item => firstList.IndexOf(item)); // [1 , 3 , 0]
You can replace the IndexOf with a BinarySearch logic, but BinarySearch returns the first matched element index, so you won't get the lowest number, IndexOf does return the lowest matching index.
The problem is that when the list contains duplicate values as in your case, the BinarySearch method will return the index of any of the matching values (non deterministic).
To get the desired result, you could create and use a custom extension method like this:
public static class ListExtensions
{
public static int BinarySearchFirst<T>(this List<T> source, T item, IComparer<T> comparer = null)
{
if (comparer == null) comparer = Comparer<T>.Default;
int index = source.BinarySearch(item, comparer);
while (index > 0 && comparer.Compare(source[index], source[index - 1]) == 0)
index--;
return index;
}
}
Sample usage:
var result = secondList.Select(x => firstList.BinarySearchFirst(x)).ToList();
// { 1, 3, 0 }
C++ has a standard library function for this called lower_bound().
Here's a C# implementation. This is useful if you are searching large collections:
public static int LowerBound<T>(IList<T> values, T target, int first, int last)
where T : IComparable<T>
{
int left = first;
int right = last;
while (left < right)
{
int mid = left + (right - left) / 2;
var middle = values[mid];
if (middle.CompareTo(target) < 0)
left = mid + 1;
else
right = mid;
}
return left;
}
That doesn't return -1 for elements that it doesn't find, so to fix that we can wrap it like so:
public static int LowerBoundOrMinusOne<T>(IList<T> values, T target, int first, int last)
where T : IComparable<T>
{
int result = LowerBound(values, target, first, last);
if (result >= last || result < first || values[result].CompareTo(target) != 0)
return -1;
return result;
}
Here is how you use it:
List<int> firstList = new List<int> { 1, 2, 2, 3, 5 };
List<int> secondList = new List<int> { 2, 3, 1 };
List<int> result = secondList
.Select(value => LowerBoundOrMinusOne(firstList, value, 0, firstList.Count))
.ToList();
Console.WriteLine(string.Join(", ", result));
Of course, this is mainly of benefit to large lists because it has an O(Log2(N)) rather than an O(N) complexity.
Iterate through second array and get index of element in first array:
foreach (int item in secondList)
{
Console.WriteLine(firstList.IndexOf(item));
}
If you have a large firstList and so you have to use BinarySearch try amending it: find out the item (which is not guaranteed to be the leftmost one) by BinarySearch, then move to the left while having read the same item:
List<int> firstList = new List<int> { 1, 2, 2, 3, 5 };
List<int> secondList = new List<int> { 2, 3, 1, 123 };
var result = secondList
.Select(item => firstList.BinarySearch(item))
.Select(index => index < 0 ? -1 : Enumerable
.Range(0, index + 1) // we have to scan [0..index] at the worst case
.Select(i => index - i) // scan in reverse
.TakeWhile(i => firstList[index] == firstList[i]) // take while items are the same
.Last()); // finally, we want the last item
Test
// 1, 3, 0, -1
Console.Write(String.Join(", ", result));
I'm looking for a way to prevent repeating items in a list but still preserve the order.
For example
1, 2, 3, 4, 4, 4, 1, 1, 2, 3, 4, 4
should become
1, 2, 3, 4, 1, 2, 3, 4
I've done it quite inelegantly using a for loop, checking the next item as follows
public static List<T> RemoveSequencialRepeats<T>(List<T> input)
{
var result = new List<T>();
for (int index = 0; index < input.Count; index++)
{
if (index == input.Count - 1)
{
result.Add(input[index]);
}
else if (!input[index].Equals(input[index + 1]))
{
result.Add(input[index]);
}
}
return result;
}
Is there a more elegant way to do this, preferably with LINQ?
You can create extension method:
public static IEnumerable<T> RemoveSequentialRepeats<T>(
this IEnumerable<T> source)
{
using (var iterator = source.GetEnumerator())
{
var comparer = EqualityComparer<T>.Default;
if (!iterator.MoveNext())
yield break;
var current = iterator.Current;
yield return current;
while (iterator.MoveNext())
{
if (comparer.Equals(iterator.Current, current))
continue;
current = iterator.Current;
yield return current;
}
}
}
Usage:
var result = items.RemoveSequentialRepeats().ToList();
You can also use pure LINQ:
List<int> list = new List<int>{1, 2, 3, 4, 4, 4, 1, 1, 2, 3, 4, 4};
var result = list.Where((x, i) => i == 0 || x != list[i - 1]);
If you really really hate the world, pure LINQ:
var nmbs = new int[] { 1, 2, 3, 4, 4, 4, 1, 1, 2, 3, 4, 4, 5 };
var res = nmbs
.Take(1)
.Concat(
nmbs.Skip(1)
.Zip(nmbs, (p, q) => new { prev = q, curr = p })
.Where(p => p.prev != p.curr)
.Select(p => p.curr));
But note that you'll need to enumerate (at least partially) the enumerable 3 times (the Take, the "left" part of Zip, the first parameters of Zip). This method is slower than building a yield method or doing it directly.
Explanation:
You take the first number (.Take(1))
You take all the numbers from the second (.Skip(1)) and pair it with all the numbers (.Zip(nmbs). We will call curr the numbers from the first "collection" and prev the numbers from the second "collection" ((p, q) => new { prev = q, curr = p })). You then take only the numbers that are different from the previous number (.Where(p => p.prev != p.curr)) and from these you take the curr value and discard the prev value (.Select(p => p.curr))
You concat these two collections (.Concat()
you could write simple LINQ :
var l = new int[] { 1, 2, 3, 4, 4, 4, 1, 1, 2, 3, 4, 4 };
var k = new Nullable<int>();
var nl = l.Where(x => { var res = x != k; k = x; return res; }).ToArray();
int[8] { 1, 2, 3, 4, 1, 2, 3, 4 }
or pythonic (well, my best try) way:
l.Zip(l.Skip(1), (x, y) => new[] { x, y })
.Where(z => z[0] != z[1]).Select(a => a[0])
.Concat(new[] { l[l.Length - 1] }).ToArray()
int[8] { 1, 2, 3, 4, 1, 2, 3, 4 }
the simplest one (edit: haven't seen that it already suggested by King King)
l.Where((x, i) => i == l.Length - 1 || x != l[i + 1]).ToArray()
int[8] { 1, 2, 3, 4, 1, 2, 3, 4 }
If you want LINQ statement that do not rely on captured value of result inside the call you'll need some construct with aggregate as it is the only method that carries value along with operation. I.e. based on Zaheer Ahmed's code:
array.Aggregate(new List<string>(),
(items, element) =>
{
if (items.Count == 0 || items.Last() != element)
{
items.Add(element);
}
return items;
});
Or you can even try to build list without if:
array.Aggregate(Enumerable.Empty<string>(),
(items, element) => items.Concat(
Enumerable.Repeat(element,
items.Count() == 0 || items.Last() != element ? 1:0 ))
);
Note to get reasonable performance of above samples with Aggregate you'd need to also carry last value (Last will have to iterate whole sequence on each step), but code that carries 3 values {IsEmpty, LastValue, Sequence} in a Tuple is very strange looking. These samples are here for entertaining purposes only.
One more option is to Zip array with itself shifted by 1 and return elements that are not equal...
More practical option is to build iterator that filters values:
IEnumerable<string> NonRepeated(IEnumerable<string> values)
{
string last = null;
bool lastSet = false;
foreach(var element in values)
{
if (!lastSet || last != element)
{
yield return element;
}
last = element;
lastSet = true;
}
}
check if last of new list and current item is not same then add to new list:
List<string> results = new List<string>();
results.Add(array.First());
foreach (var element in array)
{
if(results[results.Length - 1] != element)
results.Add(element);
}
or using LINQ:
List<int> arr=new List<int>(){1, 2, 3, 4, 4, 4, 1, 1, 2, 3, 4, 4 };
List<int> result = new List<int>() { arr.First() };
arr.Select(x =>
{
if (result[result.Length - 1] != x) result.Add(x);
return x;
}).ToList();
Do have proper validation for null object.
Try this:
class Program
{
static void Main(string[] args)
{
var input = "1, 2, 3, 4, 4, 4, 1, 1, 2, 3, 4, 4 ";
var list = input.Split(',').Select(i => i.Trim());
var result = list
.Select((s, i) =>
(s != list.Skip(i + 1).FirstOrDefault()) ? s : null)
.Where(s => s != null)
.ToList();
}
}
Here the code you need :
public static List<int> RemoveSequencialRepeats(List<int> input)
{
var result = new List<int>();
result.Add(input.First());
result.AddRange(input.Where(p_element => result.Last() != p_element);
return result;
}
The LINQ magic is:
result.Add(input.First());
result.AddRange(input.Where(p_element => result.Last() != p_element);
Or you can create extension method like this:
public static class Program
{
static void Main(string[] args)
{
List<int> numList=new List<int>(){1,2,2,2,4,5,3,2};
numList = numList.RemoveSequentialRepeats();
}
public static List<T> RemoveSequentialRepeats<T>(this List<T> p_input)
{
var result = new List<T> { p_input.First() };
result.AddRange(p_input.Where(p_element => !result.Last().Equals(p_element)));
return result;
}
}
If you feel like referencing an F# project you can write
let rec dedupe = function
| x::y::rest when x = y -> x::dedupe rest
| x::rest -> x::dedupe rest
| _ -> []
In Java, Arrays.equals() allows to easily compare the content of two basic arrays (overloads are available for all the basic types).
Is there such a thing in C#? Is there any "magic" way of comparing the content of two arrays in C#?
You could use Enumerable.SequenceEqual. This works for any IEnumerable<T>, not just arrays.
Use Enumerable.SequenceEqual in 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
Also for arrays (and tuples) you can use new interfaces from .NET 4.0: IStructuralComparable and IStructuralEquatable. Using them you can not only check equality of arrays but also compare them.
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
}
SequenceEqual will only return true if two conditions or met.
They contain the same elements.
The elements are in the same order.
If you only want to check if they contain the same elements regardless of their order and your problem is of the type
Does values2 contain all the values contained in values1?
you can use LINQ extension method Enumerable.Except and then check if the result has any value. Here's an example
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
}
And also by using this you get the different items as well automatically. Two birds with one stone.
Keep in mind, if you execute your code like this
var result = values2.Except(values1);
you will get different results.
In my case I have a local copy of an array and want to check if anything has been removed from the original array so I use this method.
For .NET 4.0 and higher you can compare elements in array or tuples via using 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));
If you would like to handle null inputs gracefully, and ignore the order of items, try the following solution:
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;
if (array1.Count() != array2.Count())
return false;
return !array1.Except(array2).Any() && !array2.Except(array1).Any();
}
}
The test code looks like:
public static void Main()
{
int[] a1 = new int[] { 1, 2, 3 };
int[] a2 = new int[] { 3, 2, 1 };
int[] a3 = new int[] { 1, 3 };
Console.WriteLine(a1.ItemsEqual(a2)); // Output: True.
Console.WriteLine(a2.ItemsEqual(a3)); // Output: False.
Console.WriteLine(a3.ItemsEqual(a2)); // Output: False.
int[] a4 = new int[] { 1, 1 };
int[] a5 = new int[] { 1, 2 };
Console.WriteLine(a4.ItemsEqual(a5)); // Output: False
Console.WriteLine(a5.ItemsEqual(a4)); // Output: False
int[] a6 = null;
int[] a7 = null;
int[] a8 = new int[0];
Console.WriteLine(a6.ItemsEqual(a7)); // Output: True. No Exception.
Console.WriteLine(a8.ItemsEqual(a6)); // Output: False. No Exception.
Console.WriteLine(a7.ItemsEqual(a8)); // Output: False. No Exception.
}
For unit tests, you can use CollectionAssert.AreEqual instead of Assert.AreEqual.
It is probably the easiest way.
For some applications may be better:
string.Join(",", arr1) == string.Join(",", arr2)
Assuming array equality means both arrays have equal elements at equal indexes, there is the SequenceEqual answer and the IStructuralEquatable answer.
But both have drawbacks, performance wise.
SequenceEqual implementation in .Net Framework will not shortcut when the arrays have different lengths, and so it may enumerate one of them entirely, comparing each of its elements.
This said, depending on the .Net flavor (like .Net5), it may shortcut, see this comment. So for an up-to-date .Net project, SequenceEqual should be a good choice.
IStructuralEquatable is not generic and may cause boxing of each compared value. Moreover it is not very straightforward to use and already calls for coding some helper methods hiding it away.
It may be better, performance wise, to use something like:
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].Equals(second[i]))
return false;
}
return true;
}
But of course, that is not either some "magic way" of checking array equality.
So currently, no, there is not really an equivalent to Java Arrays.equals() in .Net.
This LINQ solution works, not sure how it compares in performance to SequenceEquals. But it handles different array lengths and the .All will exit on the first item that is not equal without iterating through the whole 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)
);
elementwise compare ? what about
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)");
}
Replace the (a==b) condition by anything you'd like to compare in a and b.
(this combines two examples from MSDN developer Linq samples)
I did this in visual studios and it worked perfectly; comparing arrays index by index with short this code.
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);
}
the output will be; The matching numbers are 7
The non matching numbers are 3
You can use Enumerable.Intersect:
int[] array1 = new int[] { 1, 2, 3, 4,5 },
array2 = new int[] {7,8};
if (array1.Intersect(array2).Any())
Console.WriteLine("matched");
else
Console.WriteLine("not matched");
I was looking to determine if two sets had equivalent contents, in any order. That meant that, for each element in set A there were equal numbers of elements with that value in both sets. I wanted to account for duplicates (so {1,2,2,3} and {1,2,3,3} should not be considered "the same").
This is what I came up with (note that IsNullOrEmpty is another static extension method that returns true if the enumerable is null or has 0 elements):
public static bool HasSameContentsAs<T>(this IEnumerable<T> source, IEnumerable<T> target)
where T : IComparable
{
//If our source is null or empty, then it's just a matter of whether or not the target is too
if (source.IsNullOrEmpty())
return target.IsNullOrEmpty();
//Otherwise, if the target is null/emtpy, they can't be equal
if (target.IsNullOrEmpty())
return false;
//Neither is null or empty, so we'll compare contents. To account for multiples of
//a given value (ex. 1,2,2,3 and 1,1,2,3 are not equal) we'll group the first set
foreach (var group in source.GroupBy(s => s))
{
//If there are a different number of elements in the target set, they don't match
if (target.Count(t => t.Equals(group.Key)) != group.Count())
return false;
}
//If we got this far, they have the same contents
return true;
}
If you don't want to compare the order but you do want to compare the count of each item, including handling null values, then I've written an extension method for this.
It gives for example the following results:
new int?[]{ }.IgnoreOrderComparison(new int?{ }); // true
new int?[]{ 1 }.IgnoreOrderComparison(new int?{ }); // false
new int?[]{ }.IgnoreOrderComparison(new int?{ 1 }); // false
new int?[]{ 1 }.IgnoreOrderComparison(new int?{ 1 }); // true
new int?[]{ 1, 2 }.IgnoreOrderComparison(new int?{ 2, 1 }); // true
new int?[]{ 1, 2, null }.IgnoreOrderComparison(new int?{ 2, 1 }); // false
new int?[]{ 1, 2, null }.IgnoreOrderComparison(new int?{ null, 2, 1 }); // true
new int?[]{ 1, 2, null, null }.IgnoreOrderComparison(new int?{ null, 2, 1 }); // false
new int?[]{ 2 }.IgnoreOrderComparison(new int?{ 2, 2 }); // false
new int?[]{ 2, 2 }.IgnoreOrderComparison(new int?{ 2, 2 }); // true
Here is the code:
public static class ArrayComparisonExtensions
{
public static bool IgnoreOrderComparison<TSource>(this IEnumerable<TSource> first, IEnumerable<TSource> second) =>
IgnoreOrderComparison(first, second, EqualityComparer<TSource>.Default);
public static bool IgnoreOrderComparison<TSource>(this IEnumerable<TSource> first, IEnumerable<TSource> second, IEqualityComparer<TSource> comparer)
{
var a = ToDictionary(first, out var firstNullCount);
var b = ToDictionary(second, out var secondNullCount);
if (a.Count != b.Count)
return false;
if (firstNullCount != secondNullCount)
return false;
foreach (var item in a)
{
if (b.TryGetValue(item.Key, out var count) && item.Value == count)
continue;
return false;
}
return true;
Dictionary<TSource, int> ToDictionary(IEnumerable<TSource> items, out int nullCount)
{
nullCount = 0;
var result = new Dictionary<TSource, int>(comparer);
foreach (var item in items)
{
if (item is null)
nullCount++;
else if (result.TryGetValue(item, out var count))
result[item] = count + 1;
else
result[item] = 1;
}
return result;
}
}
}
It only enumerates each enumerable once, but it does create a dictionary for each enumerable and iterates those once too. I'd be interested in ways to improve this.
You can also use array1.ToList().All(x => array2.Contains(x)) if you need to compare arrays which have not the same order
Check the answer to this thread which converts one of the array to a HashSet and uses SetEquals for comparison with the other array.
Note however that this does not check for order or duplicates.
List Patterns is added in C#11 .Net 7 RC2.
int[] numbers = { 1, 2, 3 };
Console.WriteLine(numbers is [1, 2, 3]); // True
Console.WriteLine(numbers is [1, 2, 4]); // False
int[] a = { 2, 1, 3, 4, 5, 2 };
int[] b = { 2, 1, 3, 4, 5, 2 };
bool ans = true;
if(a.Length != b.Length)
{
ans = false;
}
else
{
for (int i = 0; i < a.Length; i++)
{
if( a[i] != b[i])
{
ans = false;
}
}
}
string str = "";
if(ans == true)
{
str = "Two Arrays are Equal";
}
if (ans == false)
{
str = "Two Arrays are not Equal";
}
//--------------Or You can write One line of Code-------------
var ArrayEquals = a.SequenceEqual(b); // returns true
I do not understand how following code works. Specifically, I do not understand using of "return i<3". I would expect return i IF its < than 3. I always though that return just returns value. I could not even find what syntax is it.
Second question, it seems to me like using anonymous method (delegate(int i)) but could be possible to write it with normal delegate pointing to method elsewere? Thanks
List<int> listOfInts = new List<int> { 1, 2, 3, 4, 5 };
List<int> result =
listOfInts.FindAll(delegate(int i) { return i < 3; });
No, return i < 3 isn't the same as if (i < 3) return;.
Instead, it's equivalent to:
bool result = (i < 3);
return result;
In other words, it returns the evaluated result of i < 3. So it will return true if i is 2, but false if i is 10 for example.
You could definitely write this using a method group conversion:
List<int> listOfInts = new List<int> { 1, 2, 3, 4, 5 };
List<int> result = listOfInts.FindAll(TestLessThanThree);
...
static bool TestLessThanThree(int i)
{
return i < 3;
}
The return statement will can only return a value as you say. In this example the statement i<3 will first be evaluated to either true or false and boolean value will be returned, it will not return i<3, but the result of the equation.
You can also write your example using a lambda expression:
var listOfInts = new List<int> { 1, 2, 3, 4, 5 };
var result = listOfInts.FindAll(i => i < 3);
Other interesting examples:
var listOfInts = new List<int> { 1, 2, 3, 4, 5 };
var all = listOfInts.FindAll(i => true);
var none = listOfInts.FindAll(i => false);