Checking values inside a 2D array - c#

I have a 2 dimensional array int[][] data and i want to see if the value contains the value 45 for example
I created this line of code
bool contains = data.Where(x => x.Contains(45)).ToArray().Count() != 0 ? true : false;
but it looks like there is unnecessary code and I am sure that there is an easier or more efficient way to do this

You could use Any linq extension.
bool exists = data.SelectMany(x=>x).Any(x=>x == 45);
Or
bool exists = data.Any(x=>x.Any(s=>s == 45));

Array.IndexOf is optimised for integer arrays, so if your inner arrays are long and you care about speeding it up that much it might be worth doing it like this:
bool exists = data.Any(a => Array.IndexOf(a, 45) != -1);

There are two issues in your code:
data is not an array of int, it is an array int[]
the ternary operator takes a bool condition and returns a value based on the bool value. So x ? true : false is the same as x. There is no need for the operator.
So what (I assume) you want is not to check if data contains 45, but if any of the arrays in data contains 45. So you either flatten the jagged array into on enumeration using SelectMany or concat two Any calls:
bool contains = data.SelectMany(d => d).Contains(45);
or
bool contains = data.Any(d => d.Contains(45);

Related

Using lambda expressions in array.convertall()

I'm still getting acquainted with delegates and lambdas, I'm not using LINQ, and I also only discovered the ConvertAll function today, so I'm experimenting and asking this to bolster my understanding.
The task I had was to establish whether a string of numbers were even or odd. So first, convert the string list to an int list, and from there into a bool list. As bloated as the code would be, I wondered if I could get it all on one line and reduce the need for an extra for loop.
string numbers = "2 4 7 8 10";
List<bool> evenBools = new List<bool>(Array.ConvertAll(numbers.Split(' '), (x = Convert.Int32) => x % 2 == 0))
The expected result is [true, true, false, true, true]. Obviously the code doesn't work.
I understand that the second argument of Array.ConvertAll) requires the conversation to take place. From string to int, that's simply Convert.ToInt32. Is it possible to do that on the fly though (i.e. on the left side of the lambda expression), so that I can get on with the bool conversion and return on the right?
Second parameter of ConvertAll method is Converter<TInput,TOutput> delegate. You can use anonymous method here, pass string input to it (left side of =>), parse to int inside and return bool value, indicating whether it's even or odd
var boolArray = Array.ConvertAll(numbers.Split(' '), input => Convert.ToInt32(input) % 2 == 0);
List<bool> evenBools = new List<bool>(boolArray);
Finally create a List<bool> from array.
Left side of lambda expressions contains input parameters only (input string in your case). Right side is used for expressions and statements, here you have a logic for parsing and return a bool value.
With help of System.Linq it can be written on the similar way
var boolArray = numbers.Split(' ').Select(input => Convert.ToInt32(input) % 2 == 0).ToArray();
You also might use int.Parse instead of Convert.ToInt32
var boolList = numbers.Split(' ').Select(Int32.Parse).ToList().ConvertAll(i => i % 2 == 0);

Hot to logic compare a bool array with itself for a single bool result?

