I have a a line of code that looks like this
var results = DataBase.Find(x.ImportanceFactor > 5 && x.ImportanceFactor < 10);
Now in the Findfunction, what Data Structure can i use?
public static int Find(??? input)
{
:
Some Code
:
}
The format needs to be exactly how i specified above, but i have having a hard time finding a data structure to support it. I have tried a number of Expressions in Linq to no success.
EDIT For Clarification:
The Find function will go into the a database and look for an object whose importance is within the specified range, and return whichever object in that range has the highest Size value. Again, that first line cant be changed in any way, regardless of what happens in the Find function. The line below needs to be available in the Find
x.ImportanceFactor > 5 && x.ImportanceFactor < 10
EDIT2:
X is a dynamic expression, not an object with properties.
This:
x.ImportanceFactor > 5 && x.ImportanceFactor < 10
is just a bool:
public static int Find(bool input)
But given the usage of x in that condition, I suspect you actually meant this:
var results = DataBase.Find(x => x.ImportanceFactor > 5 && x.ImportanceFactor < 10);
In which case you're looking at something structurally very similar to methods like Any() or Where() on IEnumerable<T>. That would use something more like Func<T, bool>:
public static int Find<T>(Func<T, bool> input)
Related
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).
I'm getting this error message during runtime
LINQ to Entities does not recognize the method 'Int64 Max(Int64, Int64)' method, and this method cannot be translated into a store expression.
when I try to do this:
return _dbContext.Appointment.Where(x => Math.Max(x.Appointment.StartTime.Ticks, startTime.Ticks) <= Math.Min(x.Appointment.EndTime.Ticks, endTime.Ticks));
The idea behind this query is that "if the latest start time is before the earliest end time, then you have some overlap/touching" in date and time.
Is there any way to get this line working? I already checked if EntityFunctions has 'something', which wasn't the case.
Max and Min can be implemented like this:
public static long Max(long a, long b)
{
return a < b ? b : a;
}
public static long Min(long a, long b)
{
return a < b ? a : b;
}
Since LINQ to Entities understands ? :, you will be able to inline these into your expression. Also, since Ticks is not supported, but DateTime comparison is...
Math.Max(x.Appointment.StartTime.Ticks, startTime.Ticks)
Becomes
(x.Appointment.StartTime < startTime ? startTime : x.Appointment.StartTime)
You must always keep in mind that every IQueryable provider is implemented in its own way. That query would work in Linq to Objects (as it does not gets translated to anything) but may or may not work in IQueryable providers.
In your specific case, it's telling you that it has no idea on how to translate Math.Max and Math.Min into SQL commands. And that's perfectly correct, since EF doesn't recognize those methods.
In my opinion the easiest way to accomplish what you need is reading the max and the min value with two different queries and then do your logic in plain c#. Something like this:
var min = mycontext.MyDbSet.Min(c => c.Field);
var max = mycontext.MyDbSet.Max(c => c.Field);
if (max <= min)
{
// do something
}
I have code that needs to know that a collection should not be empty or contain only one item.
In general, I want an extension of the form:
bool collectionHasAtLeast2Items = collection.AtLeast(2);
I can write an extension easily, enumerating over the collection and incrementing an indexer until I hit the requested size, or run out of elements, but is there something already in the LINQ framework that would do this? My thoughts (in order of what came to me) are::
bool collectionHasAtLeast2Items = collection.Take(2).Count() == 2; or
bool collectionHasAtLeast2Items = collection.Take(2).ToList().Count == 2;
Which would seem to work, though the behaviour of taking more elements than the collection contains is not defined (in the documentation) Enumerable.Take Method , however, it seems to do what one would expect.
It's not the most efficient solution, either enumerating once to take the elements, then enumerating again to count them, which is unnecessary, or enumerating once to take the elements, then constructing a list in order to get the count property which isn't enumerator-y, as I don't actually want the list.
It's not pretty as I always have to make two assertions, first taking 'x', then checking that I actually received 'x', and it depends upon undocumented behaviour.
Or perhaps I could use:
bool collectionHasAtLeast2Items = collection.ElementAtOrDefault(2) != null;
However, that's not semantically-clear. Maybe the best is to wrap that with a method-name that means what I want. I'm assuming that this will be efficient, I haven't reflected on the code.
Some other thoughts are using Last(), but I explicitly don't want to enumerate through the whole collection.
Or maybe Skip(2).Any(), again not semantically completely obvious, but better than ElementAtOrDefault(2) != null, though I would think they produce the same result?
Any thoughts?
public static bool AtLeast<T>(this IEnumerable<T> source, int count)
{
// Optimization for ICollection<T>
var genericCollection = source as ICollection<T>;
if (genericCollection != null)
return genericCollection.Count >= count;
// Optimization for ICollection
var collection = source as ICollection;
if (collection != null)
return collection.Count >= count;
// General case
using (var en = source.GetEnumerator())
{
int n = 0;
while (n < count && en.MoveNext()) n++;
return n == count;
}
}
You can use Count() >= 2, if you sequence implements ICollection?
Behind the scene, Enumerable.Count() extension method checks does the sequence under loop implements ICollection. If it does indeed, Count property returned, so target performance should be O(1).
Thus ((IEnumerable<T>)((ICollection)sequence)).Count() >= x also should have O(1).
You could use Count, but if performance is an issue, you will be better off with Take.
bool atLeastX = collection.Take(x).Count() == x;
Since Take (I believe) uses deferred execution, it will only go through the collection once.
abatishchev mentioned that Count is O(1) with ICollection, so you could do something like this and get the best of both worlds.
IEnumerable<int> col;
// set col
int x;
// set x
bool atLeastX;
if (col is ICollection<int>)
{
atLeastX = col.Count() >= x;
}
else
{
atLeastX = col.Take(x).Count() == x;
}
You could also use Skip/Any, in fact I bet it would be even faster than Take/Count.
I'm looking for a way of parsing a conditional expression to a string.
The best example I can think of is LINQ-to-SQL. It uses ExpressionVisitors to format "Where" clauses. Example:
from a in b where a.x == 5 && a.y < 3 select a
That would translate into the following string (approximately, MSSQL is not current for me):
"SELECT * FROM b WHERE x = 5 AND y < 3"
From what I've read, this was done using the ExpressionVisitor class, as explained in this article: Link
Now the problem is that I don't use LINQ, but I need this particular functionality. Is there a way of parsing a condition like that? I'm willing to do anything with reflection, delegates, lambda, etc.
Honestly, I don't think it's possible, but my brain is a bit fried (read: be nice if the question is ridiculous), so I figured I might just as well give S/O a try.
EDIT: Final usage example:
// Usage:
foo.Bar(foo => foo.X == 5 && foo.Y < 3)
// Ideal string output (variable name (foo) is not needed):
"foo.X == 5 && foo.Y < 3"
EDIT 2: Yes, a number can be lower than 3 and equal to 5. Told you my brain is fried.
If it is about about building the expression tree itself, then you could leverage C# compiler abilities.
It is legal to pass a lambda expression to a function acception an Expression>, as long as type arguments of Func are known. For example
private static void PrintExpression(Expression<Func<int, bool>> lambda)
{
Console.WriteLine(lambda.ToString());
}
can be called as
PrintExpression(a=> a > 0 && a < 5);
You can improvise with generics as
private static void PrintExpression<T1,T2>(Expression<Func<T1, T2>> lambda)
{
Console.WriteLine(lambda.ToString());
}
and calling it with
PrintExpression<int, bool>(a=> a > 0 && a < 5);
For custom printing of the expression part, you can write a simple recursive function that prints an expression or any other logic that suits you.
Remember, the lambda expression is compiled into an Expression at compile time - so can't subsititute it with already compiled Func.
As an alternative to this, you can always build a custom query provider, but that would be slightly deviating from the purpose - as you'd need to bind it some sort of queryable (custom again).
Try something like this:
static string GetExpressionString<T>(Expression<Func<T, bool>> expression)
{
return expression.Body.ToString();
}
Usage as so:
string s = GetExpressionString<Foo>(foo => foo.X == 5 && foo.Y < 3);
Which will return:
((foo.X = 5) && (foo.Y < 3))
I'm a complete LINQ newbie, so I don't know if my LINQ is incorrect for what I need to do or if my expectations of performance are too high.
I've got a SortedList of objects, keyed by int; SortedList as opposed to SortedDictionary because I'll be populating the collection with pre-sorted data. My task is to find either the exact key or, if there is no exact key, the one with the next higher value. If the search is too high for the list (e.g. highest key is 100, but search for 105), return null.
// The structure of this class is unimportant. Just using
// it as an illustration.
public class CX
{
public int KEY;
public DateTime DT;
}
static CX getItem(int i, SortedList<int, CX> list)
{
var items =
(from kv in list
where kv.Key >= i
select kv.Key);
if (items.Any())
{
return list[items.Min()];
}
return null;
}
Given a list of 50,000 records, calling getItem 500 times takes about a second and a half. Calling it 50,000 times takes over 2 minutes. This performance seems very poor. Is my LINQ bad? Am I expecting too much? Should I be rolling my own binary search function?
First, your query is being evaluated twice (once for Any, and once for Min). Second, Min requires that it iterate over the entire list, even though the fact that it's sorted means that the first item will be the minimum. You should be able to change this:
if (items.Any())
{
return list[items.Min()];
}
To this:
var default =
(from kv in list
where kv.Key >= i
select (int?)kv.Key).FirstOrDefault();
if(default != null) return list[default.Value];
return null;
UPDATE
Because you're selecting a value type, FirstOrDefault doesn't return a nullable object. I have altered your query to cast the selected value to an int? instead, allowing the resulting value to be checked for null. I would advocate this over using ContainsKey, as that would return true if your list contained a value for 0. For example, say you have the following values
0 2 4 6 8
If you were to pass in anything less than or equal to 8, then you would get the correct value. However, if you were to pass in 9, you would get 0 (default(int)), which is in the list but isn't a valid result.
Writing a binary search on your own can be tough.
Fortunately, Microsoft already wrote a pretty robust one: Array.BinarySearch<T>. This is, in fact, the method that SortedList<TKey, TValue>.IndexOfKey uses internally. Only problem is, it takes a T[] argument, instead of any IList<T> (like SortedList<TKey, TValue>.Keys).
You know what, though? There's this great tool called Reflector that lets you look at .NET source code...
Check it out: a generic BinarySearch extension method on IList<T>, taken straight from the reflected code of Microsoft's Array.BinarySearch<T> implementation.
public static int BinarySearch<T>(this IList<T> list, int index, int length, T value, IComparer<T> comparer) {
if (list == null)
throw new ArgumentNullException("list");
else if (index < 0 || length < 0)
throw new ArgumentOutOfRangeException((index < 0) ? "index" : "length");
else if (list.Count - index < length)
throw new ArgumentException();
int lower = index;
int upper = (index + length) - 1;
while (lower <= upper) {
int adjustedIndex = lower + ((upper - lower) >> 1);
int comparison = comparer.Compare(list[adjustedIndex], value);
if (comparison == 0)
return adjustedIndex;
else if (comparison < 0)
lower = adjustedIndex + 1;
else
upper = adjustedIndex - 1;
}
return ~lower;
}
public static int BinarySearch<T>(this IList<T> list, T value, IComparer<T> comparer) {
return list.BinarySearch(0, list.Count, value, comparer);
}
public static int BinarySearch<T>(this IList<T> list, T value) where T : IComparable<T> {
return list.BinarySearch(value, Comparer<T>.Default);
}
This will let you call list.Keys.BinarySearch and get the negative bitwise complement of the index you want in case the desired key isn't found (the below is taken basically straight from tzaman's answer):
int index = list.Keys.BinarySearch(i);
if (index < 0)
index = ~index;
var item = index < list.Count ? list[list.Keys[index]] : null;
return item;
Using LINQ on a SortedList will not give you the benefit of the sort.
For optimal performance, you should write your own binary search.
OK, just to give this a little more visibility - here's a more concise version of Adam Robinson's answer:
return list.FirstOrDefault(kv => kv.Key >= i).Value;
The FirstOrDefault function has an overload that accepts a predicate, which selects the first element satisfying a condition - you can use that to directly get the element you want, or null if it doesn't exist.
Why not use the BinarySearch that's built into the List class?
var keys = list.Keys.ToList();
int index = keys.BinarySearch(i);
if (index < 0)
index = ~index;
var item = index < keys.Count ? list[keys[index]] : null;
return item;
If the search target isn't in the list, BinarySearch returns the bit-wise complement of the next-higher item; we can use that to directly get you what you want by re-complementing the result if it's negative. If it becomes equal to the Count, your search key was bigger than anything in the list.
This should be much faster than doing a LINQ where, since it's already sorted...
As comments have pointed out, the ToList call will force an evaluation of the whole list, so this is only beneficial if you do multiple searches without altering the underlying SortedList, and you keep the keys list around separately.
Using OrderedDictionary in PowerCollections you can get an enumerator that starts where they key you are looking for should be... if it's not there, you'll get the next closest node and can then navigate forwards/backwards from that in O(log N) time per nav call.
This has the advantage of you not having to write your own search or even manage your own searches on top of a SortedList.