我可以在Linq查询中选择多个对象吗?

时间:2009-02-06 15:45:22

标签: c# linq list

我可以在选择中返回多个项目吗?例如,我有一个固定装置列表(想想橄榄球(或用于猛拉的足球)固定装置)。每个夹具都包含一个主场和客场球队以及主客场得分。我想得到所有吸引的球队。我想使用像

这样的东西
IEnumerable<Team> drew = from fixture in fixtures
                         where fixture.Played && (fixture.HomeScore == fixture.AwayScore)
                         select fixture.HomeTeam && fixture.AwayTeam;

我知道这种语法不正确,我不知道是否可以这样做。我需要两个查询然后将它们连接起来吗?

编辑:这真的是一个学习的东西,因此以任何特定的方式实现这一点并不重要。基本上,在这个阶段,我想要的是已经绘制的球队列表。一个示例用法可能是对于给定的灯具列表,我可以找到所有绘制的球队,这样我就可以在一个表中更新他们的积分1分(胜利为3,亏损为0)。 < / p>

7 个答案:

答案 0 :(得分:33)

101 LINQ Samples,即选择 - 匿名类型1

... select new { HomeTeam = fixture.HomeTeam, AwayTeam = fixture.AwayTeam };

答案 1 :(得分:24)

以下内容将返回IEnumerable&lt; Team&gt;:

IEnumerable<Team> drew =
    from fixture in fixtures
    where fixture.Played && (fixture.HomeScore == fixture.AwayScore)
    from team in new[]{fixture.HomeTeam, fixture.AwayTeam}
    select team;

或者,流畅的LINQ风格:

IEnumerable<Team> drew =
    fixtures
    .Where(fxtr => fxtr.Played && (fxtr.HomeScore == fxtr.AwayScore))
    .SelectMany(fixture => new[]{fixture.HomeTeam, fixture.AwayTeam});

展平和FlatMap

此要求通常称为“扁平化”。也就是说,采用&lt;收集&lt;收集物品&gt;&gt;并将其转换为&lt; Collection of Things&gt;。

SelectMany两个地图(一个团队阵列的固定点)和展平(一系列团队阵列到一系列团队)。它类似于其他语言中的“flatMap”函数,如Java和JavaScript。

可以将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);

其他方法

迭代器块

使用迭代器块可以实现同样的目的,但我怀疑这很少是最好的方法:

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也是一种选择,但有可能产生上述不同的结果:

  1. 结果的顺序会有所不同。所有主页结果将返回所有结果。

  2. Union枚举两次灯具,因此,根据灯具的实施方式,可能会在两次通话之间更新灯具。例如,如果在调用之间添加了新的绘制夹具,那么可以返回Away团队,但不能返回主页团队。

  3. 正如迈克鲍威尔所描述的那样:

    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 );
    

    根据灯具的采购/实施方式,可能值得考虑“缓存”绘制的灯具,以避免必须两次枚举灯具。

    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);
    

    或使用流利的风格:

    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));
    

    修改Fixture类

    可以考虑将“ParticipatingTeams”添加到Fixture类中以获取:

    IEnumerable<Team> drew =
        from fixture in fixtures
        where fixture.Played && (fixture.HomeScore == fixture.AwayScore)
        from team in fixture.ParticipatingTeams
        select team;
    

    但是@MattDeKrey指出需要更改合同。

    代码示例

    代码示例可在Repl.it

    上找到

答案 2 :(得分:22)

我认为你正在寻找如下的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);

答案 3 :(得分:14)

我自己拿出一个与'依赖'相同的版本。

使用查询理解语法:

IEnumerable<Team> drew =
    from fixture in fixtures
    where fixture.Played && (fixture.HomeScore == fixture.AwayScore)
    from team in new[]{fixture.AwayTeam, fixture.HomeTeam}
    select team;

将lambda与扩展方法一起使用:

IEnumerable<Team> drew =
    fixtures.Where(f => f.Played && f.HomeScore == f.AwayScore)
    .SelectMany(f => new[]{f.HomeTeam, f.AwayTeam});

编辑:我不知道某个团队是否可能在您的数据库中多次播放和绘制,但如果可能,那么您可能想要使用{{1查询运算符:

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();

答案 4 :(得分:6)

或者您可以定义一个类型来保存所有数据:

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; }
}

答案 5 :(得分:5)

编辑:抱歉,误解了原来的问题,所以重写了答案。

您可以使用“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);

这将返回一个展平的团队列表。

答案 6 :(得分:1)

我遇到了这个问题,找不到我想要的东西,所以我写了一个小扩展方法,做了我想做的事。

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);
    }
}

在问题中出现问题后,您可以执行类似这样的操作

var drew = fixtures.Where(fixture => fixture.Played && 
                        (fixture.HomeScore == fixture.AwayScore))
                    .MapCombine(f => f.HomeTeam, f => f.AwayTeam);

有趣的是,intellisense对此并不十分满意,你不会在下拉列表的顶部获得lamdba表达式,但是在'=&gt;'之后它很开心。但主要的是编译器很高兴。