tags:

views:

4595

answers:

6

I'm very new to Linq so bare with me. 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

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

Cheers James

+3  A: 

101 LINQ Samples, namely Select - Anonymous Types 1

... select new { HomeTeam = fixture.HomeTeam, AwayTeam = fixture.AwayTeam };
Anton Gogolev
Not the answer he's looking for. He wants a list of Teams, not a list of anonymous types with hometeam and awayteam properties.
Mike Powell
This is true... i could get round it using anonymous types... just wondered if there was a way to get just a list of teams. If it's the only way it's the only way though
James Hay
I agree that this doesn't return a list of teams, but i thinks its better for him to adapt his code to suport handling this anon type. If James Hay could update his question to describe his usuage that might help.
bendewey
I think his question already describes his requirement perfectly: "I want to get a list of teams that drew." There are lots of reasons he might not want to use anonymous types here (needing to pass the list outside this method would be a common one).
Mike Powell
+1  A: 

Edit: Sorry, misunderstood your original question, so rewrote answer.

You could use the "SelectMany" operator to do what you want:

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.

John Price
+2  A: 

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; }
}
BC
+4  A: 

I think you're looking for the Union method as follows:

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);
Mike Powell
+4  A: 

An (independant) variation on John Price's solution...

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

You could consider adding "ParticipatingTeams" to the Fixture class to get:

IEnumerable<Team> drew =
    from fixture in fixtures
    where fixture.Played && (fixture.HomeScore == fixture.AwayScore)
    from team in fixture.ParticipatingTeams
    select team;
it depends
+1 for your first query - doesn't require a contract change and is more efficient than the leading answer.
mattdekrey
+1  A: 

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:

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:

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