Linq集团的数据在扁平化数字中可见

时间:2017-01-25 14:17:30

标签: c# .net linq

Period|1|
AA|0|0|32.39|0|0|-0.12|
BB|0|-1794.62|
CC|Entity1|25|31.48|244.1|
DD|Entity2|25|0|0|
Period|2|
AA|0|0|32.39|0|0|-0.12|
BB|0|-1794.62|
CC|Entity1|25|31.48|244.1|
EE|Entity2|25|0|0|
FF|Entity3|25|0|0|
GG|Entity4|25|0|0|
HH|Entity5|25|0|0|
Period|3|
AA|0|0|32.39|0|0|-0.12|
BB|0|-1794.62|

将上述集合视为:

IEnumerable<IEnumerable<string>> data;

First Enumerable是每一行。 Second Enumerable是由分隔符|

分隔的每一行

我想在每个时期对此进行分组:

预期结果:

Period1 (Group Key)
         AA|0|0|32.39|0|0|-0.12|
         BB|0|-1794.62|
         CC|Entity1|25|31.48|244.1|
         DD|Entity2|25|0|0|
Period2 (Group Key)
         AA|0|0|32.39|0|0|-0.12|
         BB|0|-1794.62|
         CC|Entity1|25|31.48|244.1|
         EE|Entity2|25|0|0|
         FF|Entity3|25|0|0|
         GG|Entity4|25|0|0|
         HH|Entity5|25|0|0|
Period3 (Group Key)
        AA|0|0|32.39|0|0|-0.12|
        BB|0|-1794.62|

目前的实施:

foreach (var dataPerPeriod in data.Take(5))
{
    yield return new DataPerPeriod(dataPerPeriod);
}

但是你可以看到只有第一个句号有5个元素,包括想成为关键元素(句号)。

因此我不明白如何解决这个问题。

4 个答案:

答案 0 :(得分:4)

我已为您的DataPerPeriod制作了帮助类:

public class DataPerPeriod
{
    public string Name { get; set; }
    public List<IEnumerable<string>> Lines { get; set;}
}

我可以用这个查询聚合它:

var res = data.Aggregate(new List<DataPerPeriod>(), (a, b) =>
{
    if (b.First() =="Period")
    {
        a.Add(new DataPerPeriod { Name = String.Join("", b),
                                  Lines = new List<IEnumerable<string>>() });
    }
    else
    {
        a.Last().Lines.Add(b);
    }
    return a;
});

结果是:

enter image description here

答案 1 :(得分:2)

不是纯粹的LINQ,而是借助于“LINQ spirit”自定义泛型扩展方法,它允许您根据条件拆分(分区)序列:

public static class LinqExtensions
{
    public static IEnumerable<IEnumerable<T>> Split<T>(this IEnumerable<T> source, Func<T, bool> splitOn)
    {
        using (var e = source.GetEnumerator())
        {
            for (bool more = e.MoveNext(); more;)
            {
                var group = new List<T> { e.Current };
                while ((more = e.MoveNext()) && !splitOn(e.Current))
                    group.Add(e.Current);
                yield return group;
            }
        }
    }
}

具体问题可以通过以下方式轻松解决:

IEnumerable<IEnumerable<string>> source = ...;
var result = source
    .Split(e => e.FirstOrDefault() == "Period")
    .Select(g => new
    {
        Key = g.First().Skip(1).FirstOrDefault(),
        Elements = g.Skip(1)
    });

答案 2 :(得分:1)

不是特别优雅(但是,你的数据集也不是这样)但是这样可行:

public static Dictionary<IEnumerable<string>,IEnumerable<IEnumerable<string>>> Parse(IEnumerable<IEnumerable<string>> input)
{
    IEnumerable<string> key = null;
    var rows = new List<IEnumerable<string>>();
    var result = new Dictionary<IEnumerable<string>,IEnumerable<IEnumerable<string>>>();

    foreach(var row in input)
    {
        if(row.First().StartsWith("Period"))
        {
            if(key != null)
                result.Add(key,rows.AsEnumerable());

            key = row;
            rows = new List<IEnumerable<string>>();
        }
        else
        {
            rows.Add(row);
        }
    }
    result.Add(key,rows);
    return result;
}

实例:http://rextester.com/ZMUM90524

答案 3 :(得分:0)

我已经解析了40年的文本文件了。如果我做不到,没人能。我的解决方案几乎与Jamiec的风格略有不同

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;



namespace ConsoleApplication43
{
    class Program
    {
        const string FILENAME = @"c:\temp\test.txt";
        static void Main(string[] args)
        {
            StreamReader reader = new StreamReader(FILENAME);
            string inputLine = "";

            Dictionary<string, List<string>> data = new Dictionary<string, List<string>>();

            List<string> period = null;
            while ((inputLine = reader.ReadLine()) != null)
            {
                inputLine = inputLine.Trim();
                if (inputLine.Length > 0)
                {
                    if (inputLine.StartsWith("Period"))
                    {
                        string key = inputLine.Replace("|", "");
                        period = new List<string>();
                        data.Add(key, period);
                    }
                    else
                    {
                        period.Add(inputLine);
                    }
                }
            }
        }
    }
}