I have an array that looks like this:
bool[] array = new bool[4] { true, false, true, true } ;
And I'd like to do an AND/OR comparison between all the elements of this array, something like:
AND example: true AND false AND true AND true
So I can get the final result which would be false in the example above, or:
OR example: true OR false OR true OR true
Which would give me true in the example above.
It there any built-in method in an array that allows me to do it? Or should I have to iterate between all elements and compare them one by one?
As per comments and other answers, you can use LINQ for both of these. (Although you don't have to; farbiondriven's answer will work absolutely fine, although it's less general purpose in that LINQ solutions can handle any IEnumerable<bool>.)
Any with an identity projection will detect if any element is true, which is the same result as performing a logical OR on all elements.
All with an identity projection will detect if all elements are true, which is the same result as performing a logical AND on all elements:
bool orResult = array.Any(x => x);
bool andResult = array.All(x => x);
Both of these will short-circuit: if the first element is true, then Any won't bother looking at later elements, as the result will definitely be true. Likewise if the first element is false, then All won't bother looking at later elements, as the result will definitely be false.
However, you may need to think about what you want the result to be for empty arrays. Any() will return false on an empty sequence, whereas All will return true on an empty sequence. That may or may not be what you expect or need.
This can be done with linq:
var all = array.All(x => x);
var or = array.Any(x => x);
Approach with Linq Aggregate and binary & and | operations
bool[] array = new bool[4] { true, false, true, true } ;
bool resultAnd = array.Aggregate((a, b) => a & b); // AND
bool resultOr = array.Aggregate((a, b) => a | b); //OR
bool resultXor = array.Aggregate((a, b) => a ^ b); //XOR
If a no LinQ solution may be required :
public static bool Or(IList<bool> bList)
{
return bList.Contains(true);
}
public static bool And(IList<bool> bList)
{
return !bList.Contains(false);
}
It there any built-in method in an array that allows me to do it?
Answer: Yes. There are static methods in the System.Array Class that can be used.
For example, Array.IndexOf Method (T[], T):
bool andResult = !(Array.IndexOf<bool>(array, false) > -1);
bool orResult = Array.IndexOf<bool>(array, true) > -1;
However, you need to define how you want to handle the edge case of an empty array.
There are other methods in the Array Class that could also be used to construct the logic. I will leave that exercise for you.

Replacing CompareTo with LINQ for array elements

I am working on a project which uses posts to represent a fence. Each fence has exactly two posts that implement IComparable and are ordered in each fence. In order to override my CompareTo on Fence, I need to compare post 0 between this and the other fence; if that result returns 0, then I need to compare post 1 between this and the other fence. I wrote a simple for loop to perform this logic, which I've included below. However, Resharper is giving me a warning that I should replace the for loop with LINQ. Is there an easy way to replace the for loop with LINQ?
public int CompareTo(Fence other)
{
for(int i = 0; i < Posts.Length; i++)
{
int c = Posts[i].CompareTo(other.Posts[i]);
if (c != 0)
return c;
}
return 0;
}
Since a Fence has exactly two Posts, then this can be reduced to :
public int CompareTo(Fence other)
{
int c = Post[0].CompareTo(other.Post[0]);
if (c == 0)
c = Post[1].CompareTo(other.Post[1]);
return c;
}
Note that you can (and probably should) replace the Post array with Post0 and `Post1'.
Note, that this could give you a completely different ordering than:
int c = Post[1].CompareTo(other.Post[1]);
if (c == 0)
c = Post[0].CompareTo(other.Post[0]);
which, presumably, is just as valid. (i.e, if this Post[0] is less than the other's, but it's Post[1] is greater, is the Fence greater or less than the other?)
If ReSharper suggests it you may easily hit AltEnterEnter and see what happens. I guess something like:
public int CompareTo(Fence other)
{
return Posts.Select((p, i) => p.CompareTo(other.Posts[i]))
.FirstOrDefault(c => c != 0);
}
This projects each Post to it's comparison result to the respective Post of the other Fence (p is the Post loop variable, i is the index). FirstOrDefault looks for the first non-zero comparsion result or returns 0 if all results are 0.
So this does exactly what your loop does (note that LINQ uses deferred execution, so when the first non-zero comparison occures, no further Posts are compared).
Note that this code is error-prone, as juharr commented: you should first null-check other and check if the two Post arrays have the same length.
(I guess that Posts is not null and the arrays don't contain null elements should be ensured by your classes' implementations).

How to check if List < int[ ] > contains an int[] element that store the same values as another int[ ]?

Let's say, that I have a list of integer arrays and an integer array:
List<int[]> MyListOfIntArrays = new List<int[]>
{
new int[1] {0},
new int[2] {0,1},
new int[2] {1,0}
};
int[] MyArray = new int[]{1, 0};
I want to find out how can I check if in MyListOfIntArrays is an element that stores the same values as MyArray.
In this case the answer should be: "Yes" (third element of MyListOfIntArrays stores the same values as MyArray).
My attempt:
if (MyListOfIntArrays.Contains(MyArray) == true)
Console.WriteLine("Yes");
if (MyListOfIntArrays.Contains(MyArray) == false)
Console.WriteLine("No");
always returns no.
I'm new to C# and my guess is that the method "Contains" checks references here, not values. Can someone help me with this problem?
This works:
var contains = MyListOfIntArrays.Any(arr => arr.GetType() == MyArray.GetType() && arr.SequenceEqual(MyArray));
Edit:
As both comments suggested, it can be shortened to
var contains = MyListOfIntArrays.Any(arr => arr.SequenceEqual(MyArray));
You can use FindIndex and SequenceEqual.
FindIndex will return the index of given array(MyListOfIntArrays) when ever predicate returns true. it will return -1 if it wasnt able to find anything.
SequenceEqual will check the equality of arrays element by element instead of checking references which Contains normally do (because it uses default comparer and arrays are checked by ref. another way is to use custom comparer showed by Servy).
if (MyListOfIntArrays.FindIndex(x => x.SequenceEqual(MyArray)) != -1) // if != -1 means we found array!
Console.WriteLine("Yes");
else
Console.WriteLine("No");
You may want to make it simple if you dont need index. Any will Just give a Boolean And as commented by Asad Saeeduddin:
if(MyListOfIntArrays.Any(MyArray.SequenceEqual))
Console.WriteLine("Yes");
else
Console.WriteLine("No");
The equality that arrays have defined for themselves only checks if the arrays reference the same object; it doesn't check if the contents of the arrays are the same. If you want to compare them based on their values, you'll need to create a comparer that can compare the values of the arrays:
public class SequenceComparer<T> : IEqualityComparer<IEnumerable<T>>
{
private IEqualityComparer<T> comparer;
public SequenceComparer(IEqualityComparer<T> comparer = null)
{
comparer = comparer ?? EqualityComparer<T>.Default;
}
public bool Equals(IEnumerable<T> x, IEnumerable<T> y)
{
return x.SequenceEqual(y, comparer);
}
public int GetHashCode(IEnumerable<T> sequence)
{
unchecked
{
int hash = 19;
foreach (var item in sequence)
hash = hash * 79 + comparer.GetHashCode(item);
return hash;
}
}
}
This lets you write:
if (MyListOfIntArrays.Contains(MyArray, new SequenceComparer<int>()))
Console.WriteLine("Yes");
else
Console.WriteLine("No");
.Contains will not work, since arrays are reference types, and you will only get true if you've added the array that MyArray points to specifically to the list, instead of an identical array.
While you can solve your problem using elementwise comparison against all arrays, I feel a better solution to the problem would be to use sets instead of arrays. If you had an ISet<ISet<int>> instead of a List<int[]>, you could very easily and efficiently check if a given ISet<int> was a member.

Comparing One Value To A Whole Array? (C#)

Let's say I have a C# variable and array:
int variable_1 = 1;
int[3] array_1 = {1,2,3};
How can I check if the value of variable_1 is equal to any of the values in array_1 without looping through array_1?
Well something has to loop. Any of the following will work:
bool exists = array.Contains(variable_1);
bool exists = Array.IndexOf(array_1, variable_1) != -1;
bool exists = Array.Exists(array_1, x => x == variable_1);
bool exists = Array.FindIndex(array_1, x => x == variable_1) != -1;
bool exists = array_1.Any(x => x == variable_1);
All of the versions using a lambda expression feel like overkill to me, but they're potentially useful if you find yourself in a situation where you don't know the actual value you're searching for - just some condition.
If you know that the array is sorted, you can use:
bool exists = Array.BinarySearch(array_1, variable_1) >= 0;
That will be O(log n) rather than O(n) (which all the others are), but it does require the array to be sorted first.
Personally I'd normally go with the very first form - assuming you're using .NET 3.5 or higher.
If you need to check for several items and the array is large, you may want to create a HashSet<int>:
HashSet<int> hashSet = new HashSet<int>(array_1);
bool exists = hashSet.Contains(variable_1);
in 3.5 and up
array_1.Contains(variable_1);
or 2.0
array_1.IndexOf(variable_1) != -1
Updated: to save on performance
mmm there can be various options,
var hasItem = Array.Exists(array_1, x => x == variable_1);

Categories