использование Linq для разделения данных в массивы

У меня есть массив элементов, где элемент имеет Отмеченное булево значение.

1 flagged
2 not flagged
3 not flagged
4 flagged
5 not flagged
6 not flagged
7 not flagged
8 flagged
9 not flagged

Я хочу повредить его в массивы на основе отмеченного индикатора

вывод>

array 1 {1,2,3}
array 2 {4,5,6,7}
array 3 {8,9}
6
задан Kenoyer130 8 April 2010 в 21:01
поделиться

5 ответов

У меня была аналогичная проблема с этим, и я решил ее, используя GroupBy и закрытие.

//sample data
var arrayOfElements = new[] {
    new { Id = 1, Flagged = true },
    new { Id = 2, Flagged = false },
    new { Id = 3, Flagged = false },
    new { Id = 4, Flagged = true },
    new { Id = 5, Flagged = false },
    new { Id = 6, Flagged = false },
    new { Id = 7, Flagged = false },
    new { Id = 8, Flagged = true },
    new { Id = 9, Flagged = false }
};

//this is the closure which will increase each time I see a flagged
int flagCounter = 0;

var query = 
    arrayOfElements.GroupBy(e => 
        {
            if (e.Flagged)
                flagCounter++;
            return flagCounter;
        });

Он группирует по типу int ( flagCounter ), который увеличивается каждый раз, когда обнаруживается помеченный элемент.
Обратите внимание, что это не будет работать с AsParallel () .

Проверка результатов:

foreach(var group in query)
{
    Console.Write("\r\nGroup: ");
    foreach (var element in group)
        Console.Write(element.Id);
}

Выходы:

Группа: 123
Группа: 4567
Группа: 89

5
ответ дан 8 December 2019 в 16:00
поделиться

Linq не имеет для этого оператора, но я написал метод расширения, который вы можете использовать (в процессе отправки его на MoreLinq , который вам также следует проверить ):

Используя приведенный ниже оператор, вы должны написать:

var result = 
   items.Segment( (item,prevItem,idx) => item.Flagged )
        .Select( seq => seq.ToArray() )  // converts each sequence to an array
        .ToList();

Вот код метода расширения:

public static IEnumerable<IEnumerable<T>> Segment<T>(IEnumerable<T> sequence, Func<T, T, int, bool> newSegmentIdentifier) 
     { 
         var index = -1; 
         using (var iter = sequence.GetEnumerator()) 
         { 
             var segment = new List<T>(); 
             var prevItem = default(T); 

             // ensure that the first item is always part 
             // of the first segment. This is an intentional 
             // behavior. Segmentation always begins with 
             // the second element in the sequence. 
             if (iter.MoveNext()) 
             { 
                 ++index; 
                 segment.Add(iter.Current); 
                 prevItem = iter.Current; 
             } 

             while (iter.MoveNext()) 
             { 
                 ++index; 
                 // check if the item represents the start of a new segment 
                 var isNewSegment = newSegmentIdentifier(iter.Current, prevItem, index); 
                 prevItem = iter.Current; 

                 if (!isNewSegment) 
                 { 
                     // if not a new segment, append and continue 
                     segment.Add(iter.Current); 
                     continue; 
                 } 
                 yield return segment; // yield the completed segment 

                 // start a new segment... 
                 segment = new List<T> { iter.Current }; 
             } 
             // handle the case of the sequence ending before new segment is detected 
             if (segment.Count > 0) 
                 yield return segment; 
         } 
     } 
7
ответ дан 8 December 2019 в 16:00
поделиться

Учитывая:

var arrayOfElements = new[] {
    new { Id = 1, Flagged = true },
    new { Id = 2, Flagged = false },
    new { Id = 3, Flagged = false },
    new { Id = 4, Flagged = true },
    new { Id = 5, Flagged = false },
    new { Id = 6, Flagged = false },
    new { Id = 7, Flagged = false },
    new { Id = 8, Flagged = true },
    new { Id = 9, Flagged = false }
};

Вы можете написать:

var grouped = 
    from i in arrayOfElements
    where i.Flagged
    select 
        (new[] { i.Id })
        .Union(arrayOfElements.Where(i2 => i2.Id > i.Id).TakeWhile(i2 => !i2.Flagged).Select(i2 => i2.Id))
        .ToArray();

Это работает, если ваши элементы упорядочены по атрибуту Id. Если они этого не сделают, вам придется внедрить последовательность в исходный массив, что также должно быть легко сделать с помощью linq, поэтому вы получите последовательность.

Также лучшей альтернативой должно быть:

// for each flagged element, slice the array,
// starting on the flagged element until the next flagged element
var grouped = 
    from i in arrayOfElements
    where i.Flagged
    select 
        arrayOfElements
            .SkipWhile(i2 => i2 != i)
            .TakeWhile(i2 => i2 == i || !i2.Flagged)
            .Select(i2 => i2.Id)
            .ToArray();

Обратите внимание, что в этих ответах используется чистый linq.

2
ответ дан 8 December 2019 в 16:00
поделиться

Я не думаю, что LINQ является подходящим инструментом для этого. задача. А как насчет этого:

public static List<List<T>> PartitionData<T>(T[] arr, Func<T, bool> flagSelector){
    List<List<T>> output = new List<List<T>>();
    List<T> partition = null;
    bool first = true;

    foreach(T obj in arr){
        if(flagSelector(obj) || first){
            partition = new List<T>();
            output.Add(partition);
            first = false;
        }
        partition.Add(obj);
    }

    return output;
}

Небольшой пример с сообщением «Данные из сообщения Фабио Батистаса»:

var arrayOfElements = new[] {
    new { Id = 1, Flagged = true },
    new { Id = 2, Flagged = false },
    new { Id = 3, Flagged = false },
    new { Id = 4, Flagged = true },
    new { Id = 5, Flagged = false },
    new { Id = 6, Flagged = false },
    new { Id = 7, Flagged = false },
    new { Id = 8, Flagged = true },
    new { Id = 9, Flagged = false }
};

var partitioned = PartitionData(arrayOfElements, x => x.Flagged);
1
ответ дан 8 December 2019 в 16:00
поделиться

Я не думаю, что LINQ подходит для этого очень хорошо. Это можно сделать с помощью Aggregate (), но я думаю, вам лучше просто зацикливаться с foreach () для получения результата.

0
ответ дан 8 December 2019 в 16:00
поделиться
Другие вопросы по тегам:

Похожие вопросы: