I have an IEnumerable and a predicate (Func) and I am writing a method that shall return a value if only one instance in the list matches the predicate. If the criteria is matched by none, then none was found. If the criteria is matched by many instances, then the predicate was insufficient to successfully identify the desired record. Both cases should return null.
What is the recommended way to express this in LINQ that does not result in multiple enumerations of the list?
The LINQ operator SingleOrDefault will throw an exception if multiple instances are found.
The LINQ operator FirstOrDefault will return the first even when multiple was found.
MyList.Where(predicate).Skip(1).Any()
...will check for ambiguity, but will not retain the desired record.
It seems that my best move is to grab the Enumerator from MyList.Where(predicate) and retain the first instance if accessing the next item fails, but it seems slightly verbose.
Am I missing something obvious?
The "slightly verbose" option seems reasonable to me, and can easily be isolated into a single extension method:
// TODO: Come up with a better name :)
public static T SingleOrDefaultOnMultiple<T>(this IEnumerable<T> source)
{
// TODO: Validate source is non-null
using (var iterator = source.GetEnumerator())
{
if (!iterator.MoveNext())
{
return default(T);
}
T first = iterator.Current;
return iterator.MoveNext() ? default(T) : first;
}
}
Update: Here is a more general approach which might be more reusable.
public static IEnumerable<TSource> TakeIfCountBetween<TSource>(this IEnumerable<TSource> source, int minCount, int maxCount, int? maxTake = null)
{
if (source == null)
throw new ArgumentNullException("source");
if (minCount <= 0 || minCount > maxCount)
throw new ArgumentException("minCount must be greater 0 and less than or equal maxCount", "minCount");
if (maxCount <= 0)
throw new ArgumentException("maxCount must be greater 0", "maxCount");
int take = maxTake ?? maxCount;
if (take > maxCount)
throw new ArgumentException("maxTake must be lower or equal maxCount", "maxTake");
if (take < minCount)
throw new ArgumentException("maxTake must be greater or equal minCount", "maxTake");
int count = 0;
ICollection objCol;
ICollection<TSource> genCol = source as ICollection<TSource>;
if (genCol != null)
{
count = genCol.Count;
}
else if ((objCol = source as ICollection) != null)
{
count = objCol.Count;
}
else
{
using (IEnumerator<TSource> enumerator = source.GetEnumerator())
{
while (enumerator.MoveNext() && ++count < maxCount);
}
}
bool valid = count >= minCount && count <= maxCount;
if (valid)
return source.Take(take);
else
return Enumerable.Empty<TSource>();
}
Usage:
var list = new List<string> { "A", "B", "C", "E", "E", "F" };
IEnumerable<string> result = list
.Where(s => s == "A")
.TakeIfCountBetween(1, 1);
Console.Write(string.Join(",", result)); // or result.First()
Related
in linq i'm tring to create gridview with dynamic sort columns
can any one help me what is worng on below code and why it does't work
// i created this function to get column value which i need to sorty by
private static string GetReflectedPropertyValue( object subject, string field)
{
object reflectedValue = subject.GetType().GetProperty(field).GetValue(subject, null);
return reflectedValue != null ? reflectedValue.ToString() : "";
}
// this is my grid query
List<ticketSearchRes> tickets = new List<ticketSearchRes>();
// here i deteermined sort direction ascending or desc
bool asc = (gridViewInputsVM.SortDirection == "asc") ? true : false;
bool desc = (gridViewInputsVM.SortDirection != "asc") ? true : false;
IQueryable<ticketSearchRes> source = (from ticket in _db.TblTicket
where (searchRes.assignTic == 1) ? ticket.AssignedTo == CurrentuserId : true
where (searchRes.myTicket == 1 && searchRes.forOthers != 1) ? ticket.CreatedFor == CurrentuserId : true
orderby
asc ? GetReflectedPropertyValue(ticket, "TicketTitle") : "",
// here i need to get dynamic column which i need to sort by
desc ? GetReflectedPropertyValue(ticket, "TicketTitle") : "" descending // doesn't work
select new ticketSearchRes
{
title = (ticket.TicketTitle != null) ? ticket.TicketTitle.ToString() : "",
ticId = ticket.TicketId.ToString()
}).AsQueryable();
How I would solve this is;
The partial class TicketSearchResList is part that fills in the partial method CustomSort. CustomSort accepts a property name and a sort direction and uses Reflection to sort on the named property. So far it should be easy to follow.
public partial class TicketSearchResList : List<TicketSearchRes>
{
partial void CustomSort(string propertyName, string direction);
public void Dump()
{
CustomSort("TicketTitle", "desc");
foreach(var ticket in this)
Console.WriteLine(ticket.ToString()); // For demo purposes
}
}
public partial class TicketSearchResList {
private string propertyName;
private string direction;
partial void CustomSort(string propertyName, string direction)
{
this.propertyName = propertyName;
this.direction = direction;
Sort(Comparer);
}
private int Comparer(TicketSearchRes x, TicketSearchRes y)
{
int directionChanger = direction == "asc" ? 1 : -1;
try
{
PropertyInfo lhs = x.GetType().GetProperty(propertyName);
PropertyInfo rhs = y.GetType().GetProperty(propertyName);
object o1 = lhs.GetValue(x, null);
object o2 = rhs.GetValue(y, null);
if(o1 is IComparable && o2 is IComparable)
{
return ((IComparable)o1).CompareTo(o2) * directionChanger;
}
// No sort
return 0;
}
catch(Exception ex)
{
Debug.WriteLine(ex.Message); // Should log something
return 0;
}
}
The comparison is done using Reflection in the Comparer method. The direction is
used to determine whether to multiply the result by 1 or -1. CompareTo returns
an integer where -1 means less than, 0 means equal to, and 1 means greater than. Thus, if
you multiply the result by -1, you change the direction of the sort.
Finally, the TicketSearchResList class inherits from List<TicketResearchRes>. As you can see, the Dump method calls CustomSort, which, if implemented, yields ordered output.
Also, have a look at the Sort Method documented here by Microsoft
In my C# application i am using linq. I need a help what is the syntax for if-elseif- using linq in single line. Data, RangeDate are the inputs. Here is the code:
var Date1 = RangeData.ToList();
int record =0;
foreach (var tr in Date1)
{
int id =0;
if (tr.Item1 != null && tr.Item1.port != null)
{
id = tr.Item1.port.id;
}
else if (tr.Item2 != null && tr.Item2.port != null)
{
id = tr.Item2.port.id;
}
if (id >0)
{
if(Data.Trygetvalue(id, out cdat)
{
// Do some operation. (var cdata = SumData(id, tr.item2.port.Date)
record ++;
}
}
}
I think your code example is false, your record variable is initialized to 0 on each loop so increment it is useless .
I suppose that you want to count records in your list which have an id, you can achieve this with one single Count() :
var record = Date1.Count(o => (o.Item1?.port?.id ?? o.Item2?.port?.id) > 0);
You can use following code:
var count = RangeData.Select(x => new { Id = x.Item1?.port?.id ?? x.Item2?.port?.id ?? 0, Item = x })
.Count(x =>
{
int? cdate = null; // change int to your desired type over here
if (x.Id > 0 && Data.Trygetvalue(x.Id, out cdat))
{
// Do some operation. (var cdata = SumData(x.Id, x.Item.Item2.port.Date)
return true;
}
return false;
});
Edit:
#D Stanley is completely right, LINQ is wrong tool over here. You can refactor few bits of your code though:
var Date1 = RangeData.ToList();
int record =0;
foreach (var tr in Date1)
{
int? cdat = null; // change int to your desired type over here
int id = tr.Item1?.port?.id ?? tr.Item2?.port?.id ?? 0;
if (id >0 && Data.Trygetvalue(id, out cdat))
{
// Do some operation. (var cdata = SumData(id, tr.Item2.port.Date)
record ++;
}
}
Linq is not the right tool here. Linq is for converting or querying a collection. You are looping over a collection and "doing some operation". Depending on what that operation is, trying to shoehorn it into a Linq statement will be harder to understand to an outside reader, difficult to debug, and hard to maintain.
There is absolutely nothing wrong with the loop that you have. As you can tell from the other answers, it's difficult to wedge all of the information you have into a "single-line" statement just to use Linq.
I am getting an "Object Reference not set to an instance of an object" error when searching for an item (on Guid) that is selected from a datagrid. I have checked that the item does return the Guid correctly (by writing it to a label on the page), however in my linq query (i assume) i am comparing incorrectly.
ctx is the domaindatasource, I know the element im trying to remove exists.
private void medItemRemove_Click(object sender, RoutedEventArgs e)
{
MedicineInventory M = (MedicineInventory)medicineInventoryDataGrid.SelectedItem;
Guid Mid = M.MedicineInventoryId;
MedicineInventory toRemove = new MedicineInventory();
toRemove = (from a in ctx.MedicineInventories where (a.MedicineInventoryId == Mid) select a).Single();
ctx.MedicineInventories.Remove(toRemove);
ctx.SubmitChanges();
}
Rewrite your code as follows:
private void medItemRemove_Click(object sender, RoutedEventArgs e)
{
MedicineInventory M = (MedicineInventory)medicineInventoryDataGrid.SelectedItem;
Guid Mid = M.MedicineInventoryId;
MedicineInventory toRemove = (from a in ctx.MedicineInventories where (a != null && a.MedicineInventoryId == Mid) select a).SingleOrDefault();
if (toRemove != null){
ctx.MedicineInventories.Remove(toRemove);
ctx.SubmitChanges();
}
else { .... } // code if toRemove is null
}
Is a null at any point?
toRemove = (from a in ctx.MedicineInventories where (a != null && a.MedicineInventoryId == Mid) select a).Single();
I think your problem is happening because you're creating a new MedicineInventory.
Replace this:
MedicineInventory toRemove = new MedicineInventory();
With this:
var toRemove = ctx.MedicineInventories.Single(mi => mi.MedicineInventoryId == Mid);
Update:
When it retuns the error message "Sequence contains no elements" it's because EF could not find a row in the database with the same Guid you're using in the where clause. In this case and to avoid an exception, you can try this line of code:
var toRemove = ctx.MedicineInventories.SingleOrDefault(
mi => mi.MedicineInventoryId == Mid);
then use an if to delete if it's not NULL:
if(toRemove != null)
{
ctx.MedicineInventories.Remove(toRemove);
ctx.SubmitChanges();
}
else
{
// Only you know what to do! :-)
}
SingleOrDefault returns the only element of a sequence, or a default
value (NULL in this case) if the sequence is empty; this method
throws an exception if there is more than one element in the sequence.
Note: the way you're comparing the Guids is correct because == is overloaded on Guid so you don't need to compare the string representations.
See http://msdn.microsoft.com/en-us/library/system.guid.op_equality%28v=vs.110%29.aspx#Y474
While looking though some code of the project I'm working on, I've come across a pretty hefty method which does
the following:
public string DataField(int id, string fieldName)
{
var data = _dataRepository.Find(id);
if (data != null)
{
if (data.A == null)
{
data.A = fieldName;
_dataRepository.InsertOrUpdate(data);
return "A";
}
if (data.B == null)
{
data.B = fieldName;
_dataRepository.InsertOrUpdate(data);
return "B";
}
// keep going data.C through data.Z doing the exact same code
}
}
Obviously having 26 if statements just to determine if a property is null and then to update that property and do a database call is
probably very naive in implementation. What would be a better way of doing this unit of work?
Thankfully C# is able to inspect and assign class members dynamically, so one option would be to create a map list and iterate over that.
public string DataField(int id, string fieldName)
{
var data = _dataRepository.Find(id);
List<string> props = new List<string>();
props.Add("A");
props.Add("B");
props.Add("C");
if (data != null)
{
Type t = typeof(data).GetType();
foreach (String entry in props) {
PropertyInfo pi = t.GetProperty(entry);
if (pi.GetValue(data) == null) {
pi.SetValue(data, fieldName);
_dataRepository.InsertOrUpdate(data);
return entry;
}
}
}
}
You could just loop through all the character from 'A' to 'Z'. It gets difficult because you want to access an attribute of your 'data' object with the corresponding name, but that should (as far as I know) be possible through the C# reflection functionality.
While you get rid of the consecutive if-statements this still won't make your code nice :P
there is a fancy linq solution for your problem using reflection:
but as it was said before: your datastructure is not very well thought through
public String DataField(int id, string fieldName)
{
var data = new { Z = "test", B="asd"};
Type p = data.GetType();
var value = (from System.Reflection.PropertyInfo fi
in p.GetProperties().OrderBy((fi) => fi.Name)
where fi.Name.Length == 1 && fi.GetValue(data, null) != null
select fi.Name).FirstOrDefault();
return value;
}
ta taaaaaaaaa
like that you get the property but the update is not yet done.
var data = _dataRepository.Find(id);
If possible, you should use another DataType without those 26 properties. That new DataType should have 1 property and the Find method should return an instance of that new DataType; then, you could get rid of the 26 if in a more natural way.
To return "A", "B" ... "Z", you could use this:
return (char)65; //In this example this si an "A"
And work with some transformation from data.Value to a number between 65 and 90 (A to Z).
Since you always set the lowest alphabet field first and return, you can use an additional field in your class that tracks the first available field. For example, this can be an integer lowest_alphabet_unset and you'd update it whenever you set data.{X}:
Init:
lowest_alphabet_unset = 0;
In DataField:
lowest_alphabet_unset ++;
switch (lowest_alphabet_unset) {
case 1:
/* A is free */
/* do something */
return 'A';
[...]
case 7:
/* A through F taken */
data.G = fieldName;
_dataRepository.InsertOrUpdate(data);
return 'G';
[...]
}
N.B. -- do not use, if data is object rather that structure.
what comes to my mind is that, if A-Z are all same type, then you could theoretically access memory directly to check for non null values.
start = &data;
for (i = 0; i < 26; i++){
if ((typeof_elem) *(start + sizeof(elem)*i) != null){
*(start + sizeof(elem)*i) = fieldName;
return (char) (65 + i);
}
}
not tested but to give an idea ;)
Before someone shouts out the answer, please read the question through.
What is the purpose of the method in .NET 4.0's ExpressionVisitor:
public static ReadOnlyCollection<T> Visit<T>(ReadOnlyCollection<T> nodes, Func<T, T> elementVisitor)
My first guess as to the purpose of this method was that it would visit each node in each tree specified by the nodes parameter and rewrite the tree using the result of the elementVisitor function.
This does not appear to be the case. Actually this method appears to do a little more than nothing, unless I'm missing something here, which I strongly suspect I am...
I tried to use this method in my code and when things didn't work out as expected, I reflectored the method and found:
public static ReadOnlyCollection<T> Visit<T>(ReadOnlyCollection<T> nodes, Func<T, T> elementVisitor)
{
T[] list = null;
int index = 0;
int count = nodes.Count;
while (index < count)
{
T objA = elementVisitor(nodes[index]);
if (list != null)
{
list[index] = objA;
}
else if (!object.ReferenceEquals(objA, nodes[index]))
{
list = new T[count];
for (int i = 0; i < index; i++)
{
list[i] = nodes[i];
}
list[index] = objA;
}
index++;
}
if (list == null)
{
return nodes;
}
return new TrueReadOnlyCollection<T>(list);
}
So where would someone actually go about using this method? What am I missing here?
Thanks.
It looks to me like a convenience method to apply an aribitrary transform function to an expression tree, and return the resulting transformed tree, or the original tree if there is no change.
I can't see how this is any different of a pattern that a standard expression visitor, other than except for using a visitor type, it uses a function.
As for usage:
Expression<Func<int, int, int>> addLambdaExpression= (a, b) => a + b;
// Change add to subtract
Func<Expression, Expression> changeToSubtract = e =>
{
if (e is BinaryExpression)
{
return Expression.Subtract((e as BinaryExpression).Left,
(e as BinaryExpression).Right);
}
else
{
return e;
}
};
var nodes = new Expression[] { addLambdaExpression.Body }.ToList().AsReadOnly();
var subtractExpression = ExpressionVisitor.Visit(nodes, changeToSubtract);
You don't explain how you expected it to behave and why therefore you think it does little more than nothing.