Reputation: 148624
I've encountered a problem in fluent LINQ for selecting a parent and a child into one Ienumerable < anonymous type>
.
For simplicity :
There is a list of commanders
(commander in each region).
Each Commander has its own List of Soldiers
. ( and each Soldier
has a bool property IsCanWinWar
and a Tool
which he uses to fight with)
I want to list each commander ( who has one or more solider who can win the war) and one tool
name which is used by that soldier.
I dont care if a commander has more then one soldier who can win the war .
All a commander needs is a tool
(never-mind which tool) from one of its soldiers (who can win the war).
the output is Ienumerable < anonymous type>
where anonymous type is like :
{
theCommander = [commanderObject] ,
theToolName = [the tool name ]
}
I did something with selectMany
but it was very long and ugly.
Is there any short query (fluent query) which can yield the same results in a shorter way?
public class Commander
{
public List<Soldier> lstSoldiers =new List<Soldier>(); //from db actually.
}
public class Soldier
{
public bool IsCanWinWar { get; set; }
public string Tool { get; set; }
}
void Main()
{
List<Commander> lstCommanders = new List<Commander>(); //data source is actually from db.
var MyIernumerableOfAnonymouseTypes= ?
}
Upvotes: 2
Views: 1411
Reputation: 25434
First approach (revised later):
from commander in lstCommanders
where commander.lstSoldiers.Any(soldier => soldier.IsCanWinWar) // Consider only commanders who have at least one soldier who can win the war
select new
{
Commander = commander,
Tool = (from soldier in commander.lstSoldiers
where soldier.IsCanWinWar // Consider tool originating from soldiers who can win the war
select soldier.Tool).FirstOrDefault()
};
Second more concise and faster:
from commander in lstCommanders
where commander.lstSoldiers.Any(soldier => soldier.IsCanWinWar)
select new { Commander = commander, Tool = commander.lstSoldiers.First(soldier => soldier.IsCanWinWar).Tool };
In the fluent way:
lstCommanders.Where(commander => commander.lstSoldiers.Any(soldier => soldier.IsCanWinWar))
.Select( commander => new
{
Commander = commander,
Tool = commander.lstSoldiers.First(soldier => soldier.IsCanWinWar).Tool
});
Third option with one iteration:
from commander in lstCommanders
let winner = commander.lstSoldiers.FirstOrDefault(soldier => soldier.IsCanWinWar)
where null != winner // Consider only commanders who have at least one soldier who can win the war
select new { Commander = commander, Tool = winner.Tool };
Upvotes: 1
Reputation: 236268
var MyIernumerableOfAnonymouseTypes =
lstCommanders.Select(c => new {
theCommander = c,
theToolName = c.lstSoldiers.Where(s => s.IsCanWinWar)
.Select(s => s.Tool)
.FirstOrDefault() })
.Where(x => x.theToolName != null);
If there is no soldier which can win war, then tool will be null. Just filter out those commanders after selection.
BTW I think Soldiers
is a better property name, then lstSoldiers
(it has no prefix and it is PascalCase).
Upvotes: 2