2012-07-26 2 views
3

У меня есть список списков динамики, которые в настоящее время фильтруются через это:Group список в группы по 3 и выбрать максимум из каждой группы

var CPUdataIWant = from s in rawData 
        where s.stat.Contains("CPU") 
        select s; 

//CPUDataIWant is a List<List<dynamic>>. 

У меня есть 86000 значений в каждом внутреннем списке.

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

Так пример того, что я хочу бы:

Raw data = 14,5,7,123,5,1,43,87,9 

И моя обработанное значение будет:

ProceData = [14,5,7], [123,5,1], [43,87,9] 
ProceData = [14,123,87] 

Не должно быть с помощью LINQ, но проще, тем лучше.

EDIT: Хорошо, я объяснил, что нужно немного плохо.

вот что у меня есть:

List<List<object>> 

В этом списке, я буду иметь X количество списков, называемых А. В А у меня будет 86000 значения, скажем, они Интс сейчас.

То, что я хотел бы, чтобы иметь

List<List<object>> 

Но вместо 86000 значения в А, я хочу 28700, который будет сделан из макс каждые 3 значений в А.

+1

Давай, это легко. Итерируйте коллекцию с шагом по три. Проверьте i, i + 1, i + 2, выберите самый большой. Добавьте некоторые граничные проверки. Готово ... – DHN

+1

Можете ли вы немного разобраться, как RawData может быть 14,5,7,123,5,1,43,87,9 ?!разве вы не сказали, что это список списков? – Vitaliy

+0

Хороший вопрос, я основывал свой ответ на примере из 'data'. – phant0m

ответ

0

Это должно дать желаемый результат:

var data = new List<dynamic> { 1, 2, 3, 3, 10, 1, 5, 2, 8 }; 
var firsts = data.Where((x, i) => i % 3 == 0); 
var seconds = data.Where((x, i) => (i + 2) % 3 == 0); 
var thirds = data.Where((x, i) => (i + 1) % 3 == 0); 
var list = firsts.Zip(
    seconds.Zip(
     thirds, (x, y) => Math.Max(x, y) 
    ), 
    (x, y) => Math.Max(x, y) 
).ToList(); 

Список содержит:

3, 10, 8 

Или обобщается метод расширения:

public static IEnumerable<T> ReduceN<T>(this IEnumerable<T> values, Func<T, T, T> map, int N) 
{ 
    int counter = 0; 
    T previous = default(T); 
    foreach (T item in values) 
    { 
     counter++; 
     if (counter == 1) 
     { 
      previous = item; 
     } 
     else if (counter == N) 
     { 
      yield return map(previous, item); 
      counter = 0; 
     } 
     else 
     { 

      previous = map(previous, item); 
     } 
    } 

    if (counter != 0) 
    { 
     yield return previous; 
    } 
} 

Используется так:

data.ReduceN(Math.Max, 3).ToList() 
+0

Это было бы страшно медленно. – Hogan

+0

@ Хоган: Можете ли вы объяснить, почему? Он работает на 1 миллион элементов в ~ 80 мс, включая преобразование в список. – phant0m

+0

Первый пример (единственный код, который у вас был, когда я сделал комментарий) работает на O (3n) вместо O (n), я не смотрел на второй. – Hogan

0
IEnumerable<int> filtered = raw.Select((x, i) => new { Index = i, Value = x }). 
    GroupBy(x => x.Index/3). 
    Select(x => x.Max(v => v.Value)); 

или, если вы планируете использовать его чаще

public static IEnumerable<int> SelectMaxOfEvery(this IEnumerable<int> source, int n) 
{ 
    int i = 0; 
    int currentMax = 0; 
    foreach (int d in source) 
    { 
     if (i++ == 0) 
      currentMax = d; 
     else 
      currentMax = Math.Max(d, currentMax); 
     if (i == n) 
     { 
      i = 0; 
      yield return currentMax; 
     } 
    } 
    if (i > 0) 
     yield return currentMax; 
} 

//... 

IEnumerable<int> filtered = raw.SelectMaxOfEvery(3); 
+0

Почему все вложенные выбирает? .... 'GroupBy (x => x.Index/3) .Выберите (x => x.Max (v => v.Value))' –

+0

Я сомневаюсь, что это сработало бы, будучи динамичным, я подозреваю, что содержимое не будет 'IComparable'. – Alex

+0

@BobVale - Правда, это был остаток того, как я построил результат. обновленный – voidengine

0

пользуют школьный способ делать вещи делает его довольно простым (хотя он не такой компактный, как LINQ):

// Based on this spec: "CPUDataIWant is a List<List<dynamic>>" 
// and on the example, which states that the contents are numbers. 
// 
List<List<dynamic>> filteredList = new List<List<dynamic>>(); 
foreach (List<dynamic> innerList in CPUDataIWant) 
{ 
    List<dynamic> innerFiltered = new List<dynamic>(); 

    // if elements are not in multiples of 3, the last one or two won't be checked. 
    for (int i = 0; i < innerList.Count; i += 3) 
    { 
     if(innerList[i+1] > innerList[i]) 
      if(innerList[i+2] > innerList[i+1]) 
       innerFiltered.Add(innerList[i+2]); 
      else 
       innerFiltered.Add(innerList[i+1]); 
     else 
      innerFiltered.Add(innerList[i]); 
    } 
    filteredList.Add(innerFiltered); 
} 
0

Если вы почувствовали необходимость использования Aggregate вы могли бы сделать это следующим образом:

(протестировано Wiht LINQPad)

class Holder 
{ 
     public dynamic max = null; 
     public int count = 0; 
} 

void Main() 
{ 
    var data = new List<dynamic> 
     {new { x = 1 }, new { x = 2 }, new { x = 3 }, 
     new { x = 3 }, new { x = 10}, new { x = 1 }, 
     new { x = 5 }, new { x = 2 }, new { x = 1 }, 
     new { x = 1 }, new { x = 9 }, new { x = 3 }, 
     new { x = 11}, new { x = 10}, new { x = 1 }, 
     new { x = 5 }, new { x = 2 }, new { x = 12 }}; 

    var x = data.Aggregate(
     new LinkedList<Holder>(), 
     (holdList,inItem) => 
     { 
      if ((holdList.Last == null) || (holdList.Last.Value.count == 3)) 
      { 
      holdList.AddLast(new Holder { max = inItem, count = 1}); 
      } 
      else 
      { 
      if (holdList.Last.Value.max.x < inItem.x) 
       holdList.Last.Value.max = inItem; 

      holdList.Last.Value.count++; 
      } 
      return holdList; 
     }, 
     (holdList) => { return holdList.Select((h) => h.max);}); 

    x.Dump("We expect 3,10,5,9,11,12"); 
} 
Смежные вопросы