C# 我可以在 Linq 查询中选择多个对象吗
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/520788/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Can I select multiple objects in a Linq query
提问by James Hay
Can I return more than one item in a select? For instance I have a List of Fixtures (think football (or soccer for the yanks) fixtures). Each fixture contains a home and away team and a home and away score. I want to get all the teams that drew. I want to use something like
我可以在一个选择中返回多个项目吗?例如,我有一个固定装置列表(想想足球(或 yanks 的足球)固定装置)。每个赛程包含一个主客场球队和一个主客场比分。我想得到所有抽签的球队。我想使用类似的东西
IEnumerable<Team> drew = from fixture in fixtures
where fixture.Played && (fixture.HomeScore == fixture.AwayScore)
select fixture.HomeTeam && fixture.AwayTeam;
I know this syntax is incorrect, what I don't know is if it's possible to do this. Would I need two queries and then concatenate them?
我知道这种语法不正确,我不知道是否可以这样做。我需要两个查询然后将它们连接起来吗?
Edit: this is really a learning thing so it's not critical to achieve this in any particular way. Basically, at this stage all i want is a list of teams that have drawn. An example usage might be that for a given list of fixtures i can find all of the drawn teams so that i could update their standings in a table by 1 point (3 for a win, 0 for a loss).
编辑:这真的是一个学习的东西,所以以任何特定的方式实现这一点并不重要。基本上,在这个阶段,我想要的只是一个已经抽签的球队名单。一个示例用法可能是,对于给定的固定装置列表,我可以找到所有被抽中的球队,以便我可以将他们在表格中的排名更新 1 分(赢 3 分,输球 0 分)。
采纳答案by Mike Powell
I think you're looking for the Union method as follows:
我认为您正在寻找 Union 方法如下:
IEnumerable<Team> drew = (from fixture in fixtures
where fixture.Played
&& (fixture.HomeScore == fixture.AwayScore)
select fixture.HomeTeam)
.Union(from fixture in fixtures
where fixture.Played
&& (fixture.HomeScore == fixture.AwayScore)
select fixture.AwayTeam);
回答by Anton Gogolev
101 LINQ Samples, namely Select - Anonymous Types 1
101 个 LINQ 样本,即 Select - Anonymous Types 1
... select new { HomeTeam = fixture.HomeTeam, AwayTeam = fixture.AwayTeam };
回答by AwesomeTown
Edit:Sorry, misunderstood your original question, so rewrote answer.
编辑:对不起,误解了你原来的问题,所以重写了答案。
You could use the "SelectMany" operator to do what you want:
您可以使用“SelectMany”运算符来执行您想要的操作:
IEnumerable<Team> drew =
(from fixture in fixtures
where fixture.Played && (fixture.HomeScore == fixture.AwayScore)
select new List<Team>()
{ HomeTeam = fixture.HomeTeam,
AwayTeam = fixture.AwayTeam
}).SelectMany(team => team);
This will return a flattened list of teams that drew.
这将返回平展的球队列表。
回答by BC.
Or you can define a type to hold all that data:
或者您可以定义一个类型来保存所有数据:
IEnumerable<TeamCluster> drew = from fixture in fixtures
where fixture.Played && (fixture.HomeScore == fixture.AwayScore)
select new TeamCluster {
Team1 = fixture.HomeTeam,
Team2 = fixture.AwayTeam,
Score1 = fixture.HomeScore,
Score2 = fixture.AwayScore
};
class TeamCluster {
public Team Team1 { get; set; }
public Team Team2 { get; set; }
public int Score1 { get; set; }
public int Score2 { get; set; }
}
回答by codybartfast
The following will return an IEnumerable<Team>:
以下将返回一个 IEnumerable<Team>:
IEnumerable<Team> drew =
from fixture in fixtures
where fixture.Played && (fixture.HomeScore == fixture.AwayScore)
from team in new[]{fixture.HomeTeam, fixture.AwayTeam}
select team;
Or, with the fluent style of LINQ:
或者,用流畅的 LINQ 风格:
IEnumerable<Team> drew =
fixtures
.Where(fxtr => fxtr.Played && (fxtr.HomeScore == fxtr.AwayScore))
.SelectMany(fixture => new[]{fixture.HomeTeam, fixture.AwayTeam});
Flattening and FlatMap
展平和平面地图
This requirement is often called 'flattening'. That is, taking a <Collection of <Collections of Things>> and converting it to a <Collection of Things>.
这种要求通常被称为“扁平化”。即,将<Collection of <Collections of Things>>转换为<Collection of Things>。
SelectMany
both maps (a fixture to an Array of Teams) and flattens (a sequence of Team Arrays to a sequence of Teams). It is similar to the "flatMap" function in other languages such as Java and JavaScript.
SelectMany
两个映射(一个固定到一个团队的阵列)和展平(一个团队阵列的序列到一个团队的序列)。它类似于 Java 和 JavaScript 等其他语言中的“flatMap”函数。
It is possible to separate the Mapping and the Flattening:
可以将 Mapping 和 Flattening 分开:
IEnumerable<Team> drew =
fixtures
.Where(fxtr => fxtr.Played && (fxtr.HomeScore == fxtr.AwayScore))
// map
.Select(fixture => new[]{fixture.HomeTeam, fixture.AwayTeam})
// flatten
.SelectMany(teams => teams);
Other Approaches
其他方法
Iterator Block
迭代器块
The same can be achieved with an iterator block, but I suspect this is rarely the best approach:
使用迭代器块也可以实现同样的效果,但我怀疑这很少是最好的方法:
IEnumerable<Team> Drew(IEnumerable<Fixture> fixtures){
var draws =
fixtures
.Where(fxtr => fxtr.Played && (fxtr.HomeScore == fxtr.AwayScore));
foreach(var fixture in draws){
yield return fixture.HomeTeam;
yield return fixture.AwayTeam;
}
}
Union
联盟
Union is also an option but has the potential to produce different results from the above:
Union 也是一种选择,但有可能产生与上述不同的结果:
The order of results will be different. All Home results are returned then all Away results.
Union
enumerates fixtures twice, so, depending on how fixtures is implemented, there is the potential for fixtures to be updated between calls. E.g., if a new drawn fixture were added between calls then the Away team could be returned but not the Home team.
结果的顺序会有所不同。返回所有主场结果,然后返回所有客场结果。
Union
枚举设备两次,因此,根据设备的实现方式,设备有可能在调用之间更新。例如,如果在呼叫之间添加了一个新的抽签装置,则可以返回客队,但不能返回主队。
As Mike Powell describes:
正如迈克鲍威尔所描述的:
IEnumerable<Team> drew =
( from fixture in fixtures
where fixture.Played && (fixture.HomeScore == fixture.AwayScore)
select fixture.HomeTeam
).Union(
from fixture in fixtures
where fixture.Played && (fixture.HomeScore == fixture.AwayScore)
select fixture.AwayTeam );
Depending on how fixtures is sourced/implemented it may be worth considering 'caching' the drawn fixtures to avoid having to enumerate fixtures twice.
根据夹具的来源/实现方式,可能值得考虑“缓存”绘制的夹具以避免必须枚举夹具两次。
var draws =
( from fixture in fixtures
where fixture.Played && (fixture.HomeScore == fixture.AwayScore)
select fixture
).ToList();
IEnumerable<Team> drew =
(from draw in draws select draw.HomeTeam)
.Union(from draw in draws select draw.AwayTeam);
Or using the fluent style:
或者使用流畅的风格:
var draws =
fixtures
.Where(fxtr => fxtr.Played && (fxtr.HomeScore == fxtr.AwayScore))
.ToList();
IEnumerable<Team> drew =
draws.Select(fixture => fixture.HomeTeam)
.Union(draws.Select(fixture => fixture.AwayTeam));
Modifying the Fixture class
修改 Fixture 类
One could consider adding "ParticipatingTeams" to the Fixture class to get:
可以考虑在 Fixture 类中添加“ParticipatingTeams”以获得:
IEnumerable<Team> drew =
from fixture in fixtures
where fixture.Played && (fixture.HomeScore == fixture.AwayScore)
from team in fixture.ParticipatingTeams
select team;
but as @MattDeKrey points out that requires a contract change.
但正如@MattDeKrey 指出的那样,这需要更改合同。
Code Samples
代码示例
Code samples are available on Repl.it
Repl.it上提供了代码示例
回答by Mike Rosenblum
Taking a stab at this myself I came up with the same version as 'it depends'.
我自己对此进行了尝试,我想出了与“视情况而定”相同的版本。
Using query comprehension syntax:
使用查询理解语法:
IEnumerable<Team> drew =
from fixture in fixtures
where fixture.Played && (fixture.HomeScore == fixture.AwayScore)
from team in new[]{fixture.AwayTeam, fixture.HomeTeam}
select team;
Using lambda with extension methods:
将 lambda 与扩展方法一起使用:
IEnumerable<Team> drew =
fixtures.Where(f => f.Played && f.HomeScore == f.AwayScore)
.SelectMany(f => new[]{f.HomeTeam, f.AwayTeam});
Edit:I don't know if a team could have possibly played and drawn more than once in your database, but if that's possible, then you might want to make use of the Distinct
query operator:
编辑:我不知道一个球队是否可以在您的数据库中多次参加和抽签,但如果可能的话,您可能希望使用Distinct
查询运算符:
IEnumerable<Team> drew =
(from fixture in fixtures
where fixture.Played && (fixture.HomeScore == fixture.AwayScore)
from team in new[]{fixture.AwayTeam, fixture.HomeTeam}
select team).Distinct();
or:
或者:
IEnumerable<Team> drew =
fixtures.Where(f => f.Played && f.HomeScore == f.AwayScore)
.SelectMany(f => new[]{f.HomeTeam, f.AwayTeam})
.Distinct();
回答by Marlon
I came up against this very issue, and couldn't find what I wanted so I wrote a small extension method which did what I wanted.
我遇到了这个问题,但找不到我想要的东西,所以我写了一个小扩展方法来完成我想要的。
public static IEnumerable<R> MapCombine<M, R>(this IEnumerable<M> origList, params Func<M, R>[] maps)
{
foreach (var item in origList)
foreach (var map in maps)
{
yield return map(item);
}
}
Following the problem in the question, you would then do something like this
按照问题中的问题,然后你会做这样的事情
var drew = fixtures.Where(fixture => fixture.Played &&
(fixture.HomeScore == fixture.AwayScore))
.MapCombine(f => f.HomeTeam, f => f.AwayTeam);
Interestingly intellisense isn't exactly happy about this, you don't get the lamdba expression in the top of the drop down, however after the '=>' its quite happy. But the main thing is the compiler is happy.
有趣的是,intellisense 对此并不完全满意,您没有在下拉列表的顶部看到 lamdba 表达式,但是在 '=>' 之后它很高兴。但主要的是编译器很高兴。