Can I use LINQ to compare ranges in two arrays? - c#

I can roll a method, pseudo:
bool Compare(IList left, int lIndex, IList right, int rIndex, int num)
{
for(int i=0;i<num;++i)
{
if(left[lIndex+i] != right[rIndex+i])
{
return false;
}
}
return true;
}
So given L =[1,2,3,4,5,6,7,8] and R = [5,6,7,8,9] : Compare(L,5,R,1,3) == true
I feel I should be able to do a simple LINQ version but I am not sure how to handle the indexing. Can it be written as a trivial LINQ/lambda... otherwise I'll pull this out as a utility method.
By the way there is a question with a very similar title but it is asking a different thing: https://stackoverflow.com/questions/33812323/compare-two-arrays-using-linq

You can Skip, Take, and SequenceEqual:
return left.Skip(lIndex).Take(num).SequenceEqual(
right.Skip(rIndex).Take(num))
Note that you should make your Compare method generic and use the generic IList<T> instead.

you can try this
int num = 3,lIndex =5,rIndex =1;
var L = (new List<int>(){1,2,3,4,5,6,7,8}).Skip(lIndex).Take(num).ToList();
var R = (new List<int>(){5,6,7,8,9}).Skip(rIndex).Take(num).ToList();
var result = L.Count() == R.Count() && !R.Except(L).Any() && !L.Except(R).Any() && string.Join(",",L).Equals(string.Join(",",R));

Related

Finding Nearest Number in array C# [duplicate]

int[] array = new int[5]{5,7,8,15,20};
int TargetNumber = 13;
For a target number, I want to find the closest number in an array. For example, when the target number is 13, the closest number to it in the array above is 15. How would I accomplish that programmatically in C#?
EDIT: Have adjusted the queries below to convert to using long arithmetic, so that we avoid overflow issues.
I would probably use MoreLINQ's MinBy method:
var nearest = array.MinBy(x => Math.Abs((long) x - targetNumber));
Or you could just use:
var nearest = array.OrderBy(x => Math.Abs((long) x - targetNumber)).First();
... but that will sort the whole collection, which you really don't need. It won't make much difference for a small array, admittedly... but it just doesn't feel quite right, compared with describing what you're actually trying to do: find the element with the minimum value according to some function.
Note that both of these will fail if the array is empty, so you should check for that first.
If you're using .Net 3.5 or above LINQ can help you here:
var closest = array.OrderBy(v => Math.Abs((long)v - targetNumber)).First();
Alternatively, you could write your own extension method:
public static int ClosestTo(this IEnumerable<int> collection, int target)
{
// NB Method will return int.MaxValue for a sequence containing no elements.
// Apply any defensive coding here as necessary.
var closest = int.MaxValue;
var minDifference = int.MaxValue;
foreach (var element in collection)
{
var difference = Math.Abs((long)element - target);
if (minDifference > difference)
{
minDifference = (int)difference;
closest = element;
}
}
return closest;
}
Useable like so:
var closest = array.ClosestTo(targetNumber);
Both Jon and Rich gave great answers with MinBy and ClosestTo. But I would never recommend using OrderBy if your intent is to find a single element. It's far too inefficient for those kinds of tasks. It's simply the wrong tool for the job.
Here's a technique that performs marginally better than MinBy, is already included in the .NET framework, but less elegant than MinBy: Aggregate
var nearest = array.Aggregate((current, next) => Math.Abs((long)current - targetNumber) < Math.Abs((long)next - targetNumber) ? current : next);
As I said, not as elegant as Jon's method, but viable.
Performance on my computer:
For(each) Loops = fastest
Aggregate = 2.5x slower than loops
MinBy = 3.5x slower than loops
OrderBy = 12x slower than loops
I found this really sexy approach years ago in Math.NET Numerics https://numerics.mathdotnet.com/ which works with BinarySearch in the array. It was a good help in preparation for interpolations and works down to .Net 2.0:
public static int LeftSegmentIndex(double[] array, double t)
{
int index = Array.BinarySearch(array, t);
if (index < 0)
{
index = ~index - 1;
}
return Math.Min(Math.Max(index, 0), array.Length - 2);
}
If you need to find the closest value to the average
very open style
public static double Miidi(double[] list)
{
bool isEmpty = !list.Any();
if (isEmpty)
{
return 0;
}
else
{
double avg = list.Average();
double closest = 100;
double shortest = 100;
{
for ( int i = 0; i < list.Length; i++)
{
double lgth = list[i] - avg;
if (lgth < 0)
{
lgth = lgth - (2 * lgth);
}
else
lgth = list[i] - avg;
if (lgth < shortest)
{
shortest = lgth;
closest = list[i];
}
}
}
return closest;
}
}
Performance wise custom code will be more useful.
public static int FindNearest(int targetNumber, IEnumerable<int> collection) {
var results = collection.ToArray();
int nearestValue;
if (results.Any(ab => ab == targetNumber))
nearestValue = results.FirstOrDefault(i => i == targetNumber);
else{
int greaterThanTarget = 0;
int lessThanTarget = 0;
if (results.Any(ab => ab > targetNumber)) {
greaterThanTarget = results.Where(i => i > targetNumber).Min();
}
if (results.Any(ab => ab < targetNumber)) {
lessThanTarget = results.Where(i => i < targetNumber).Max();
}
if (lessThanTarget == 0) {
nearestValue = greaterThanTarget;
}
else if (greaterThanTarget == 0) {
nearestValue = lessThanTarget;
}
else if (targetNumber - lessThanTarget < greaterThanTarget - targetNumber) {
nearestValue = lessThanTarget;
}
else {
nearestValue = greaterThanTarget;
}
}
return nearestValue;
}

