pkfox Ответов: 1

Подсчет элементов в списке & lt;string>


Привет всем, у меня есть коллекция строк в общем списке.
H,1000,28-09-2017
L,30,Pete
L,50,Pete
H,200,29-09-2017
L,35,Pete
L,45,Pete
L,55,Pete
etc....


Как я могу ( используя Linq, если это возможно ) подсчитать количество строк "L" между каждой строкой "H" при повторении списка ? В основном "H" указывает на начало группы, содержащей n подробных строк, например, для первой группы я хотел бы сформировать строку типа
H,1000,28-09-2017,80,Pete,2 - where 2 = the number of L lines and 80 the sum of the amounts


Что я уже пробовал:

В настоящее время я делаю это в цикле while суммируя и подсчитывая по ходу дела

1 Ответов

Рейтинг:
8

Richard Deeming

Я сильно подозреваю, что регулярная петля будет вашим лучшим вариантом. Но если вы действительно хотите заставить его:

IEnumerable<string> headerLinesWithCounts = source
    .Select((value, index) => (value: value, index: index))
    .Where(pair => pair.value[0] == 'H')
    .Select(pair => (value: pair.value, lines: source.Skip(pair.index + 1).TakeWhile(v => v[0] != 'H')))
    .Select(pair => $"{pair.value},{pair.lines.Count()}");
Выход:
H,1000,28-09-2017,2 
H,200,29-09-2017,3 

Или, если вам нужно включить строки В вывод, а также:
IEnumerable<string> headerLinesWithCounts = source
    .Select((value, index) => (value: value, index: index))
    .Where(pair => pair.value[0] == 'H')
    .Select(pair => (value: pair.value, lines: source.Skip(pair.index + 1).TakeWhile(v => v[0] != 'H')))
    .Select(pair => (header: $"{pair.value},{pair.lines.Count()}", lines: pair.lines))
    .SelectMany(pair => Enumerable.Repeat(pair.header, 1).Concat(pair.lines));
Выход:
H,1000,28-09-2017,2 
L,30,Pete 
L,50,Pete 
H,200,29-09-2017,3 
L,35,Pete 
L,45,Pete 
L,55,Pete 


NB: Это использование нового ValueTuple[^] тип. Если ваш компилятор не поддерживает его, вы можете использовать вместо него анонимные типы.


pkfox

Спасибо, Ричард, я постараюсь

pkfox

Привет, Ричард, это очень приятно - как я могу сложить сумму L строк ?

Richard Deeming

Что вы подразумеваете под суммой линий?

pkfox

Значения в L строках 30,35 и т. д...

Richard Deeming

Создайте функцию для извлечения значения из строки:

static int ExtractLineValue(string line)
{
    int index = line.IndexOf(',', 2);
    if (index == -1) index = line.Length;
    string part = line.Substring(2, index - 2);
    int.TryParse(part, out int result);
    return result;
}

Затем добавьте сумму в строки заголовка:
IEnumerable<string> linesWithCountsAndSums = source
    .Select((value, index) => (value: value, index: index))
    .Where(pair => pair.value[0] == 'H')
    .Select(pair => (value: pair.value, lines: source.Skip(pair.index + 1).TakeWhile(v => v[0] != 'H')))
    .Select(pair => (header: $"{pair.value},{pair.lines.Count()},{pair.lines.Sum(ExtractLineValue)}", lines: pair.lines))
    .SelectMany(pair => Enumerable.Repeat(pair.header, 1).Concat(pair.lines));

pkfox

Редактировать
Извините, Ричард, он действительно производит суммы - большое вам спасибо за вашу помощь


Привет, Ричард, спасибо за ваше время - это произвело значения L, но не их сумму , чего я пытаюсь достичь

Сек,1000,28-09-2017,2,80
Л, 30, Пит
Л, 50, Пит
Сек,200,29-09-2017,3,135
Л, 35 Лет, Пит
Л, 45, Пит
Л, 55, Пит

Richard Deeming

Это именно тот результат, который дает код из моего последнего комментария:
Демонстрация[^]
(NB: .NET Fiddle, похоже, не поддерживает кортежи значений, поэтому вместо этого мне пришлось использовать анонимные типы.)

using System;
using System.Collections.Generic;
using System.Linq;

public class Program
{
    public static void Main()
    {
        var source = new List<string>
        {
            "H,1000,28-09-2017", 
            "L,30,Pete", 
            "L,50,Pete", 
            "H,200,29-09-2017", 
            "L,35,Pete", 
            "L,45,Pete", 
            "L,55,Pete", 
        };
        
        IEnumerable<string> linesWithCountsAndSums = source
            .Select((value, index) => new { value, index })
            .Where(pair => pair.value[0] == 'H')
            .Select(pair => new { pair.value, lines = source.Skip(pair.index + 1).TakeWhile(v => v[0] != 'H') })
            .Select(pair => new { header = $"{pair.value},{pair.lines.Count()},{pair.lines.Sum(ExtractLineValue)}", lines = pair.lines })
            .SelectMany(pair => Enumerable.Repeat(pair.header, 1).Concat(pair.lines));
        
        foreach (string line in linesWithCountsAndSums)
        {
            Console.WriteLine(line);
        }
    }

    static int ExtractLineValue(string line)
    {
        int index = line.IndexOf(',', 2);
        if (index == -1) index = line.Length;
        string part = line.Substring(2, index - 2);
        int.TryParse(part, out int result);
        return result;
    }
}
Выход:
H,1000,28-09-2017,2,80
L,30,Pete
L,50,Pete
H,200,29-09-2017,3,135
L,35,Pete
L,45,Pete
L,55,Pete

pkfox

Я действительно исправил свой комментарий, Ричард, это именно то, что я хотел, где вы узнали все эти вещи Linq ? это блестяще

jaket-cp

договорились гениальное - 5 ЕД

Richard Deeming

Помощью linqpad[^] вероятно, это было бы хорошим местом для начала. :)

pkfox

У меня есть LinqPad, который великолепен, но мне нужно лучше понимать Linq - в настоящее время я смотрю серию учебных пособий на Youtube, которые помогают, но это не до вашего уровня - где вы изучили Linq ? или это случай RTFM :-)

Richard Deeming

В основном читаю документы и играю с примерами запросов в LINQPad. :)