I have the following xml:
https://pastebin.pl/view/63af9294
I should find the name of the battle where the highest army fought.
(Yes, it's a school work, but i'm not getting any closer)
So far my code looks like:
var q10 = (from a in
(from x in xdoc.Descendants("size") select x)
join b in
(from y in xdoc.Descendants("battle") select y)
on a equals b.Element("attacker").Element("size")
select new
{
size = a.Value,
battle = b.Element("name")
});
I am trying to get the highest number first, than join every battle by the size and than use a
.Max(x => x.size) , but as you see i have no clue how to do it for 2 different nodes, or whatever called.
I mean i can join the attacker or the defender based on the size of an army but cannot join both of them in the same time, unless i use 2 joins, but i guess it could be done much easier and nicer. I don't want to write the code, just need some tips.
If I correctly understand what you need, I would go this way:
var battle = xDoc.Descendants("battle")
.OrderByDescending(b => GetMaxBattleArmySize(b))
.First();
where GetMaxArmySize is
private static int GetMaxBattleArmySize(XElement battle)
{
XElement attacker = battle.Element("attacker");
XElement defender = battle.Element("defender");
var attackerSizeEl = attacker.Element("size");
var defenderSizeEl = defender.Element("size");
var attackerSize = attackerSizeEl == null
? 0
: int.Parse(attackerSizeEl.Value);
var defenderSize = defenderSizeEl == null
? 0
: int.Parse(defenderSizeEl.Value);
return Math.Max(attackerSize, defenderSize);
}
Related
I have problem I've been trying to solve for the last couple of hours but without any luck at all.
First, let me show you how my database looks like (just an important part of it):
[radno_mjesto] = JOB
[grupa_radnih_mjesta] = JOB GROUPS (jobs that fall into specific groups; for example if the group name was judges jobs that would fall into this group would be: supreme court judge, administrative law judge, senior judge, etc.)
[osoba] = PERSON
What I'd like to achieve is to query all the people who fall into specific job groups, but after couple of hours I wasn't able to succeed in doing it so. I was trying various combinations of the following code and there are only 2 results I've been getting: all people (no matter what their job is) or people with specific job only (the last job from the job group as in this case).
var sveOsobe = from p in db.osobas
select p;
if (chkGrupaRadnihMjesta.Checked)
{
int id = Convert.ToInt32(GrupaRadnihMjesta.SelectedValue);
var radnaMjesta = from rm in db.grupe_radnih_mjesta_radna_mjesta
where rm.grm_id == id
select rm;
var praznoOsobe = sveOsobe.Where(o => o.osoba_id == -1);
foreach (var radnoMjesto in radnaMjesta)
{
var sveOsobeRadnaMjesta = from p in db.osobas
where p.osoba_id == -1
select p;
sveOsobeRadnaMjesta = sveOsobe.Where(o => o.rm_id == radnoMjesto.rm_id).Union(sveOsobeRadnaMjesta);
praznoOsobe = praznoOsobe.Union(sveOsobeRadnaMjesta);
}
sveOsobe = sveOsobe.Intersect(praznoOsobe);
}
Any help would be appreciated.
This should work....
if (chkGrupaRadnihMjesta.Checked) {
int id = Convert.ToInt32(GrupaRadnihMjesta.SelectedValue);
var sveOsobe = (
from p in db.osobas
join l in db.grupe_radnih_mjesta_radna_mjesta on l.rm_id equals p.rm_id
where l.grm_id == id
select p
).Distinct();
}
I'm guessing at names here!!!
I retrieve data from two different repositories:
List<F> allFs = fRepository.GetFs().ToList();
List<E> allEs = eRepository.GetEs().ToList();
Now I need to join them so I do the following:
var EFs = from c in allFs.AsQueryable()
join e in allEs on c.SerialNumber equals e.FSerialNumber
where e.Year == Convert.ToInt32(billingYear) &&
e.Month == Convert.ToInt32(billingMonth)
select new EReport
{
FSerialNumber = c.SerialNumber,
FName = c.Name,
IntCustID = Convert.ToInt32(e.IntCustID),
TotalECases = 0,
TotalPrice = "$0"
};
How can I make this LINQ query better so it will run faster? I would appreciate any suggestions.
Thanks
Unless you're able to create one repository that contains both pieces of data, which would be a far preferred solution, I can see the following things which might speed up the process.
Since you'r always filtering all E's by Month and Year, you should do that before calling ToList on the IQueryable, that way you reduce the number of E's in the join (probably considerably)
Since you're only using a subset of fields from E and F, you can use an anonymous type to limit the amount of data to transfer
Depending on how many serialnumbers you're retrieving from F's, you could filter your E's by serials in the database (or vice versa). But if most of the serialnumbers are to be expected in both sets, that doesn't really help you much further
Reasons why you might not be able to combine the repositories into one are probably because the data is coming from two separate databases.
The code, updated with the above mentioned points 1 and 2 would be similar to this:
var allFs = fRepository.GetFs().Select(f => new {f.Name, f.SerialNumber}).ToList();
int year = Convert.ToInt32(billingYear);
int month = Convert.ToInt32(billingMonth);
var allEs = eRepository.GetEs().Where(e.Year == year && e.Month == month).Select(e => new {e.FSerialNumber, e.IntCustID}).ToList();
var EFs = from c in allFs
join e in allEs on c.SerialNumber equals e.FSerialNumber
select new EReport
{
FSerialNumber = c.SerialNumber,
FName = c.Name,
IntCustID = Convert.ToInt32(e.IntCustID),
TotalECases = 0,
TotalPrice = "$0"
};
I have the following query that receives a list of IDs and I want to do a count. There's also an object model CountModel that holds the counts with each property defined as an int.
public class GetCountByStatus(List<int> TheIDs)
{
...using MyDC...
var CountData = (from d in MyDC.Data
where TheIDs.Contains(d.ID)
group d by d.Status into statusgroup
select new CountModel()
{
CountStatus1 = (from g in statusgroup
where g.Status == 1
select g).Count(),
CountStatus2 = (from g in statusgroup
where g.Status == 2
select g).Count(),
CountStatusN = ....
}).Single();
If for instance there are no elements with status N, will this code crash or will the count be 0 for CountStatusN ? Is this the best way to do what I want?
Thanks.
I would go for a dictionary instead, try something like this:
var countData = MyDC.Data.Where(y => TheIDs.Contains(y.ID))
.GroupBy(y => y.Status).ToDictionary(y => y.Key, y => y.Count());
I haven't tried it my self and not written the code in VS, but I think that is almost how you do can do it. That will give you a dictionary where the key is the status and the value is the count of that status.
Defining a model with properties named SomethingX is not very flexible. That means you have to go in an change the model when there is a new status. Keeping the data in the dictionary instead will save you from that.
Count() will always return an integer, which is 0 if there are no elements with the given status. Therefore CountStatusN will always be an integer as well.
I'm still new to Linq so if you see something I really shouldn't be doing, please feel free to suggest a change.
I am working on a new system to allow officers to sign up for overtime. Part of the data is displayed on a map with search criteria filtering unwanted positions. In order to make the data easier to work with, it is read into a hierarchy object structure using Linq. In this example, a job can contain multiple shifts and each shift can have multiple positions available. The Linq statement to read them in looks like the following.
var jobs = (from j in db.Job
join s in db.Shift on j.Id equals s.JobId into shifts
select new JobSearchResult
{
JobNumber = j.Id,
Name = j.JobName,
Latitude = j.LocationLatitude,
Longitude = j.LocationLongitude,
Address = j.AddressLine1,
Shifts = (from shift in shifts
join p in db.Position on shift.Id equals p.ShiftId into positions
select new ShiftSearchResult
{
Id = shift.Id,
Title = shift.ShiftTitle,
StartTime = shift.StartTime,
EndTime = shift.EndTime,
Positions = (from position in positions
select new PositionSearchResult
{
Id = position.Id,
Status = position.Status
}).ToList()
}).ToList()
});
That works fine and has been tested. There may be a better way to do it and if you know of a way, feel free to suggest. My problem is this. After the query is created, search criteria will be added. I know that I could add it when the query is created but for this its easier to do it after. Now, I can easy add criteria that looks like this.
jobs = jobs.Where(j => j.JobNumber == 1234);
However, I am having trouble figuring out how to do the same for Shifts or Positions. In other words, how would I could it to add the condition that a shift starts after a particular time? The following example is what I am trying to accomplish but will not (obviously) work.
jobs = jobs.Shifts.Where(s = s.StartTime > JobSearch.StartTime) //JobSearch.StartTime is a form variable.
Anyone have any suggestions?
Step 1: create associations so you can have the joins hidden behind EntitySet properties.
http://msdn.microsoft.com/en-us/library/bb629295.aspx
Step 2: construct your filters. You have 3 queryables and the possibility of filter interaction. Specify the innermost filter first so that the outer filters may make use of them.
Here are all jobs (unfiltered). Each job has only the shifts with 3 open positions. Each shift has those open positions.
Expression<Func<Position, bool>> PositionFilterExpression =
p => p.Status == "Open";
Expression<Func<Shift, bool>> ShiftFilterExpression =
s => s.Positions.Where(PositionFilterExpression).Count == 3
Expression<Func<Job, bool>> JobFilterExpression =
j => true
Step 3: put it all together:
List<JobSearchResult> jobs = db.Jobs
.Where(JobFilterExpression)
.Select(j => new JobSearchResult
{
JobNumber = j.Id,
Name = j.JobName,
Latitude = j.LocationLatitude,
Longitude = j.LocationLongitude,
Address = j.AddressLine1,
Shifts = j.Shifts
.Where(ShiftFilterExpression)
.Select(s => new ShiftSearchResult
{
Id = s.Id,
Title = s.ShiftTitle,
StartTime = s.StartTime,
EndTime = s.EndTime,
Positions = s.Positions
.Where(PositionFilterExpression)
.Select(p => new PositionSearchResult
{
Id = position.Id,
Status = position.Status
})
.ToList()
})
.ToList()
})
.ToList();
The following method is pretty simple, I'm trying to determine a line-item rate by matching up another property of the line-item with a lookup from a parent object. There's a few things I don't like about it and am looking for elegant solutions to either make the method smaller, more efficient, or both. It works in it's current state and it's not like it's noticeably inefficient or anything. This isn't mission critical or anything, more of a curiosity.
private decimal CalculateLaborTotal()
{
decimal result = 0;
foreach (ExtraWorkOrderLaborItem laborItem in Labor)
{
var rates = (from x in Project.ContractRates where x.ProjectRole.Name == laborItem.ProjectRole.Name select x).ToList();
if (rates != null && rates.Count() > 0)
{
result += laborItem.Hours * rates[0].Rate;
}
}
return result;
}
I like the idea of using List<T>.ForEach(), but I was having some trouble keeping it succinct enough to still be easy to read/maintain. Any thoughts?
Something like this should do it (untested!):
var result =
(from laborItem in Labor
let rate = (from x in Project.ContractRates
where x.ProjectRole.Name == laborItem.ProjectRole.Name
select x).FirstOrDefault()
where rate != null
select laborItem.Hours * rate.Rate).Sum();
Or (assuming only one rate can match) a join would be even neater:
var result =
(from laborItem in Labor
join rate in Project.ContractRates
on laborItem.ProjectRole.Name equals rate.ProjectRole.Name
select laborItem.Hours * rate.Rate).Sum();
Okay, well how about this:
// Lookup from name to IEnumerable<decimal>, assuming Rate is a decimal
var ratesLookup = Project.ContractRates.ToLookup(x => x.ProjectRole.Name,
x => x.Rate);
var query = (from laborItem in Labor
let rate = ratesGroup[laborItem].FirstOrDefault()
select laborItem.Hours * rate).Sum();
The advantage here is that you don't need to look through a potentially large list of contract rates every time - you build the lookup once. That may not be an issue, of course.
Omit the rates != null check - A linq query may be empty but not null.
If you just need the first element of a list, use List.First or List.FirstOrDefault.
There is no advantage in using List<T>.ForEach.