finding closest value in an array

int[] array = new int[5]{5,7,8,15,20};
int TargetNumber = 13;
For a target number, I want to find the closest number in an array. For example, when the target number is 13, the closest number to it in the array above is 15. How would I accomplish that programmatically in C#?
EDIT: Have adjusted the queries below to convert to using long arithmetic, so that we avoid overflow issues.
I would probably use MoreLINQ's MinBy method:
var nearest = array.MinBy(x => Math.Abs((long) x - targetNumber));
Or you could just use:
var nearest = array.OrderBy(x => Math.Abs((long) x - targetNumber)).First();
... but that will sort the whole collection, which you really don't need. It won't make much difference for a small array, admittedly... but it just doesn't feel quite right, compared with describing what you're actually trying to do: find the element with the minimum value according to some function.
Note that both of these will fail if the array is empty, so you should check for that first.
If you're using .Net 3.5 or above LINQ can help you here:
var closest = array.OrderBy(v => Math.Abs((long)v - targetNumber)).First();
Alternatively, you could write your own extension method:
public static int ClosestTo(this IEnumerable<int> collection, int target)
{
// NB Method will return int.MaxValue for a sequence containing no elements.
// Apply any defensive coding here as necessary.
var closest = int.MaxValue;
var minDifference = int.MaxValue;
foreach (var element in collection)
{
var difference = Math.Abs((long)element - target);
if (minDifference > difference)
{
minDifference = (int)difference;
closest = element;
}
}
return closest;
}
Useable like so:
var closest = array.ClosestTo(targetNumber);
Both Jon and Rich gave great answers with MinBy and ClosestTo. But I would never recommend using OrderBy if your intent is to find a single element. It's far too inefficient for those kinds of tasks. It's simply the wrong tool for the job.
Here's a technique that performs marginally better than MinBy, is already included in the .NET framework, but less elegant than MinBy: Aggregate
var nearest = array.Aggregate((current, next) => Math.Abs((long)current - targetNumber) < Math.Abs((long)next - targetNumber) ? current : next);
As I said, not as elegant as Jon's method, but viable.
Performance on my computer:
For(each) Loops = fastest
Aggregate = 2.5x slower than loops
MinBy = 3.5x slower than loops
OrderBy = 12x slower than loops
I found this really sexy approach years ago in Math.NET Numerics https://numerics.mathdotnet.com/ which works with BinarySearch in the array. It was a good help in preparation for interpolations and works down to .Net 2.0:
public static int LeftSegmentIndex(double[] array, double t)
{
int index = Array.BinarySearch(array, t);
if (index < 0)
{
index = ~index - 1;
}
return Math.Min(Math.Max(index, 0), array.Length - 2);
}
If you need to find the closest value to the average
very open style
public static double Miidi(double[] list)
{
bool isEmpty = !list.Any();
if (isEmpty)
{
return 0;
}
else
{
double avg = list.Average();
double closest = 100;
double shortest = 100;
{
for ( int i = 0; i < list.Length; i++)
{
double lgth = list[i] - avg;
if (lgth < 0)
{
lgth = lgth - (2 * lgth);
}
else
lgth = list[i] - avg;
if (lgth < shortest)
{
shortest = lgth;
closest = list[i];
}
}
}
return closest;
}
}
Performance wise custom code will be more useful.
public static int FindNearest(int targetNumber, IEnumerable<int> collection) {
var results = collection.ToArray();
int nearestValue;
if (results.Any(ab => ab == targetNumber))
nearestValue = results.FirstOrDefault(i => i == targetNumber);
else{
int greaterThanTarget = 0;
int lessThanTarget = 0;
if (results.Any(ab => ab > targetNumber)) {
greaterThanTarget = results.Where(i => i > targetNumber).Min();
}
if (results.Any(ab => ab < targetNumber)) {
lessThanTarget = results.Where(i => i < targetNumber).Max();
}
if (lessThanTarget == 0) {
nearestValue = greaterThanTarget;
}
else if (greaterThanTarget == 0) {
nearestValue = lessThanTarget;
}
else if (targetNumber - lessThanTarget < greaterThanTarget - targetNumber) {
nearestValue = lessThanTarget;
}
else {
nearestValue = greaterThanTarget;
}
}
return nearestValue;
}

