Related
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;
}
I am wondering why if I change the line
"sub = sub.SelectMany(x => x.Next(i)).ToList();"
to
"sub = sub.SelectMany(x => x.Next(i));"
I get the error
Line 48: System.IndexOutOfRangeException: Index was outside the bounds of the array" when I provide an input of 4 to the method SolveNQueens.
I believe it may have something to do with lazy evaluation.
The full code sample is listed below and is a valid solution
to the n queens problem.
public class Solution {
public IList<IList<string>> SolveNQueens(int n)
{
IEnumerable<PartialQueens> sub = new List<PartialQueens>(){
new PartialQueens(n)};
for(int i=0;i<n;i++)
{
sub = sub.SelectMany(x => x.Next(i)).ToList();
}
return sub.Select(x => x.ToPosition()).ToList();
}
}
public class PartialQueens
{
public byte FREE = 0;
public byte BLOCKED = 1;
public byte QUEEN = 2;
public byte[,] fill;
int n;
public PartialQueens(int n)
{
this.n = n;
fill = new byte[n,n];
}
public PartialQueens(byte[,] fill, int n)
{
this.fill = fill;
this.n = n;
}
public PartialQueens Fill(int row, int column)
{
byte[,] newFill = fill.Clone() as byte[,];
newFill[row,column] = QUEEN;
Action<int,int> f = (x,y) =>
{
if(y >= 0 && y < n)
newFill[x,y] = BLOCKED;
};
for(int i=1;i<n-row;i++)
{
f(row+i,column+i);
f(row+i,column-i);
f(row+i,column);
}
return new PartialQueens(newFill,n);
}
public IEnumerable<PartialQueens> Next(int row)
{
for(int j=0;j<n;j++)
{
if(fill[row,j] == FREE)
yield return Fill(row,j);
}
}
public IList<string> ToPosition()
{
return Enumerable.Range(0,n).Select(i => ConvertRow(i)).ToList();
}
public string ConvertRow(int i)
{
StringBuilder builder = new StringBuilder();
for(int j=0;j<n;j++)
{
if(fill[i,j] == QUEEN)
builder.Append("Q");
else
builder.Append(".");
}
return builder.ToString();
}
}
The reason this fails is because of the way that the iterator variable used in a for loop is evaluated when it is captured by a closure. When you remove the ToList() inside the loop, the sub IEnumerable is only evaluated when sub is materialized in the return statement return sub.Select(x => x.ToPosition()).ToList();. At this time, the for loop variable i will have a value of n (e.g. 8 on a standard chess board), which is outside the array bounds.
However, when you materialize the List immediately, the side effect isn't encountered, since the value of i is used before the next iteration (ToList materializes).
Works:
for (int i = 0; i < n; i++)
{
// Materialized here so `i` evaluated immediately
sub = sub.SelectMany(x => x.Next(i)).ToList();
}
Broken:
for (int i = 0; i < n; i++)
{
sub = sub.SelectMany(x => x.Next(i));
}
return sub.Select(x => x.ToPosition()).ToList(); // `i` evaluated here
To fix the for loop variable evaluation issue, you can explicitly capture the current value of the iterator variable:
for (int i = 0; i < n; i++)
{
var loop = i;
sub = sub.SelectMany(x => x.Next(loop)); // No To List - lazy evaluation
}
Re : Avoiding for loops in FP Paradigm code
OP's SolveNQueens method uses a loop which progressively changes the sub, rather than recursion, but the for can also be replaced with a foreach and a range:
foreach(var i in Enumerable.Range(0, n))
{
sub = sub.SelectMany(x => x.Next(i));
}
Which Resharper then offers to re-write as a left fold:
sub = Enumerable.Range(0, n)
.Aggregate(sub, (current, i) => current.SelectMany(x => x.Next(i)));
Either way, the flaw in lazy evaluation of the iterator variable inside a for loop is avoided.
Very brief question. I have a randomly sorted large string array (100K+ entries) where I want to find the first occurance of a desired string. I have two solutions.
From having read what I can my guess is that the 'for loop' is going to currently give slightly better performance (but this margin could always change), but I also find the linq version much more readable. On balance which method is generally considered current best coding practice and why?
string matchString = "dsf897sdf78";
int matchIndex = -1;
for(int i=0; i<array.length; i++)
{
if(array[i]==matchString)
{
matchIndex = i;
break;
}
}
or
int matchIndex = array.Select((r, i) => new { value = r, index = i })
.Where(t => t.value == matchString)
.Select(s => s.index).First();
The best practice depends on what you need:
Development speed and maintainability: LINQ
Performance (according to profiling tools): manual code
LINQ really does slow things down with all the indirection. Don't worry about it as 99% of your code does not impact end user performance.
I started with C++ and really learnt how to optimize a piece of code. LINQ is not suited to get the most out of your CPU. So if you measure a LINQ query to be a problem just ditch it. But only then.
For your code sample I'd estimate a 3x slowdown. The allocations (and subsequent GC!) and indirections through the lambdas really hurt.
Slightly better performance? A loop will give SIGNIFICANTLY better performance!
Consider the code below. On my system for a RELEASE (not debug) build, it gives:
Found via loop at index 999999 in 00:00:00.2782047
Found via linq at index 999999 in 00:00:02.5864703
Loop was 9.29700432810805 times faster than linq.
The code is deliberately set up so that the item to be found is right at the end. If it was right at the start, things would be quite different.
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
namespace Demo
{
public static class Program
{
private static void Main(string[] args)
{
string[] a = new string[1000000];
for (int i = 0; i < a.Length; ++i)
{
a[i] = "Won't be found";
}
string matchString = "Will be found";
a[a.Length - 1] = "Will be found";
const int COUNT = 100;
var sw = Stopwatch.StartNew();
int matchIndex = -1;
for (int outer = 0; outer < COUNT; ++outer)
{
for (int i = 0; i < a.Length; i++)
{
if (a[i] == matchString)
{
matchIndex = i;
break;
}
}
}
sw.Stop();
Console.WriteLine("Found via loop at index " + matchIndex + " in " + sw.Elapsed);
double loopTime = sw.Elapsed.TotalSeconds;
sw.Restart();
for (int outer = 0; outer < COUNT; ++outer)
{
matchIndex = a.Select((r, i) => new { value = r, index = i })
.Where(t => t.value == matchString)
.Select(s => s.index).First();
}
sw.Stop();
Console.WriteLine("Found via linq at index " + matchIndex + " in " + sw.Elapsed);
double linqTime = sw.Elapsed.TotalSeconds;
Console.WriteLine("Loop was {0} times faster than linq.", linqTime/loopTime);
}
}
}
LINQ, according to declarative paradigm, expresses the logic of a computation without describing its control flow. The query is goal oriented, selfdescribing and thus easy to analyse and understand. Is also concise. Moreover, using LINQ, one depends highly upon abstraction of data structure. That involves high rate of maintanability and reusability.
Iteration aproach addresses imperative paradigm. It gives fine-grained control, thus ease obtain higher performance. The code is also simpler to debug. Sometimes well contructed iteration is more readable than query.
There is always dilemma between performance and maintainability. And usually (if there is no specific requirements about performance) maintainability should win. Only if you have performance problems, then you should profile application, find problem source, and improve its performance (by reducing maintainability at same time, yes that's the world we live in).
About your sample. Linq is not very good solution here, because it do not add match maintainability into your code. Actually for me projecting, filtering, and projecting again looks even worse, than simple loop. What you need here is simple Array.IndexOf, which is more maintainable, than loop, and have almost same performance:
Array.IndexOf(array, matchString)
Well, you gave the answer to your question yourself.
Go with a For loop if you want the best performance, or go with Linq if you want readability.
Also perhaps keep in mind the possibility of using Parallel.Foreach() which would benefit from in-line lambda expressions (so, more closer to Linq), and that is much more readable then doing paralelization "manually".
I don't think either is considered best practice some people prefer looking at LINQ and some don't.
If performance is a issue the I would profile both bits of code for your scenario and if the difference is negligible then go with the one you feel more conformable with, after all it will most likely be you who maintains the code.
Also have you thought about using PLINQ or making the loop run in parallel?
Just an interesting observation. LINQ Lambda queries for sure add a penalty over LINQ Where queries or a For Loop. In the following code, it fills a list with 1000001 multi-parameter objects and then searches for a specific item that in this test will always be the last one, using a LINQ Lamba, a LINQ Where Query and a For Loop. Each test iterates 100 times and then averages the times to get the results.
LINQ Lambda Query Average Time: 0.3382 seconds
LINQ Where Query Average Time: 0.238 seconds
For Loop Average Time: 0.2266 seconds
I've run this test over and over, and even increase the iteration and the spread is pretty much identical statistically speaking. Sure we are talking 1/10 of a second for essentially that a million item search. So in the real world, unless something is that intensive, not sure you would even notice. But if you do the LINQ Lambda vs LINQ Where query does have a difference in performance. The LINQ Where is near the same as the For Loop.
private void RunTest()
{
try
{
List<TestObject> mylist = new List<TestObject>();
for (int i = 0; i <= 1000000; i++)
{
TestObject testO = new TestObject(string.Format("Item{0}", i), 1, Guid.NewGuid().ToString());
mylist.Add(testO);
}
mylist.Add(new TestObject("test", "29863", Guid.NewGuid().ToString()));
string searchtext = "test";
int iterations = 100;
// Linq Lambda Test
List<int> list1 = new List<int>();
for (int i = 1; i <= iterations; i++)
{
DateTime starttime = DateTime.Now;
TestObject t = mylist.FirstOrDefault(q => q.Name == searchtext);
int diff = (DateTime.Now - starttime).Milliseconds;
list1.Add(diff);
}
// Linq Where Test
List<int> list2 = new List<int>();
for (int i = 1; i <= iterations; i++)
{
DateTime starttime = DateTime.Now;
TestObject t = (from testO in mylist
where testO.Name == searchtext
select testO).FirstOrDefault();
int diff = (DateTime.Now - starttime).Milliseconds;
list2.Add(diff);
}
// For Loop Test
List<int> list3 = new List<int>();
for (int i = 1; i <= iterations; i++)
{
DateTime starttime = DateTime.Now;
foreach (TestObject testO in mylist)
{
if (testO.Name == searchtext)
{
TestObject t = testO;
break;
}
}
int diff = (DateTime.Now - starttime).Milliseconds;
list3.Add(diff);
}
float diff1 = list1.Average();
Debug.WriteLine(string.Format("LINQ Lambda Query Average Time: {0} seconds", diff1 / (double)100));
float diff2 = list2.Average();
Debug.WriteLine(string.Format("LINQ Where Query Average Time: {0} seconds", diff2 / (double)100));
float diff3 = list3.Average();
Debug.WriteLine(string.Format("For Loop Average Time: {0} seconds", diff3 / (double)100));
}
catch (Exception ex)
{
Debug.WriteLine(ex.ToString());
}
}
private class TestObject
{
public TestObject(string _name, string _value, string _guid)
{
Name = _name;
Value = _value;
GUID = _guid;
}
public string Name;
public string Value;
public string GUID;
}
The Best Option Is To Use IndexOf method of Array Class. Since it is specialized for arrays it will b significantly faster than both Linq and For Loop.
Improving on Matt Watsons Answer.
using System;
using System.Diagnostics;
using System.Linq;
namespace PerformanceConsoleApp
{
public class LinqVsFor
{
private static void Main(string[] args)
{
string[] a = new string[1000000];
for (int i = 0; i < a.Length; ++i)
{
a[i] = "Won't be found";
}
string matchString = "Will be found";
a[a.Length - 1] = "Will be found";
const int COUNT = 100;
var sw = Stopwatch.StartNew();
Loop(a, matchString, COUNT, sw);
First(a, matchString, COUNT, sw);
Where(a, matchString, COUNT, sw);
IndexOf(a, sw, matchString, COUNT);
Console.ReadLine();
}
private static void Loop(string[] a, string matchString, int COUNT, Stopwatch sw)
{
int matchIndex = -1;
for (int outer = 0; outer < COUNT; ++outer)
{
for (int i = 0; i < a.Length; i++)
{
if (a[i] == matchString)
{
matchIndex = i;
break;
}
}
}
sw.Stop();
Console.WriteLine("Found via loop at index " + matchIndex + " in " + sw.Elapsed);
}
private static void IndexOf(string[] a, Stopwatch sw, string matchString, int COUNT)
{
int matchIndex = -1;
sw.Restart();
for (int outer = 0; outer < COUNT; ++outer)
{
matchIndex = Array.IndexOf(a, matchString);
}
sw.Stop();
Console.WriteLine("Found via IndexOf at index " + matchIndex + " in " + sw.Elapsed);
}
private static void First(string[] a, string matchString, int COUNT, Stopwatch sw)
{
sw.Restart();
string str = "";
for (int outer = 0; outer < COUNT; ++outer)
{
str = a.First(t => t == matchString);
}
sw.Stop();
Console.WriteLine("Found via linq First at index " + Array.IndexOf(a, str) + " in " + sw.Elapsed);
}
private static void Where(string[] a, string matchString, int COUNT, Stopwatch sw)
{
sw.Restart();
string str = "";
for (int outer = 0; outer < COUNT; ++outer)
{
str = a.Where(t => t == matchString).First();
}
sw.Stop();
Console.WriteLine("Found via linq Where at index " + Array.IndexOf(a, str) + " in " + sw.Elapsed);
}
}
}
Output:
Found via loop at index 999999 in 00:00:01.1528531
Found via linq First at index 999999 in 00:00:02.0876573
Found via linq Where at index 999999 in 00:00:01.3313111
Found via IndexOf at index 999999 in 00:00:00.7244812
A bit of a non-answer, and really just an extension to https://stackoverflow.com/a/14894589, but I have, on and off, been working on an API-compatible replacement for Linq-to-Objects for a while now. It still doesn't provide the performance of a hand-coded loop, but it is faster for many (most?) linq scenarios. It does create more garbage, and has some slightly heavier up front costs.
The code is available https://github.com/manofstick/Cistern.Linq
A nuget package is available https://www.nuget.org/packages/Cistern.Linq/ (I can't claim this to be battle hardened, use at your own risk)
Taking the code from Matthew Watson's answer (https://stackoverflow.com/a/14894589) with two slight tweaks, and we get the time down to "only" ~3.5 time worse than the hand-coded loop. On my machine it take about 1/3 of the time of original System.Linq version.
The two changes to replace:
using System.Linq;
...
matchIndex = a.Select((r, i) => new { value = r, index = i })
.Where(t => t.value == matchString)
.Select(s => s.index).First();
With the following:
// a complete replacement for System.Linq
using Cistern.Linq;
...
// use a value tuple rather than anonymous type
matchIndex = a.Select((r, i) => (value: r, index: i))
.Where(t => t.value == matchString)
.Select(s => s.index).First();
So the library itself is a work in progress. It fails a couple of edge cases from the corefx's System.Linq test suite. It also still needs a few functions to be converted over (they currently have the corefx System.Linq implementation, which is compatible from an API perspective, if not a performance perspective). But anymore who wants to help, comment, etc would be appreciated....
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;
}
I'm looking for a better alternative for Enumerable.Count() == n. The best I've been able to come up with is:
static class EnumerableExtensions
{
public static bool CountEquals<T>(this IEnumerable<T> items, int n)
{
if (n <= 0) throw new ArgumentOutOfRangeException("n"); // use Any()
var iCollection = items as System.Collections.ICollection;
if (iCollection != null)
return iCollection.Count == n;
int count = 0;
bool? retval = null;
foreach (var item in items)
{
count++;
if (retval.HasValue)
return false;
if (count == n)
retval = true;
}
if (retval.HasValue)
return retval.Value;
return false;
}
}
class Program
{
static void Main(string[] args)
{
var items0 = new List<int>();
var items1 = new List<int>() { 314 };
var items3 = new List<int>() { 1, 2, 3 };
var items5 = new List<int>() { 1, 2, 3, 4, 5 };
var items10 = Enumerable.Range(0, 10);
var itemsLarge = Enumerable.Range(0, Int32.MaxValue);
Console.WriteLine(items0.CountEquals(3));
Console.WriteLine(items1.CountEquals(3));
Console.WriteLine(items3.CountEquals(3));
Console.WriteLine(items5.CountEquals(3));
Console.WriteLine(itemsLarge.CountEquals(3));
}
}
Can I do any better? Is there a way to generalize this even more—passing in the comparision?
You can use a combination of Take and Count to get rid of the loop entirely:
public static bool CountEquals<T>(this IEnumerable<T> items, int n)
{
var iCollection = items as System.Collections.ICollection;
if (iCollection != null)
return iCollection.Count == n;
return items.Take(n + 1).Count() == n;
}
Using Enumerable.Count would be much better than your code above. It already optimizes for ICollection internally.
That being said, if you must keep your extension, you could simplify the loop a bit:
int count = 0;
foreach (var item in items)
{
count++;
if(count > n)
return false;
}
return count == n;
What exactly do you mean by "better"? Faster? Easier?
Essentially what you seem to have done is written a specialized method that's optimized for one specific task. You mention generalizing it, but its performance advantage stems from the fact that it's so specific (assuming there is a performance advantage--methods like Count are already tuned pretty hard for performance, and the compiler's pretty good at optimizing stuff like this).
Premature optimization is the root of all evil. If the performance of this particular operation is so important that it's worth replacing the twenty-odd-character expression xyz.Count() == abc with dozens of lines of code, you may want to try other methods of increasing performance, like refactoring. For most situations, just the overhead from using managed code is going to dwarf the performance bonus you get (if any).
That being said -- if you have something like 10 million items, and your target count is a whole lot less, I'm pretty sure the below will short-circuit the iteration:
int count = 0;
var subset = items.TakeWhile(x => count++ < n + 1);
return count == n + 1;
Easy to read, easy to maintain, and probably just as fast.