代码之家  ›  专栏  ›  技术社区  ›  James Hay

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

  •  40
  • James Hay  · 技术社区  · 16 年前

    我可以在一个选择中返回多个项目吗?例如,我有一个赛程表(想想足球(或猛攻队的足球)赛程)。每场比赛都包含一支主队和一支客队以及一个主客场得分。我想得到所有平局的球队。我想用类似的东西

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

    我知道这个语法不正确,但我不知道是否有可能做到这一点。我需要两个查询,然后将它们连接起来吗?

    编辑:这真的是一件学习的事情,所以以任何特定的方式实现这一点并不重要。基本上,在这个阶段,我只想要一份抽签的球队名单。一个示例用法可能是,对于给定的赛程列表,我可以找到所有抽签的球队,这样我就可以将他们在表格中的排名更新1分(胜利3分,失败0分)。

    7 回复  |  直到 7 年前
        1
  •  34
  •   Anton Gogolev    16 年前

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

    ... select new { HomeTeam = fixture.HomeTeam, AwayTeam = fixture.AwayTeam };
    
        2
  •  32
  •   codybartfast    6 年前

    下面将返回一个IEnumerable<团队>:

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

    平面化和平面地图

    这一要求通常被称为“扁平化”。也就是说,采取<<物品收藏>>并将其转换为<收集物品>。

    SelectMany 既有映射(团队阵列的固定装置)也有扁平化(团队阵列到团队序列的序列)。它类似于Java和JavaScript等其他语言中的“flatMap”函数。

    可以将映射和展平分开:

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

    联盟

    联盟也是一种选择,但有可能产生与上述不同的结果:

    1. 结果的顺序会有所不同。返回所有主场成绩,然后返回所有客场成绩。

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

    根据夹具的来源/实现方式,可能值得考虑“缓存”绘制的夹具,以避免重复枚举夹具。

    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

        3
  •  23
  •   Mike Powell    16 年前

    我认为您正在寻找以下联盟方法:

    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);
    
        4
  •  14
  •   Mike Rosenblum    16 年前

    我自己尝试了一下,得出了与“这取决于”相同的版本。

    使用查询理解语法:

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

    编辑: 我不知道一支球队是否可能在你的数据库中玩过不止一次,但如果可能的话,那么你可能想利用 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();
    

    或者:

    IEnumerable<Team> drew =
        fixtures.Where(f => f.Played && f.HomeScore == f.AwayScore)
        .SelectMany(f => new[]{f.HomeTeam, f.AwayTeam})
        .Distinct();
    
        5
  •  6
  •   BC.    16 年前

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

    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; }
    }
    
        6
  •  5
  •   AwesomeTown    16 年前

    编辑: 对不起,误解了你最初的问题,所以重写了答案。

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

    这将返回一个已绘制的球队的扁平列表。

        7
  •  1
  •   Marlon    14 年前

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

    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对此并不满意,你在下拉列表的顶部没有得到λ表达式,但是在'=>“它很快乐。但最重要的是编译器很高兴。

    推荐文章