Linq для вложенной петли

У меня есть цикл следующим образом:

foreach(x in myColl) 
{
    foreach(var y in x.MyList) 
    {
        result.Add(x.MyKey + y)
    }
}

Это означает, что в моем внутреннем цикле мне нужен доступ к свойству текущего внешнего элемента.

Я ищу оператор LINQ, но я не уверен в этом. Я попробовал это, используя

result = myColl
    .SelectMany(x => x.MyList)
    .SelectMany(x => /* how to get the key of the outer loop here */ + x)

Ответ 1

Это легко с выражениями запроса:

(from x in myColl
 from y in x.MyList
 select x.MyKey + y).ToList()

Это работает, потому что это означает:

myColl
.SelectMany(x => x.MyList.Select(item => new { List = x, Item = item }))
.Select(x => ...) //rest of the query, whatever you like

Ключ должен содержать как список, так и элементы списка. Проведите их через запрос с использованием анонимного типа (или любого другого контейнера).

Ответ 2

Существует перегрузка SelectMany, которая позволяет получить доступ к элементу "parent". ListOfList.SelectMany(list = > list.InnerList, (lst, element) = > HandleInnerListAndElementFromIt (lst, element))

 result = myColl.SelectMany(x => x.MyList,(x1,x2)=>DoSomething(x1,x2));

EDIT Добавлено:

Для вашего конкретного примера это выглядит так:

result = myColl.SelectMany(x=>x.MyList,(x,y)=>x.MyKey+y));

Обратите внимание, что для вызова метода SelectMany есть два лямбда-параметра.

Первая лямбда возьмет "x" и вернет новый Enumerable. х = > x.MyList

Вторая лямбда принимает "x" и "y" и создает новый результат. (х, у) = > x.MyKey + у

Ответ 3

Это когда я лично предпочитаю синтаксис запроса

var result = from x in myCol1
             from y in x.MyList
             select x.MyKey + y;

Ответ 4

Моя коллекция Лиг, Команд и Игроков имеет следующую структуру:

enter image description here

Эта самая базовая версия дает вам полную коллекцию IEnumerable всех команд во всех лигах.

var allTeams = from t in leagues.
SelectMany( l => l.Teams )
select t;

Вы можете связать вызовы SelectMany вместе, чтобы погрузиться в иерархию настолько глубоко, насколько вы хотите. Это возвращает IEnumerable всех игроков во всех лигах и командах.

var allPlayers = from p in leagues
.SelectMany( l => l.Teams )
.SelectMany( t => t.Players )
select p;

И, конечно же, вы можете добавить критерии условия where для дальнейшего уточнения, какие игроки вы получаете сейчас, когда вы работаете с фиксированным списком игроков.

var onlyYoungPlayers = from p in leagues
.SelectMany( l => l.Teams )
.SelectMany( t => t.Players )
where p.Age < 30
select p;

Вот хороший способ связать Where() между вызовами SelectMany(), чтобы получить всех игроков только из определенных команд.

var players = leagues.SelectMany( l => l.Teams )
.Where( t => t.NumberOfWins > 2  )
.SelectMany( t => t.Players )
.Where( p => p.HomeState == "CA" )
.Select( p => p );

3-я и 4-я перегрузки метода SelectMany() с дополнительным параметром "селектор результата" требуют более подробного объяснения. Я рассматриваю этот дополнительный параметр селектора результата как вспомогательный объект, чтобы помочь вам узнать отношения между родительской и дочерней коллекциями. Скажем, вам нужна коллекция результатов, которая будет не только иметь полный список команд, соответствующих некоторым критериям во всех лигах, но и знать, в какую лигу входят команды. Если вы используете один из указанных выше запросов, вы получите полный список Командные объекты, но потеряли связь с тем, из какой они Лиги. (Иногда в вашей объектной модели есть "обратные ссылки" для перехода от дочернего объекта к их родителю, что делает ненужным использование этого селектора результатов, но вы не всегда имеете это преимущество.) Селектор результатов - это промежуточный объект, доступный в области действия запроса, чтобы дать вам необходимую информацию, и вам решать, какие данные вам нужны в селекторе результатов, чтобы помочь вам. Вот пример:

var teamsAndTheirLeagues = from helper in leagues
.SelectMany( l => l.Teams, ( league, team ) 
=> new { league, team } )
where helper.team.Players.Count > 2 
    && helper.league.Teams.Count < 10
select new { LeagueID = helper.league.ID, Team = helper.team };

Таким образом, вспомогательный объект создается из Func <> с двумя аргументами, который берет объект из родительской коллекции и объект из дочерней коллекции, которые становятся парными во время обработки запроса, и вы можете делать с ними все, что захотите - Im просто делать что-то простое, что создает новый анонимный тип со встроенными в них объектами, что дает мне возможность использовать эти данные в предложении where, а также в результатах запроса. (Примечание: вы можете просто "выделить" весь вспомогательный объект в последней строке запроса)

Я полагаю, вы могли бы взглянуть на эту ссылку, поскольку я прочитал эту статью и обнаружил, что она почти полна, насколько это понятие касается.

http://blogs.interknowlogy.com/2008/10/10/use-linqs-selectmany-method-to-flatten-collections/