2016-06-20 5 views
1

Скажем, у вас есть список элементов, и вы хотите их разбить, выполнить операцию на одном разделе и объединить разделы обратно в список.Как связать результат GroupBy с помощью Linq

Например, есть список чисел, и я хочу разбить их по четности, а затем изменить коэффициенты и объединить с эвенов. [1,2,3,4,5,6,7,8] -> [7,5,3,1,2,4,6,8]

Звучит просто, но я застрял в слиянии двух групп. Как вы это сделаете с LINQ?

IEnumerable<int> result = Enumerable.Range(0, 1000) 
    .GroupBy(i => i % 2) 
    .Select(p => p.Key == 1 ? p.Reverse() : p) 
    .??? // need to concatenate 

Редактировать

[1,2,3] является представление массива, который я хочу получить в результате, а не выход, извините, если я спутать вас этим.

+0

Что является желаемым результатом? –

+0

описание товара. Я хочу, чтобы '[1,2,3,4,5,6,7,8]' был преобразован в '[7,5,3,1,2,4,6,8]' – klappvisor

+0

@TimSchmelter '[1 , 2,3] '- просто представление или массив, если целые числа. Я обновлю свой пост – klappvisor

ответ

2

Метод GroupBy возвращает IEnumerable<IGrouping<TKey, TSource>>. Поскольку IGrouping реализует IEnumerable, вы можете использовать SelectMany, чтобы объединить несколько экземпляров IEnumerable<T> в один.

Enumerable.Range(0, 1000) 
    .GroupBy(i => i % 2) 
    .Select(p => p.Key == 1 ? p.Reverse() : p) 
    .OrderByDescending(p => p.Key) 
    .SelectMany(p => p); 
+0

С 'SelectMany' я не мог заставить его упорядочиваться, когда сначала идут коэффициенты, поэтому я думаю, что' Aggregate' необходим для использовать ... – klappvisor

+2

Вы можете заказать его перед тем, как сделать SelectMany с 'OrderBy' или' OrderByDescending'. Я добавил его к ответу. – Pidon

1

Вы могли бы использовать этот подход с использованием Lookup<TKey, TElement>:

var evenOddLookup = numbers.ToLookup(i => i % 2); 
string result = String.Join(",", evenOddLookup[1].Reverse().Concat(evenOddLookup[0])); 

Если вы не хотите строку но int[] как результат:

int[] result = evenOddLookup[1].Reverse().Concat(evenOddLookup[0]).ToArray(); 
+0

Поиск интересный вариант, просто нужно иметь в виду [разницу] (http://stackoverflow.com/a/13739501/793874) между ними – klappvisor

+1

@klappvisor: поиск похож на словарь, который возвращает всегда 'IEnumerable ' (пустой, если он недоступен). Таким образом, он имеет очень быструю производительность поиска, и вы можете использовать его без повторного запроса источника данных (так что в памяти) –

0

Вы могли бы сделать что-то вроде этого.

var number = string.Join(",", 
        Enumerable.Range(0, 1000) 
          .GroupBy(i => i % 2)   // Separate even/odd numbers 
          .OrderByDescending(x=>x.Key) // Sort to bring odd numbers first. 
          .SelectMany(x=> x.Key ==1?  // Sort elements based on even or odd. 
              x.OrderByDescending(s=>s) 
              : x.Where(s=> s!=0).OrderBy(s=>s)) 
          .ToArray());   

    string output = string.Format("[{0}]", number); 

Проверить это Demo

0

Просто используйте OrderBy так:

List<int> arr = new List<int> { 1, 2, 3, 4, 5, 6, 7, 8 }; 
var result = arr.OrderBy(i => i % 2 == 0 ? 1 : 0) 
       .ThenBy(i => i % 2 == 0 ? i : int.MaxValue) 
       .ThenByDescending(i => i); 

Это должно дать вам желаемый результат, как вы хотите:

[1,2,3,4,5,6,7,8] will be converted into [7,5,3,1,2,4,6,8] 
+0

Хорошее место, указывающее на то, что исходный вопрос был слишком сложным для заявленной задачи, но OQ заключался в том, как согласовать результаты группы с – MikeT

+0

@MikeT ... Да. Просто посмотрите комментарий OP (* Я хочу, чтобы '[1,2,3,4,5,6,7,8]' был преобразован в '[7,5,3,1,2,4,6,8] '*) Я думаю, что это все, чего хочет OP, и если просто использование' OrderBy' должно делать то, что он хочет. –

+0

@ S.Akbari @MikeT альтернативное решение для этого через «GroupBy» также интересно, не уверен, что порядок наиболее оптимален, хотя ... – klappvisor

1

Есть несколько способов для достижения этой цели,

поэтому, если мы начнем с вашей функции

Enumerable.Range(0, 1000) 
.GroupBy(i => i % 2) 
.Select(p => p.Key == 1 ? p.Reverse() : p) 

вы могли бы использовать агрегатную

.Aggregate((aggrgate,enumerable)=>aggrgate.Concat(enumerable)) 

это будет идти, хотя в списке результатов и Concat их всех в коллекции и вернуть его, вам просто нужно, чтобы убедиться, что aggrgate и перечислимы являются тот же самый тип в данном случае IEnumerable<int>

другое было бы назвать SelectMany()

.SelectMany(enumerable=>enumerable) 

это, то л ikewise тянет все перечислимых вместе в один перечислимы, вы снова должны гарантировать, типы IEnumerable<int>

другие варианты будут жестко закодировать ключи, как Тим предлагая или вытащить из LINQ и использовать цикл

Смежные вопросы