This question is unlikely to help any future visitors; it is only relevant to a small geographic area, a specific moment in time, or an extraordinarily narrow situation that is not generally applicable to the worldwide audience of the internet. For help making this question more broadly applicable, visit the help center.
Closed 10 years ago.
How would i write this with linq?
foreach (var to in allCurrentTradeObjects)
{
foreach (var ro in theseWantMe)
{
if (ro.Type != to.Type
|| ro.MaxRent < to.Rent
|| ro.MinRooms > to.Rooms
|| ro.MinSquareMeters > to.SquareMeters
|| ro.MaxPrice < to.Price
|| ro.MinFloors > to.Floors
|| ro.TradeObjectId == to.TradeObjectId
|| ro.TradeObjectId == myTradeObject.TradeObjectId)
{
continue;
}
RatingListTriangleModel rlt = new RatingListTriangleModel
{
To1Id = myTradeObject.TradeObjectId,
To2Id = to.TradeObjectId,
To3Id = ro.TradeObjectId,
T1OnT2Rating = 0,
T2OnT3Rating = 0,
T3OnT1Rating = 0,
TotalRating = 0
};
//_context.RatingListTriangle.Add(rlt);
this.InsertOrUpdate(rlt);
}
}
this.Save();
var query = from to in allCurrentTradeObjects
from ro in theseWantMe
where ro.Type == to.Type &&
ro.MaxRent >= to.Rent &&
ro.MinRooms <= to.Rooms &&
ro.MinSquareMeters <= to.SquareMeters &&
ro.MaxPrice >= to.Price &&
ro.MinFloors <= to.Floors &&
ro.TradeObjectId != to.TradeObjectId &&
ro.TradeObjectId != myTradeObject.TradeObjectId
select new RatingListTriangleModel
{
To1Id = myTradeObject.TradeObjectId,
To2Id = to.TradeObjectId,
To3Id = ro.TradeObjectId,
T1OnT2Rating = 0,
T2OnT3Rating = 0,
T3OnT1Rating = 0,
TotalRating = 0
};
foreach(var rlt in query)
this.InsertOrUpdate(rlt);
this.Save();
Start by converting the skeleton of the nested loops to LINQ:
var rtls = allCurrentTradeObjects
.SelectMany(to => theseWantMe.Select(ro => new {to, ro}));
This gives you a list of pairs {to, ro}. Now add filtering by inverting the continue condition:
var rtls = allCurrentTradeObjects
.SelectMany(to => theseWantMe.Select(ro => new {to, ro}));
.Where(p => p.ro.Type == p.to.Typpe && p.ro.MaxRent >= p.to.Rent && ...)
Finally, add a Select to call `new:
var rtls = allCurrentTradeObjects
.SelectMany(to => theseWantMe.Select(ro => new {to, ro}));
.Where(p => p.ro.Type == p.to.Typpe && p.ro.MaxRent >= p.to.Rent && ...)
.Select(p => new RatingListTriangleModel {
To1Id = myTradeObject.TradeObjectId,
To2Id = p.to.TradeObjectId,
To3Id = p.ro.TradeObjectId,
...
});
With rtls list in hand, you can call InsertOrUpdate in a loop.
Following is the method syntax.
allCurrentTradeObjects.Select (
to => to.theseWantMe.Where ( ro => !(ro.Type != to.Type
|| ro.MaxRent < to.Rent
|| ro.MinRooms > to.Rooms
|| ro.MinSquareMeters > to.SquareMeters
|| ro.MaxPrice < to.Price
|| ro.MinFloors > to.Floors
|| ro.TradeObjectId == to.TradeObjectId
|| ro.TradeObjectId == myTradeObject.TradeObjectId))
.Select({
var rlt = new RatingListTriangleModel
{
To1Id = myTradeObject.TradeObjectId,
To2Id = to.TradeObjectId,
To3Id = ro.TradeObjectId,
T1OnT2Rating = 0,
T2OnT3Rating = 0,
T3OnT1Rating = 0,
TotalRating = 0
};
this.InsertOrUpdate(rlt);
return rlt;
} ).ToArray();
this.Save();
There are many answers here advocating SelectMany (or double from). These are "optimize for readability" answers in that they do not change the N*M nested loop performance of this operation.
You shouldn't use that approach if both collections are large. Instead, you should take advantage of the well defined relationship between your two collections, and the hashing in Enumerable.Join to reduce the operation to N+M.
var myTradeObject = GetThatOneObject();
IEnumerable<RatingListTriangleModel> query =
from to in allCurrentTradeObjects
//pre-emptively filter to the interesting objects in the first collection
where to.TradeObjectId == myTradeObject.TradeObjectId
//take advantage of hashing in Enumerable.Join - theseWantMe is enumerated once
join ro in theseWantMe
on to.Type equals ro.Type
//remaining matching criteria
where to.Rent <= ro.MaxRent //rent is lower than max
&& ro.MinRooms <= to.Rooms //rooms are higher than min
&& ro.MinSquareMeters <= to.SquareMeters //area is higher than min
&& to.Price <= ro.MaxPrice //price is lower than max
&& ro.MinFloors <= to.Floors // floors are higher than min
&& to.TradeObjectId != ro.TradeObjectId //not same trade object
select CreateRatingListTriangleModel(myTradeObject, to, ro);
foreach(RatingListTriangleModel row in query)
{
this.InsertOrUpdate(row);
}
this.Save();
To increase readability I would start by refactoring the complicated condition and move it to a neat little function (It can also be a method of the object)
private bool IsMatchingTradeObject (TradeObject to, SomeOtherObject ro, int TradeObjectId)
{
return ro.Type == to.Type &&
ro.MaxRent >= to.Rent &&
ro.MinRooms <= to.Rooms &&
ro.MinSquareMeters <= to.SquareMeters &&
ro.MaxPrice >= to.Price &&
ro.MinFloors <= to.Floors &&
ro.TradeObjectId != to.TradeObjectId &&
ro.TradeObjectId != TradeObjectId;
}
Second I would do the same with the creation and initialization of the RatingListTriangleModel, i.e. move it to a small method and give it a meaningful name.
private RatingListTriangleModel CreateModel(TradeObject to, SomeOtherObject ro, int TradeObjectId)
{
return new RatingListTriangleModel
{
To1Id = myTradeObject.TradeObjectId,
To2Id = to.TradeObjectId,
To3Id = ro.TradeObjectId,
T1OnT2Rating = 0,
T2OnT3Rating = 0,
T3OnT1Rating = 0,
TotalRating = 0
};
The remaining code is much easier to read
foreach (var to in allCurrentTradeObjects)
foreach (var ro in theseWantMe)
if (IsMatchingTradeObject(to, ro, myTradeObject.TradeObjectId))
this.InsertOrUpdate(CreateModel(to, ro, myTradeObject.TradeObjectId));
this.Save();
Converting this to LINQ is easy:
allCurrentTradeObjects.Select (
to => to.Where (
ro => IsMatchingTradeObject (to, ro, myTradeObject.TradeObjectId)
)
).Select(
{
this.InsertOrUpdate(CreateModel(to, ro, myTradeObject.TradeObjectId));
return null;
}
);
this.Save();
However, the foreach-loops seem easier to read.
Related
Code
if(Model.CurrentStatus == 1 || Model.CurrentStatus == 2)
{
//can display those records..
}
else if((Model.CurrentStatus == 3 || Model.CurrentStatus == 4) && Model.Date != null)
{
if(Model.Date <= 30 days)
{
//can display those records..
}
}
I have tried the following code and unable to complete it fully as expected
#Html.Partial("Filter", new IndexModel()
{
Id = Model.Id,
Collection = Model.Collection.Where((a => a.CurrentStatus == 1 || a.CurrentStatus == 2)
&& )
})
How to convert the above if condition to linq in cshtml. Thanks
the else-if relationship is an OR relationship. So simply combine the two lines. the inner nested if inside the else if is an AND relationship. This would go into the second set of parentheses
Collection = Model.Collection.Where
(
(a => a.CurrentStatus == 1 || a.CurrentStatus == 2) ||
((a.CurrentStatus == 3 || a.CurrentStatus == 4) && a.Date != null && a.Date <= 30)
)
EDIT:
Here is another suggestion: extract the readable code into an own method that evaluates the condition and returns the boolean result. This way you can make a predicate that can be accepted by the Where method:
private bool IsForDisplay( ModelDataType Model )
{
if(Model.CurrentStatus == 1 || Model.CurrentStatus == 2)
{
//can display those records..
return true;
}
else if((Model.CurrentStatus == 3 || Model.CurrentStatus == 4) && Model.Date != null)
{
if(Model.Date <= 30 days)
{
//can display those records..
return true;
}
}
return false;
}
now you can use it simply in the linq expression:
#Html.Partial("Filter", new IndexModel()
{
Id = Model.Id,
Collection = Model.Collection.Where(a => IsForDisplay(a))
});
I have a method in a thread that pulls user images, and tie the images to an ItemCollection list. while the images are being pulled, I want to be able to search through the list. I keep getting this error, Collection was modified; enumeration operation may not execute. Here is the image pulling code:
Thread reprintAppsThread = new Thread(() =>
{
var items = assignmentPage.reprintItemListView.Items;
foreach (EcofOApplicationObject obj in items)
{
byte[] userPassport;
bool fetched = userPassports.TryGetValue(obj.TrackCode, out userPassport);
if (!fetched && !obj.fetchingThumbnail) /*&& (obj.userPassportBytes == null ||
obj.userPassportBytes.Length == 0))*/
{
while (thumbnailThreadCount >= 20)
{
Thread.Sleep(2000);
}
thumbnailThreadCount++;
Thread newT = new Thread(() => { fetchThumbnailsAsync(obj); });
newT.Start();
}
else
{
m_log.DebugFormat("Matching {0} to its passport", obj.TrackCode);
obj.userPassportBytes = userPassport;
}
}
});
newAppsThread.SetApartmentState(ApartmentState.STA);
newAppsThread.Start();
reprintAppsThread.Start();
}
Here is the search code:
private void ShowSearchList()
{
searchButton.IsEnabled = false;
searchTextBox.IsEnabled = false;
string searchTerm = searchTextBox.Text;
string searchConstraint = ((ComboBoxItem)searchComboBox.SelectedItem).Name;
IEnumerable<EcofOApplicationObject> searchList;
List<EcofOApplicationObject> currentList;
ListView currentListView;
TabItem currentTab = (TabItem)TabControl.SelectedItem;
//bool isReprint = false;
if (DefaultTab.Equals(currentTab))
{
currentList = m_AssignmentList;
currentListView = itemListView;
}
else
{
currentList = m_ReprintList;
currentListView = reprintItemListView;
}
switch (searchConstraint)
{
case "holderNameAddress":
searchList = currentList.Where(
appli => ((appli.application.Holder.City != null && appli.application.Holder.City.IndexOf(
searchTerm, StringComparison.OrdinalIgnoreCase) >= 0) ||
(appli.application.Holder.ContactAddress != null && appli.application.Holder.ContactAddress.IndexOf(
searchTerm, StringComparison.OrdinalIgnoreCase) >= 0) ||
(appli.application.Holder.ContactAddressLga != null && appli.application.Holder.ContactAddressLga.IndexOf(
searchTerm, StringComparison.OrdinalIgnoreCase) >= 0) ||
(appli.application.Holder.ContactAddressState != null &&
appli.application.Holder.ContactAddressState.IndexOf(
searchTerm, StringComparison.OrdinalIgnoreCase) >= 0)));
break;
case "propertyAddress":
searchList = currentList.Where(
appli => ((appli.application.PropertyLga != null && appli.application.PropertyLga.IndexOf(
searchTerm, StringComparison.OrdinalIgnoreCase) >= 0) ||
(appli.application.PropertyLocation != null && appli.application.PropertyLocation.IndexOf(
searchTerm, StringComparison.OrdinalIgnoreCase) >= 0) ||
(appli.application.PropertyLocationDescription != null && appli.application.PropertyLocationDescription.IndexOf(
searchTerm, StringComparison.OrdinalIgnoreCase) >= 0)));
break;
case "propertyUse":
searchList = currentList.Where(
appli => (appli.ApprovedTypeOfUse != null &&
appli.ApprovedTypeOfUse.IndexOf(searchTerm, StringComparison.OrdinalIgnoreCase) >= 0));
break;
case "trackCode":
// This cannot be null. We check all the same
searchList = currentList.Where(
appli => (appli.TrackCode != null &&
appli.application.TrackCode.IndexOf(searchTerm, StringComparison.OrdinalIgnoreCase) >= 0));
break;
case "scheme":
searchList = currentList.Where(
appli => (appli.Scheme != null &&
appli.Scheme.IndexOf(searchTerm, StringComparison.OrdinalIgnoreCase) >= 0));
break;
case "surveyPlanNum":
searchList = currentList.Where(
appli => (appli.application.SurveyPlanNo != null &&
appli.application.SurveyPlanNo.IndexOf(searchTerm, StringComparison.OrdinalIgnoreCase) >= 0));
break;
case "coordinateOne":
searchList = currentList.Where(
appli => (appli.application.PropertyCordinate1 != null &&
appli.application.PropertyCordinate1.IndexOf(searchTerm, StringComparison.OrdinalIgnoreCase) >= 0));
break;
case "coordinateTwo":
searchList = currentList.Where(
appli => (appli.application.PropertyCordinate2 != null &&
appli.application.PropertyCordinate2.IndexOf(searchTerm, StringComparison.OrdinalIgnoreCase) >= 0));
break;
case "holderName":
default:
searchList = currentList.Where(
appli => (appli.application.Holdernames != null &&
appli.application.Holdernames.IndexOf(searchTerm, StringComparison.OrdinalIgnoreCase) >= 0));
break;
}
currentListView.Items.Clear();
foreach (EcofOApplicationObject app in searchList)
{
currentListView.Items.Add(app);
}
refreshDisplay();
searchButton.IsEnabled = true;
searchTextBox.IsEnabled = true;
}
I have read other suggestions about this same issue, but none seems to work for me. How do I solve this issue?
You can create a copy of the items like this:
var itemsCopy = assignmentPage.reprintItemListView.Items.Cast<object>().ToArray();
It is still not safe though to create this copy in a different thread than the UI thread. You may still get some rare Collection was modified... exceptions. To make it 100% safe you must create the copy while still running in the UI thread. To pass the copy in the newAppsThread you could use a ParameterizedThreadStart:
var reprintAppsThread = new Thread(itemsCopy =>
//...
reprintAppsThread.Start(
assignmentPage.reprintItemListView.Items.Cast<object>().ToArray());
I want to make my code short and simple using linq.
I have a list that contains leaveDates and every leaveDates contain number of leavelist.
Something like this:
{ leaves_date = {07-05-2018 18:30:00}, LeaveList = {System.Collections.Generic.List<TimeClock.Model.LeaveManagementModel>} }
{ leaves_date = {08-05-2018 18:30:00}, LeaveList = {System.Collections.Generic.List<TimeClock.Model.LeaveManagementModel>} }
{ leaves_date = {21-05-2018 18:30:00}, LeaveList = {System.Collections.Generic.List<TimeClock.Model.LeaveManagementModel>} }
leaveList contains UserId, LeaveType, Status fields
Now all I want is to count the number of leavedates per user who's status is 1 and leave type != 3
I have already tried using a for loop, but I want to do it with linq.
Here is my code with the for loop:
for (var i = 0; i < leavesresult.Count; i++) {
for (var a = 0; a < leavesresult[i].LeaveList.Count; a++) {
if (leavesresult[i].LeaveList[a].status == 1.ToString() && leavesresult[i].LeaveList[a].leave_type != 3.ToString()) {
var compair1 = leavesresult[i].LeaveList[a].user_id;
var compair2 = attendancelist.Any(z = >z.user_id == leavesresult[i].LeaveList[a].user_id);
if (attendancelist.Any(z = >z.user_id == leavesresult[i].LeaveList[a].user_id)) {
int index = attendancelist.FindIndex(y = >y.user_id == leavesresult[i].LeaveList[a].user_id);
if (leavesresult[i].LeaveList[a].check_halfday == 1) {
attendancelist[index].days = attendancelist[index].days
}
else {
attendancelist[index].days = attendancelist[index].days + 1;
}
}
else {
if (leavesresult[i].LeaveList[a].check_halfday == 1) {
attendancelist.Add(new AttendanceModel {
user_id = leavesresult[i].LeaveList[a].user_id,
days = 0.5
});
}
else {
attendancelist.Add(new AttendanceModel {
user_id = leavesresult[i].LeaveList[a].user_id,
days = 1
});
}
}
}
}
}
I could give you the query and you would learn nothing. Instead learn how to do this transformation yourself. The trick is to not try to do it all at once. Rather, we make a series of small, obviously correct transformations each one of which gets us closer to our goal.
Start by rewriting the inner for loop as a foreach:
for (var i = 0; i < leavesresult.Count; i++)
{
foreach (var leavelist in leavesresult[i].LeaveList)
{
if (leavelist.status == 1.ToString() && leavelist.leave_type != 3.ToString())
{
var compair1 = leavelist.user_id;
var compair2 = attendancelist.Any(z => z.user_id == leavelist.user_id);
if (attendancelist.Any(z => z.user_id == leavelist.user_id))
{
int index = attendancelist.FindIndex(y => y.user_id == leavelist.user_id);
if (leavelist.check_halfday == 1)
attendancelist[index].days = attendancelist[index].days
else
attendancelist[index].days = attendancelist[index].days + 1;
}
else
{
if (leavelist.check_halfday == 1)
attendancelist.Add(
new AttendanceModel {user_id = leavelist.user_id, days = 0.5});
else
attendancelist.Add(
new AttendanceModel {user_id = leavelist.user_id, days = 1});
}
}
}
}
Already your code is about 100 times easier to read with that change.
Now we notice a few things:
if (leavelist.status == 1.ToString() && leavelist.leave_type != 3.ToString())
That is a crazy way to write this check. Rewrite it into a sensible check.
var compair1 = leavelist.user_id;
var compair2 = attendancelist.Any(z => z.user_id == leavelist.user_id);
Neither of these variables are ever read, and their initializers are useless. Delete the second one. Rename the first one to user_id.
if (leavelist.check_halfday == 1)
attendancelist[index].days = attendancelist[index].days
else
attendancelist[index].days = attendancelist[index].days + 1;
The consequence makes no sense. Rewrite this.
OK, we now have
for (var i = 0; i < leavesresult.Count; i++)
{
foreach (var leavelist in leavesresult[i].LeaveList)
{
if (leavelist.status == "1" && leavelist.leave_type != "3")
{
var user_id= leavelist.user_id;
if (attendancelist.Any(z => z.user_id == leavelist.user_id))
{
int index = attendancelist.FindIndex(y => y.user_id == leavelist.user_id);
if (leavelist.check_halfday != 1)
attendancelist[index].days = attendancelist[index].days + 1;
}
else
{
if (leavelist.check_halfday == 1)
attendancelist.Add(
new AttendanceModel {user_id = leavelist.user_id, days = 0.5});
else
attendancelist.Add(
new AttendanceModel {user_id = leavelist.user_id, days = 1});
}
}
}
}
Use the helper variable throughout:
for (var i = 0; i < leavesresult.Count; i++)
{
foreach (var leavelist in leavesresult[i].LeaveList)
{
if (leavelist.status == "1" && leavelist.leave_type != "3")
{
var user_id = leavelist.user_id;
if (attendancelist.Any(z => z.user_id == user_id))
{
int index = attendancelist.FindIndex(y => y.user_id == user_id);
if (leavelist.check_halfday != 1)
attendancelist[index].days = attendancelist[index].days + 1;
}
else
{
if (leavelist.check_halfday == 1)
attendancelist.Add(
new AttendanceModel {user_id = user_id, days = 0.5});
else
attendancelist.Add(
new AttendanceModel {user_id = user_id, days = 1});
}
}
}
}
We realize that the Any and the FindIndex are doing the same thing. Eliminate one of them:
for (var i = 0; i < leavesresult.Count; i++)
{
foreach (var leavelist in leavesresult[i].LeaveList)
{
if (leavelist.status == "1" && leavelist.leave_type != "3")
{
var user_id = leavelist.user_id;
int index = attendancelist.FindIndex(y => y.user_id == user_id);
if (index != -1)
{
if (leavelist.check_halfday != 1)
attendancelist[index].days = attendancelist[index].days + 1;
}
else
{
if (leavelist.check_halfday == 1)
attendancelist.Add(
new AttendanceModel {user_id = user_id, days = 0.5});
else
attendancelist.Add(
new AttendanceModel {user_id = user_id, days = 1});
}
}
}
}
We notice that we are duplicating code in the final if-else. The only difference is days:
for (var i = 0; i < leavesresult.Count; i++)
{
foreach (var leavelist in leavesresult[i].LeaveList)
{
if (leavelist.status == "1" && leavelist.leave_type != "3")
{
var user_id = leavelist.user_id;
int index = attendancelist.FindIndex(y => y.user_id == user_id);
if (index != -1)
{
if (leavelist.check_halfday != 1)
attendancelist[index].days = attendancelist[index].days + 1;
}
else
{
double days = leavelist.check_halfday == 1 ? 0.5 : 1;
attendancelist.Add(new AttendanceModel {user_id = user_id, days = days});
}
}
}
}
Now your code is 1000x easier to read than it was before. Keep going! Rewrite the outer loop as a foreach:
foreach (var lr in leavesresult)
{
foreach (var leavelist in lr.LeaveList)
{
if (leavelist.status == "1" && leavelist.leave_type != "3")
{
var user_id = leavelist.user_id;
int index = attendancelist.FindIndex(y => y.user_id == user_id);
if (index != -1)
{
if (leavelist.check_halfday != 1)
attendancelist[index].days = attendancelist[index].days + 1;
}
else
{
double days = leavelist.check_halfday == 1 ? 0.5 : 1;
attendancelist.Add(new AttendanceModel {user_id = user_id, days = days});
}
}
}
}
And we notice a couple more things: we can put check_halfday into an explanatory variable, and eliminate days. And we can simplify the increment:
foreach (var lr in leavesresult)
{
foreach (var leavelist in lr.LeaveList)
{
if (leavelist.status == "1" && leavelist.leave_type != "3")
{
var user_id = leavelist.user_id;
int index = attendancelist.FindIndex(y => y.user_id == user_id);
bool halfday= leavelist.check_halfday == 1;
if (index != -1)
{
if (!halfday)
attendancelist[index].days += 1;
}
else
{
attendancelist.Add(new AttendanceModel {user_id = user_id, days = halfday ? 0.5 : 1});
}
}
}
}
Now we begin transforming this to a query. The key thing to understand is that mutations must not go in queries. Mutations only go into loops, never queries. Queries ask questions, they do not perform mutations.
You have a mutation of attendancelist, so that's got to stay in a loop. But we can move all the query logic out of the loop by recognizing that the nested foreach with a test inside the inner loop is equivalent to:
var query = from lr in leaveresult
from ll in lr.LeaveList
where ll.status == "1"
where ll.leave_type != "3"
select ll;
Excellent. Now we can use that in our foreach:
foreach(var ll in query)
{
var index = attendancelist.FindIndex(y => y.user_id == ll.user_id);
var halfday = ll.check_halfday == 1;
if (index != -1)
{
if (!halfday)
attendancelist[index].days += 1;
}
else
{
attendancelist.Add(
new AttendanceModel {user_id = ll.user_id, days = halfday? 0.5 : 1 });
}
}
Now that we have the loop in this extremely simple form, we notice that we can re-order the if to simplify it:
foreach(var ll in query)
{
var index = attendancelist.FindIndex(y => y.user_id == ll.user_id);
var halfday = ll.check_halfday == 1;
if (index == -1)
attendancelist.Add(
new AttendanceModel {user_id = ll.user_id, days = halfday? 0.5 : 1 });
else if (!halfday)
attendancelist[index].days += 1;
}
And we're done. All the computation is done by the query, all the mutations are done by the foreach, as it should be. And your loop body is now a single, extremely clear conditional statement.
This answer is to answer your question, which was how to convert an existing bunch of hard-to-read loops into an easy-to-read query. But it would be better still to write a query that clearly expressed the business logic you're trying to implement, and I don't know what that is. Create your LINQ queries so that they make it easy to understand what is happening at the business level.
In this case what I suspect you are doing is maintaining a per-user count of days, to be updated based on the leave lists. So let's write that!
// dict[user_id] is the accumulated leave.
var dict = new Dictionary<int, double>();
var query = from lr in leaveresult
from ll in lr.LeaveList
where ll.status == "1"
where ll.leave_type != "3"
select ll;
foreach(var ll in query)
{
var halfday = ll.check_halfday == 1;
if (!dict.ContainsKey(ll.user_id))
dict[ll.user_id] = halfday? 0.5 : 1;
else if (!halfday)
dict[ll.user_id] = dict[ll.user_id] + 1;
}
That seems like a nicer way to represent this than a list that you are constantly having to search.
Once we are at this point we can then recognize that what you are really doing is computing a per-user sum! The answer by JamieC shows that you can use the Aggregate helper method to compute a per-user sum.
But again, this is based on the assumption that you have built this whole mechanism to compute that sum. Again: design your code so that it clearly implements the business process in the jargon of that process. If what you're doing is computing that sum, boy, does that ever not show up in your original code. Strive to make it clearer what your code is doing.
This is basically 1 line of linq with a groupby, I'm not sure ill get it spot on with 1 try, but something along the lines of:
var attendancelist = leavesresult
.SelectMany(a => a.LeaveList) // flatten the list
.Where(a => a.status == "1" && a.type != "3") // pick the right items
.GroupBy(a => a.user_id) // group by users
.Select(g => new AttendanceModel(){ // project the model
user_id = g.Key,
days = g.Aggregate(0, (a,b) => a + (b.check_halfday == 1 ? 0.5 : 1))
})
.ToList();
Let me know any issues, and i'll try to fix as necessary.
edit1: Assuming AttendanceModel.days is an int you need to decide what to do as it is calculating a float.
Perhaps something like:
...
days = (int)Math.Ceiling(g.Aggregate(0, (a,b) => a + (b.check_halfday == 1 ? 0.5 : 1)))
...
Not a linq version but used foreach to simplify and make it more readable
var userLeaves = new Dictionary<int, double>();
foreach( var lr in leavesresult)
{
foreach (var leave in lr.LeaveList)
{
if (leave.Status == "1" && leave.LeaveType != "3")
{
var leaveDay = leave.check_halfday ==1 ? 0.5 : 1;
if (userLeaves.ContainsKey(leave.UserID))
userLeaves[leave.UserID] = userLeaves[leave.UserID] + leaveDay;
else
userLeaves.Add(leave.UserID, leaveDay);
}
}
}
I have following code in c# in which I am searching for lowest price flight .Now I want to convert it to Linq
for (; count < _flightSearchController.ListOfContracts.Count; count++)
{
contract = (DTContract)_flightSearchController.ListOfContracts[count];
if (contract.CurrentStatus == AvailabilityStatus.AVAILABLE)
{
if (CheckContractCitiesWithSearchCriteria(contract, originAirports, destinationAirports))
{
//if fare is lower than selected contract.
if (lowestPriceContract == null || lowestPriceContract.FareDetails.PriceForDefaultFlightSelection > contract.FareDetails.PriceForDefaultFlightSelection)
{
lowestPriceContract = contract;
}
else if (lowestPriceContract.FareDetails.PriceForDefaultFlightSelection == contract.FareDetails.PriceForDefaultFlightSelection)
{
if (lowestPriceContract.FareDetails.PriceAdult > 0 && (lowestPriceContract.FareDetails.PriceAdult + lowestPriceContract.FareDetails.FareTaxAdult) > (contract.FareDetails.PriceAdult + contract.FareDetails.FareTaxAdult))
{
lowestPriceContract = contract;
}
else if (lowestPriceContract.FareDetails.PriceSenior > 0 && (lowestPriceContract.FareDetails.PriceSenior + lowestPriceContract.FareDetails.FareTaxSenior) > (contract.FareDetails.PriceSenior + contract.FareDetails.FareTaxSenior))
{
lowestPriceContract = contract;
}
}
}
}
I tried it to convert but stuck in if else if section.
var q = _flightSearchController.ListOfContracts.ToList<DTContract>()
.Where(cont => cont.CurrentStatus == AvailabilityStatus.AVAILABLE);
if (lowestPriceContract == null || lowestPriceContract.FareDetails.PriceForDefaultFlightSelection > contract.FareDetails.PriceForDefaultFlightSelection)
{
}
Use the Min extension method:
var q = _flightSearchController.ListOfContracts
.Where(cont => cont.CurrentStatus == AvailabilityStatus.AVAILABLE
&& CheckContractCitiesWithSearchCriteria(cont, originAirports, destinationAirports))
.Min(cont=> cont.FareDetails.PriceForDefaultFlightSelection)
Edit I had glossed over the tie-breaker part, which makes it a bit more complicated. You can do it with sorting, but this will be slower when there are a lot of contracts:
var q = _flightSearchController.ListOfContracts
.Where(cont => cont.CurrentStatus == AvailabilityStatus.AVAILABLE)
&& CheckContractCitiesWithSearchCriteria(cont, originAirports, destinationAirports))
.OrderBy(cont => FareDetails.PriceForDefaultFlightSelection)
.ThenBy(cont => cont.FareDetails.PriceAdult + lowestPriceContract.FareDetails.FareTaxAdult)
.ThenBy(cont => cont.FareDetails.PriceSenior + lowestPriceContract.FareDetails.FareTaxSenior)
.First();
You could implement the IComparable interface for the FareDetails object to compare the prices, which would allow you to do this:
var q = _flightSearchController.ListOfContracts
.Where(cont => cont.CurrentStatus == AvailabilityStatus.AVAILABLE
&& CheckContractCitiesWithSearchCriteria(cont, originAirports, destinationAirports))
.Min(cont=> cont.FareDetails)
I have a collection of records. Which have two boxers, match date, location etc...
I want to separate them by months and group them together. Currently I have what is below. And it works to a degree. That looks for matchdates in the future. that is this year and steps through each month (1-12) and finds any matches in that date range.
Placing it into a nice dictionary of int, enumerable where int is the month and enumberable is the collection of matches in that month
//Build the matches list by Months!!!
var summarysDic = new Dictionary<int, IEnumerable<MatchSummary>>();
for (int i = 1; i <= 12; i++)
{
var MatchesOfMonth = matches.Where(x => x.MatchDate.Value.Year == DateTime.Now.Year &&
x.MatchDate.Value.Month == i &&
!x.HasResult() &&
x.MatchDate.Value > DateTime.Now);
if (MatchesOfMonth.Count() > 0)
{
summarysDic.Add(i, MatchesOfMonth.OrderBy(x => x.MatchDate).Select(x=> new MatchSummary(x)).ToArray());
}
}
Problem is this currently only deals with this year. I would like to instead make it so it works for "the next 6 months" but this would of course have to work over the new year as well!
Whats the best/cleanest way to go about doing this?
thanks in advance!
P.S on a side note i have yet to find how to simply do DateTime.Now.Month.add(1) for example (as i will always be going from current date forwards!)
-----COMPLETED CODE!-----
//Build the matches list by Months!!!
var summarysDic = new Dictionary<string, IEnumerable<MatchSummary>>();
for (int i = 1; i <= 12; i++)
{
var checkDate = DateTime.Now.AddMonths(i);
var MatchesOfMonth = matches.Where(x => x.MatchDate.Value.Month == checkDate.Month &&
x.MatchDate.Value.Year == checkDate.Year &&
!x.HasResult() &&
x.MatchDate.Value > DateTime.Now);
if (MatchesOfMonth.Count() > 0)
{
var firstMatchDate = MatchesOfMonth.First().MatchDate.Value;
if (firstMatchDate.Year != DateTime.Now.Year)
{
summarysDic.Add(firstMatchDate.ToString("MMMM yyyy"), MatchesOfMonth.OrderBy(x => x.MatchDate).Select(x => new MatchSummary(x)).ToArray());
}
else
{
summarysDic.Add(firstMatchDate.ToString("MMMM"), MatchesOfMonth.OrderBy(x => x.MatchDate).Select(x => new MatchSummary(x)).ToArray());
}
}
}
I believe you can get what you want without modifying your algorithm significantly:
//Build the matches list by Months!!!
var summarysDic = new Dictionary<int, IEnumerable<MatchSummary>>();
for (int i = 0; i <= 6; i++)
{
var checkDate = DateTime.Now.AddMonths(i);
var MatchesOfMonth = matches.Where(x => x.MatchDate.Value.Year == checkDate.Year &&
x.MatchDate.Value.Month == checkDate.Month &&
!x.HasResult() &&
x.MatchDate.Value > DateTime.Now);
if (MatchesOfMonth.Count() > 0)
{
summarysDic.Add(i, MatchesOfMonth.OrderBy(x => x.MatchDate).Select(x=> new MatchSummary(x)).ToArray());
}
}
What's wrong with DateTime.Now.AddMonth(1)?
var MatchesOfMonth = matches.Where(x => x.MatchDate.Value <= DateTime.Now.AddMonth(i)
&& !x.HasResult()
&& x.MatchDate.Value > DateTime.Now);
I haven't compiled that, but it should run with only fairly minor tweeking...