how do i return a count of match items

I have a sorted generic list. I would like to return the first 10 that match a condition.
sort of like the method below but only the first 10 items
mySortedlist.FindAll(delegate(myclass tmp){ return tmp.ID == 123;});
Something like the following:
int count = 0;
mySortedlist.FindAll(delegate(myclass tmp){ return (tmp.ID == 123 && ++count <= 10);});
Well, that will return a list already. You can create your own equivalent of Enumerable.Take pretty easily:
public static IEnumerable<T> Take<T>(IEnumerable<T> source, int size)
{
int count = 0;
foreach (T item in source)
{
yield return item;
count++;
if (count == size)
{
yield break;
}
}
}
Then you can use:
List<myclass> filtered = mySortedlist.FindAll(delagate(myclass tmp) {
return tmp.ID == 123;
});
List<myclass> list = new List<myclass>(Helper.Take(filtered, 10));
Another option is to use LINQBridge so that you can use LINQ as much as possible - ideally using C# 3 even when you're targeting .NET 2.0, if possible. It'll make your life much simpler :)

Easy way to compare values of more than 3 variables?

I want to check whether these variables have same values.
EXAMPLE:
int a = 5;
int b = 5;
int c = 5;
int d = 5;
int e = 5;
. . .
int k = 5;
if(a==b && b==c && c==d && d==e && .... && j==k)
{
//this is Complex way and not well understandable.
}
Any easy way to Compare all are same?
LIKE in below example
if(a==b==c==d==e.....j==k)
{
//Understandable but not work
}
how about something like this:
if (Array.TrueForAll<int>(new int[] {a, b, c, d, e, f, g, h, i, j, k },
val => (a == val))) {
// do something
}
With this many variables, would it make sense to move them into an array?
You could then test to see if they are all equal using Linq expressions like myarray.Distinct().Count() == 1; or perhaps myarray.All(r => r == 5);
You could create a var args method to do that:
bool intsEqual (params int[] ints) {
for (int i = 0; i < ints.Length - 1; i++) {
if (ints[i] != ints[i+1]) {
return False;
}
}
return True;
}
Then just call it with all your ints as parameters:
if (intsEqual(a, b, c, d, e, f, g, h, i, j, k)) {
doSomeStuff();
}
Just a thought, but if you can calculate the standard deviation of the entire list, and it is equal to zero, you would have your answer.
Here's an answer on the site that addresses this that may help with that: Standard deviation of generic list?
Interesting problem. Good luck with it.
I agree that the easiest way is to place them all into a list and then use the following to compare. This is in essence looping through and comparing to the first value, but this is a little cleaner.
var match = counts.All(x => x == counts[0])
How about
int common = a;
if (a==common && b==common && c==common && d==common && .... && k==common)
You could write a helper method like this:
public static bool AllEqual<T> (params T[] values) where T : IEquatable<T>
{
if (values.Length < 2) return true;
for (int i = 1; i < values.Length; i++)
if (!values[i].Equals (values[0])) return false;
return true;
}
This will be subtly different to the == operator in special cases, though:
AllEqual (double.NaN, double.NaN).Dump(); // True
(double.NaN == double.NaN).Dump(); // False
It doesn't work because a==b evaluates to a boolean which can't be compared to an integer, c. What you have seems to be the best way.
You might consider putting the values in an array and using a for() loop. It isn't really any simpler, but it might help if the number of values changed.
You could use a variable argument helper function to perform the comparison pretty easily.
static bool CompareLongList(params int[] args)
{
if (args.Length > 1)
{
int value = args[0];
for (int i = 1; i < args.Length; ++i)
{
if (value != args[i])
return false;
}
}
return true;
}
Then you would just use the function as follows
if(CompareLongList(a,b,c,d,e,f,j,h,i,j,k))
{
// True Code
}
I know it's an old question I came across but I was wondering what's wrong with:
if (a == (b & c & d & e & f & g & h & i & j & k))
{
}
Compare the same elements in array:
same = len(uniq([1,2,3,4])) == 1
Use Linq Query.
var greatestInt = new List() { a,b,c,d,e,f}.Max();
Bitwise and is a possible way to check multiple variables for same value.
Such a helper method could of course also check for equality instead of using the '&' operator. Helper method accepting a params array of variables seems to be the right method here. We could adjust this method to accept a generic argument also, but there are only a few data types which support boolean logical operators anyways in C# (and other languages).
Testing with a high value of Int32 to check validity of this:
void Main()
{
int a = 1234567891;
int b = 1234567891;
int c = 1234567891;
int d = 1234567891;
int e = 1234567891;
int f = 1234567891;
int g = 1234567891;
int h = 1234567891;
int i = 1234567891;
int j = 1234567891;
int k = 1234567891;
bool areAllSameValue = IntUtils.AreAllVariablesSameValue(a,b,c,d,e,f,g,h,i,j,k);
areAllSameValue.Dump(); //Linqpad method - dump this code into Linqpad to test
}
public class IntUtils
{
public static bool AreAllVariablesSameValue(params int[] values)
{
if (values == null || !values.Any())
{
return false;
}
int bitWiseAndValue = values[0];
foreach (var value in values)
{
bitWiseAndValue &= value;
}
return bitWiseAndValue == values[0];
}
}
This spots also if one of the values got a different sign (negative number).

