2015-11-03 5 views
-2

У меня есть список целых чисел, которые я хотел бы разбить на 2 или более списков на основе соответствия определенным критериям. Например:Разделить список на несколько списков на основе критериев, используя LINQ

List<int> myList = new List<int>(); 
myList.Add(100); 
myList.Add(200); 
myList.Add(300); 
myList.Add(400); 
myList.Add(200); 
myList.Add(500); 

Я хотел бы разделить список на несколько списков, каждый из которых содержит все элементы, общие < = 600. В приведенном выше, было бы затем привести в 3-х отдельных объектах списка.

  • Список 1 будет содержать 100, 200 300
  • Список 2 будет содержать 400, 200
  • Список 3 будет содержать 500

В идеале, я хотел бы, чтобы быть единым LINQ заявление.

+6

Что вы пробовали и почему оно должно быть в linq или даже в одном выражении linq? –

+2

Что вы пробовали? Что сделал этот код? Как это было конкретно? Отличается от того, что вы хотели этого сделать? Наряду с ответами на эти вопросы, пожалуйста, предоставьте [хороший, _minimal_, _complete_ пример кода] (http://stackoverflow.com/help/mcve), который поддерживает эти ответы. Переполнение стека не является кодовым письмом. –

+1

Это невозможно с помощью одного оператора linq, но с одной строкой linq. Или вам нужно реализовать свой собственный допуск для этого. –

ответ

0

Хотя выполнимо, это отличный пример того, что LINQ является не для. Проверь себя.

Имея

var myList = new List<int> { 100, 200, 300, 400, 200, 500, }; 
int maxSum = 600; 

"чистый" LINQ (сила Aggregate)

var result = myList.Aggregate(
    new { Sum = 0, List = new List<List<int>>() }, 
    (data, value) => 
    { 
     int sum = data.Sum + value; 
     if (data.List.Count > 0 && sum <= maxSum) 
      data.List[data.List.Count - 1].Add(value); 
     else 
      data.List.Add(new List<int> { (sum = value) }); 
     return new { Sum = sum, List = data.List }; 
    }, 
    data => data.List) 
    .ToList(); 

нормального (не LINQ) осуществление указанной выше

var result = new List<List<int>>(); 
int sum = 0; 
foreach (var value in myList) 
{ 
    if (result.Count > 0 && (sum += value) <= maxSum) 
     result[result.Count - 1].Add(value); 
    else 
     result.Add(new List<int> { (sum = value) }); 
} 

Для полноты (и какая-то забава), «Hackish» LINQ (мощность замыканий и операторов C#)

int sum = 0, key = -1; 
var result = myList.GroupBy(x => key >= 0 && (sum += x) <= maxSum ? key : ++key + (sum = x) * 0, (k, e) => e.ToList()).ToList(); 
0

Вот решение проблемы. Я не уверен, что это лучший случай решатель, но это, безусловно, сделать работу:

List<int> First = myList.Where(x => x <= 300).ToList(); 
List<int> Second = myList.Where(x => x == 400 || x == 200).ToList(); 
List<int> Third = myList.Where(x => x == 500).ToList(); 

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

0

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

List<int> myList = new List<int>(); 
myList.Add(100); 
myList.Add(200); 
myList.Add(300); 
myList.Add(400); 
myList.Add(200); 
myList.Add(500); 

var result = new List<List<int>>(); 
var skip = 0; 
while (skip < myList.Count) 
{ 
    var sum = 0; 
    result.Add(myList.Skip(skip).TakeWhile(x => 
    { 
     sum += x; 
     return sum <= 600; 
    }).ToList()); 
    skip += result.Last().Count(); 
} 
Смежные вопросы