Подтвердить что ты не робот

Можно ли выбрать несколько объектов в запросе Linq?

Могу ли я вернуть более одного товара в выбор? Например, у меня есть список матчей (думаю, футбол (или футбол для янки) матчи). Каждое приспособление содержит домашнюю и выездную команду и счет гостей и гостей. Я хочу получить все команды, которые рисовали. Я хочу использовать что-то вроде

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

Я знаю, что этот синтаксис неправильный, но я не знаю, возможно ли это сделать. Нужно ли мне два запроса, а затем объединить их?

Изменение: это действительно учебная вещь, поэтому не важно, чтобы добиться этого каким-либо конкретным способом. По сути, на данном этапе все, что я хочу, - это список команд, которые сыграли вничью. Примером использования может быть то, что для данного списка матчей я могу найти все привлеченные команды, чтобы я мог обновить их таблицы в таблице на 1 очко (3 за победу, 0 за поражение).

4b9b3361

Ответ 1

Я думаю, что вы ищете метод 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);

Ответ 2

101 Образцы LINQ, а именно Select - Anonymous Types 1

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

Ответ 3

Следующее вернет 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;

Или со свободным стилем LINQ:

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

Сглаживание и FlatMap

Это требование часто называют "сплющиванием". То есть взять <Collection of Things >> и преобразовать его в <Collection of Things>.

SelectMany карт" (SelectMany к массиву команд) и "сплющить" (последовательность групповых массивов к последовательности команд). Это похоже на функцию "flatMap" в других языках, таких как Java и JavaScript.

Можно разделить отображение и выравнивание:

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. Порядок результатов будет другим. Все результаты Home возвращаются, затем все результаты Away.

  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

Ответ 4

Взяв на себя удар, я придумал ту же версию, что и "она зависит".

Использование синтаксиса понимания запроса:

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

Использование лямбда с методами расширения:

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

Или вы можете определить тип для хранения всех этих данных:

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

Изменить: Извините, непонятый исходный вопрос, поэтому переписал ответ.

Вы можете использовать оператор 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

Я столкнулся с этой самой проблемой и не смог найти то, что хотел, поэтому написал небольшой метод расширения, который сделал то, что я хотел.

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 в верхней части раскрывающегося списка, однако после "= > " его вполне доволен. Но главное - компилятор счастлив.