I have some data that I need to partition based on some condition, i.e.:
var trues = from item in items where MyCondition(item, blah) select item;
var falses = from item in items where !MyCondition(item, blah) select item;
Is there a cleaner way to do this in a single query and get both results back so that I don't have to repeat myself (and end up iterating over the data twice) like above?
If you don't want to iterate over the data twice, you will have to create a LINQ query that contains the true values and the false values with an indicator to which group they belong.
You can do this using a ToLookup:
var combined = items.ToLookup(x => MyCondition(x, blah));
var trues = combined[true];
var falses = combined[false];
Related
I have a linq query which seems to be reversing one column of several in some rows of an earlier query:
var dataSet = from fb in ds.Feedback_Answers
where fb.Feedback_Questions.Feedback_Questionnaires.QuestionnaireID == criteriaType
&& fb.UpdatedDate >= dateFeedbackFrom && fb.UpdatedDate <= dateFeedbackTo
select new
{
fb.Feedback_Questions.Feedback_Questionnaires.QuestionnaireID,
fb.QuestionID,
fb.Feedback_Questions.Text,
fb.Answer,
fb.UpdatedBy
};
Gets the first dataset and is confirmed working.
This is then grouped like this:
var groupedSet = from row in dataSet
group row by row.UpdatedBy
into grp
select new
{
Survey = grp.Key,
QuestionID = grp.Select(i => i.QuestionID),
Question = grp.Select(q => q.Text),
Answer = grp.Select(a => a.Answer)
};
While grouping, the resulting returnset (of type: string, list int, list string, list int) sometimes, but not always, turns the question order back to front, without inverting answer or questionID, which throws it off.
i.e. if the set is questionID 1,2,3 and question A,B,C it sometimes returns 1,2,3 and C,B,A
Can anyone advise why it may be doing this? Why only on the one column? Thanks!
edit: Got it thanks all! In case it helps anyone in future, here is the solution used:
var groupedSet = from row in dataSet
group row by row.UpdatedBy
into grp
select new
{
Survey = grp.Key,
QuestionID = grp.OrderBy(x=>x.QuestionID).Select(i => i.QuestionID),
Question = grp.OrderBy(x=>x.QuestionID).Select(q => q.Text),
Answer = grp.OrderBy(x=>x.QuestionID).Select(a => a.Answer)
};
Reversal of a grouped order is a coincidence: IQueryable<T>'s GroupBy returns groups in no particular order. Unlike in-memory GroupBy, which specifies the order of its groups, queries performed in RDBMS depend on implementation:
The query behavior that occurs as a result of executing an expression tree that represents calling GroupBy<TSource,TKey,TElement>(IQueryable<TSource>, Expression<Func<TSource,TKey>>, Expression<Func<TSource,TElement>>) depends on the implementation of the type of the source parameter.`
If you would like to have your rows in a specific order, you need to add OrderBy to your query to force it.
How I do it and maintain the relative list order, rather than apply an order to the resulting set?
One approach is to apply grouping to your data after bringing it into memory. Apply ToList() to dataSet at the end to bring data into memory. After that, the order of subsequent GrouBy query will be consistent with dataSet. A drawback is that the grouping is no longer done in RDBMS.
I have a 'complex' linq query I would like to improve and to understand.
(from x in tblOrder
orderby x.OrderNo
// where x.Filename is most recent filename for this order
group x by new { x.OrderNo, x.Color } into groupedByColorCode
select new
{
OrderNo = groupedByColorCode.Key.OrderNo,
ProductRef = groupedByColorCode.FirstOrDefault().ProductRef,
Color = groupedByColorCode.Key.Color,
Packing = groupedByColorCode.FirstOrDefault().Packing,
TotalQuantity = groupedByColorCode.Sum(bcc => bcc.OriQty).ToString()
}
x is an Order. I also would like to filter by Filename. Filename is a variable from tblOrder. Actually I would like to keep and keep only the orders from the most recent file.
What 'where' clause should I add to my linq query to be able to filter these last file name.
Thank you
First it's better to use orderby in the end of the query, because sorting will work quicker on the smaller set of data.
Second you should use where in the top of query, it will make smaller your set before grouping and sorting (set it after from line)
At last grouping creates dictionary with Key = new { x.OrderNo, x.Color } (in this keys) and Value = IEnumerable, and then groupedByColorCode becomes IEnumerabler of {Key, Value}. So it should stand in the end before orederby
there is MaxBy() or MinBy() if you need max or min by some criteria
I have Rows object that is IEnumerable<dynamic>, it has 5 properties (columns) and 100 rows. One of the properties/columns is Group, only 2 distinct groups out of 100 rows, so first I run a distinct against it:
IEnumerable<dynamic> Groups = Rows.Select(x => x.Group).Distinct();
This works, no error.
Then I want to go back to my Rows object and loop through them where this group = the group in Rows, like this:
foreach (string Group in Groups)
{
IEnumerable<dynamic> GroupData =
from rowdata in Rows
where rowdata.Group = #Group
select rowdata;
But I get this error on the last line:
'WebMatrix.Data.DynamicRecord' does not contain a definition for 'Group'
Anyone knows why this isn't working?
Surely I can do this another way, but I wanted to use c# select statement instead. How can I though?
Edit to show usage:
foreach (var row in GroupData){
string ThisGroup = row.Group
}
...
Instead of selecting twice, group on the Group value:
IEnumerable<IGrouping<string, dynamic>> groups = Rows.GroupBy(x => (string)x.Group);
Now you can just loop through the result:
foreach (IGrouping<string, dynamic> group in groups) {
...
}
The IGrouping<> object has a Key property which is the value that you grouped on, and it's also a collection of the values in the group.
I am having at hierarchical table with the structure
ID, Name, FK_ID, Sortkey
Fetching the data in LINQ to SQL is straight forward:
var list = from ls in db.myTable
where ls.FK_ID == levelId
orderby ls.sortkey ascending
select ls;
And I can traverse down the tree by linking to the next levelId.
But what I can't figure out, if there is a way in LINQ, to check if there is any children
I could probably build a view, that added a flag to each record, but I would rather do this in LINQ, if possible.
What would even be the best practice for adding such a flag in SQL?
My idea on checking each record, is not the most performance friendly solution.
If you have set up the foreign key correctly, should you not have the 1 to Many mapping properties?
i.e. You could write
var listWithChildren = list.Where(l => l.Children.Any());
or going the other direction
var listWithParent = list.Where(l => l.FK_ID != null);
or using the query expression instead of fluent
var listWithChildren = from item in list
where item.Children.Any()
select item;
as you asked in your comments for a boolean flag, you could do
var updatedList = from item in list
select new
{
Item = item,
HasChildren = item.Children.Any()
};
i have a query which gets records from the database,
i need to pass ids in parameters to call this function,
like Myfunction(1, 2, 3)
i want to get the results which matching with this ids,
like
public List<Items> GetItems(int[] ids)
{
var a = from Items in db.item
where items.id == ids[]
select new Items
{
}
return a.ToList();
}
there is confusion on where clause ( how to get records regarding provided its)
i tried this with looping the ids but could not get any success
Thanks in Advance
You may use Contains, method to check. Something similar to Select * from table where Ids in (1,2,3,...)
Try the following.
var a = from item in db.Items
where ids.Contains(item.id)
select new Item {.....}
Where ids is your array.
You may see: Creating IN Queries With Linq To Sql
change your code to the following
public List<Items> GetItems(int[] ids)
{
var a = from Items in db.item
where ids.Contains(Items.id)
select new Items
{
}
return a.ToList();
}