C#: how do you check lists are the same size & same elements?

There are two lists of string
List<string> A;
List<string> B;
What is the shortest code you would suggest to check that A.Count == B.Count and each element of A in B and vise versa: every B is in A (A items and B items may have different order).
If you don't need to worry about duplicates:
bool equal = new HashSet<string>(A).SetEquals(B);
If you are concerned about duplicates, that becomes slightly more awkward. This will work, but it's relatively slow:
bool equal = A.OrderBy(x => x).SequenceEquals(B.OrderBy(x => x));
Of course you can make both options more efficient by checking the count first, which is a simple expression. For example:
bool equal = (A.Count == B.Count) && new HashSet<string>(A).SetEquals(B);
... but you asked for the shortest code :)
A.Count == B.Count && new HashSet<string>(A).SetEquals(B);
If different frequencies of duplicates are an issue, check out this question.
If you call Enumerable.Except() on the two lists, that will return an IEnumerable<string> containing all of the elements that are in one list but not the other. If the count of this is 0, then you know that the two lists are the same.
var result = A.Count == B.Count && A.Where(y => B.Contains(y)).Count() == A.Count;
Maybe?
How about a simple loop?
private bool IsEqualLists(List<string> A, List<string> B)
{
for(int i = 0; i < A.Count; i++)
{
if(i < B.Count - 1) {
return false; }
else
{
if(!String.Equals(A[i], B[i]) {
return false;
}
}
}
return true;
}
If you aren't concerned about duplicates, or you're concerned about duplicates but not overly concerned about performance micro-optimisations, then the various techniques in Jon's answer are definitely the way to go.
If you're concerned about duplicates and performance then something like this extension method should do the trick, although it really doesn't meet your "shortest code" criteria!
bool hasSameElements = A.HasSameElements(B);
// ...
public static bool HasSameElements<T>(this IList<T> a, IList<T> b)
{
if (a == b) return true;
if ((a == null) || (b == null)) return false;
if (a.Count != b.Count) return false;
var dict = new Dictionary<string, int>(a.Count);
foreach (string s in a)
{
int count;
dict.TryGetValue(s, out count);
dict[s] = count + 1;
}
foreach (string s in b)
{
int count;
dict.TryGetValue(s, out count);
if (count < 1) return false;
dict[s] = count - 1;
}
return dict.All(kvp => kvp.Value == 0);
}
(Note that this method will return true if both sequences are null. If that's not the desired behaviour then it's easy enough to add in the extra null checks.)

Categories

Resources