1

我在文本文件中有一个购物清单,如下所示:

BuyerId    Item;
1;         Item1;
1;         Item2;
1;         ItemN;
2;         Item1;
2;         ItemN;
3;         ItemN;

我需要将此列表转换为如下格式:

Item1; Item2; Item3; ...; ItemN    <--- For buyer 1
Item1; ...; ItemN                  <--- For buyer 2
Item1; ...; ItemN                  <--- For buyer 3

首先,我像这样解析 CSV 文件:

IList<string[]> parsedcsv = (from line in lines.Skip(1) 
                             let parsedLine = line.TrimEnd(';').Split(';')
                             select parsedLine).ToList();

然后我用 LINQ 对这些项目进行分组并将它们聚合为最终格式:

IEnumerable<string> buyers = from entry in parsedcsv
                             group entry by entry[0] into cart
                             select cart.SelectMany(c => c.Skip(1))
                                  .Aggregate((item1, item2) => 
                                      item1 + ";" + item2).Trim();

但是,碰巧,BuyerId 不是唯一的,而是在多次重复后重复(例如,它可以像这样重复:1,2,3,4,5,1,2,3,4,5,1 ,2,3 或类似的 1,2,3,1,2,3,1,2)。

没什么大不了的,我可以很容易地解决这个问题,方法是将项目分组在一个循环中,检查我一次只与一个买家打交道:

int lastBatchId = 0;
string currentId = parsedcsv[0][0];
for (int i = 0; i < parsedcsv.Count; i++)
{
    bool last = parsedcsv.Count - 1 == i;
    if (parsedcsv[i][0] != currentId || last)
    {
         IEnumerable<string> buyers = from entry in parsedcsv.Skip(lastBatchId)
              .Take(i - lastBatchId + (last ? 1 : 0))
         ...
         lastBatchId = i;
         currentId = parsedcsv[i][0];
         ...

...但是,这不是最优雅的解决方案。我几乎可以肯定这只能用 LINQ 来完成。

有人可以帮我吗?

谢谢!

4

2 回答 2

1

你应该看看GroupAdjacent

于 2012-09-11T11:28:52.710 回答
0

我不确定这是最好的解决方案,但你说你想要一个纯 Linq 答案,所以在这里你有它:

var result = from r in (

    from l in lines.Skip(1)
    let data = l.Split(new string[]{";"," "}, 
                       StringSplitOptions.RemoveEmptyEntries)
    select new { Id = data.First(), Item = data.Skip(1).First() })
    .Aggregate(new 
                { 
                    Rows = Enumerable.Repeat(new 
                                            { 
                                                Id = string.Empty, 
                                                Items = new List<string>() 
                                            }, 1).ToList(), 
                    LastID = new List<string>() { "" } 
                }, 
                (acc, x) => 
                { 
                    if (acc.Rows[0].Id == string.Empty)
                        acc.Rows.Clear();
                    if (acc.LastID[0] != x.Id)
                        acc.Rows.Add(new 
                                    {
                                        Id = x.Id, 
                                        Items = new List<string>() 
                                    });
                    acc.Rows.Last().Items.Add(x.Item);
                    acc.LastID[0] = x.Id;
                    return acc; 
                }       
    ).Rows
select new 
{ 
    r.Id, 
    Items = string.Join(";", from x in r.Items 
                             select x) 
};

我写得很快,它可以改进,我特别不喜欢它,因为它使用了一些技巧,但它是纯 Linq 并且可以作为一个起点。

于 2012-09-11T14:53:56.137 回答