2010-11-26 2 views

ответ

29

Выберите много позволяет выбрать свойство из источника запроса, который является IEnumerable <T> коллекции, но вместо того, чтобы возвращать коллекцию коллекций (IEnumerable < IEnumerable <T> >) будет сглаживать коллекции в единый коллекция.

Вот пример, который вы можете запустить, чтобы продемонстрировать разницу между Select и SelectMany:

//set up some data for our example 
var tuple1 = new { Name = "Tuple1", Values = new int [] { 1, 2, 3 } }; 
var tuple2 = new { Name = "Tuple2", Values = new int [] { 4, 5, 6 } }; 
var tuple3 = new { Name = "Tuple3", Values = new int [] { 7, 8, 9 } }; 

//put the tuples into a collection 
var tuples = new [] { tuple1, tuple2, tuple3 }; 

//"tupleValues" is an IEnumerable<IEnumerable<int>> that contains { { 1, 2, 3 }, { 4, 5, 6 }, { 7, 8, 9 } } 
var tupleValues = tuples.Select(t => t.Values); 

//"tupleSelectManyValues" is an IEnumerable<int> that contains { 1, 2, 3, 4, 5, 6, 7, 8, 9 } 
var tupleSelectManyValues = tuples.SelectMany(t => t.Values); 

С помощью SelectMany вы сделать его проще для запроса значений в дочерних коллекций.

+0

Благодаря abatishchev, я не заметил опечатку. –

6

SelectMany основном сглаживается и обрабатывает иерархические данные, и имеет две основных форм

(для целей примера, см этого исходного кода)

class TestObj 
{ 
    public string Name { get; set; } 
    public List<string> Items { get; set; } 
} 

var hierarchicalCollection = new List<TestObj>(); 

hierarchicalCollection.Add(new TestObj() 
    {Items = new List<string>() 
     {"testObj1-Item1", "testObj1-Item2"}, Name="t1"}); 
hierarchicalCollection.Add(new TestObj() 
    {Items = new List<string>() 
     {"testObj2-Item1", "testObj2-Item2"}, Name="t2"}); 

вариант 1) создает коллекцию из коллекции коллекции (по существу, сплющивание иерархических данных)

IEnumerable<string> flattenedCollection = 
    hierarchicalCollection.SelectMany(t => t.Items); 

В результате получается:

"testObj1-Item1" 
"testObj1-Item2" 
"testObj2-Item1" 
"testObj2-Item2" 

вариант 2) создает коллекцию из коллекции коллекций, а затем обрабатывает каждый элемент новой коллекции с помощью ссылки на оригинальный родителю

IEnumerable<string> flattenedModifiedCollection = 
    hierarchicalCollection.SelectMany 
     (t => t.Items, (t, i) => t.Name + " : " + i); 

результат:

"t1 : testObj1-Item1" 
"t1 : testObj1-Item2" 
"t2 : testObj2-Item1" 
"t2 : testObj2-Item2" 

, каждое из указанных выше вариантов использования имеет вариант, в котором индекс обрабатываемого элемента доступен для функций преобразования.

3

Я использую это расширение все время для погружения в иерархии.

Еще один крутой способ сделать это, когда Extensions получить немного неаккуратно, чтобы использовать формальный способ LINQ, как:

var vehicles = from cust in context.Customers 
       from fleet in cust.Fleets 
       from v in fleet.Vehicles 
       select v; 

Это было бы эквивалентно:

var vehicles = context.Customers.SelectMany(c => c.Fleets).SelectMany(f => f.Vehicles); 

Это может получить немного длиннее намотки при добавлении туда, где предложения и объединения и т. д. Надеюсь, это поможет!

0

У меня было некоторое удовольствие, используя SelectMany в LINQ. Следующая ссылка описала возвращение IEnumerable в предложение select LINQ, которое возвращает последовательность последовательностей и использование SelectMany, чтобы сгладить это в простую последовательность. "Linq to XML using Let, Yield return and Selectmany". Это не только вариант использования SelectMany, но и часть подхода, который генерирует несколько выходов с одного входа в LINQ.

13

Есть несколько перегрузок в SelectMany. Один из них позволяет вам отслеживать любые отношения между родителем и детьми при обходе иерархии.

Пример: предположим, что вы имеете следующую структуру: League -> Teams -> Player

Вы можете легко вернуть плоский сбор игроков. Однако вы можете потерять любую ссылку на команду, частью которой является игрок.

К счастью, есть перегрузка для такой цели:

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

Предыдущий пример взят из IK блога Дэна:

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

Я сильно рекомендую вам взглянуть на него ,

0

Вот еще один пример (VB.NET) использование:

'Original list 
Dim l() As String = {"/d", "/bc:\Temp\In*;c:\Temp\Out", "/hABC", "/s123"} 

'Processed list: will list first 2 characters from each string member. 
Dim L1 As IEnumerable(Of String) = l.SelectMany(Function(x As String) {x.Substring(0, 2)}) 

Dim L2 As List(Of String) = l.SelectMany(Function(x As String) {x.Substring(0, 2)}).ToList 

'Will return dictionary like list with keys==2 characters and values the rest from each string member. 
Dim L3 As List(Of KeyValuePair(Of String, String)) = l.SelectMany(Function(x As String) {New KeyValuePair(Of String, String)(x.Substring(0, 2), x.Substring(2))}).ToList 
Смежные вопросы