C# 如何在C中透视列表

C# 如何在C中透视列表,c#,.net,linq,pivot,C#,.net,Linq,Pivot,我有一个结构如下的列表 TimeStamp Name Value --------------------------------------- 01/May/2018 Prop1 5 07/May/2018 Prop1 9 01/May/2018 Prop2 8 07/May/2018 Prop2 11 01/May/20

我有一个结构如下的列表

TimeStamp          Name          Value
---------------------------------------     
01/May/2018        Prop1          5
07/May/2018        Prop1          9
01/May/2018        Prop2          8
07/May/2018        Prop2          11
01/May/2018        Prop3          18
07/May/2018        Prop3          7
.....................................................
......................................................
  07/May/2018        Prop(N)      (N)Value
TimeStamp         Prop1      Prop2      Prop3  ....  PropN                         Value
---------------------------------------------------------------------------------------------
01/May/2018        5           8          18           (N)th Value             31+(N)th Value  
07/May/2018        9           11          7             (N)th Value             27+(N)th Value  
我正在尝试将其转换为以下结构

TimeStamp          Name          Value
---------------------------------------     
01/May/2018        Prop1          5
07/May/2018        Prop1          9
01/May/2018        Prop2          8
07/May/2018        Prop2          11
01/May/2018        Prop3          18
07/May/2018        Prop3          7
.....................................................
......................................................
  07/May/2018        Prop(N)      (N)Value
TimeStamp         Prop1      Prop2      Prop3  ....  PropN                         Value
---------------------------------------------------------------------------------------------
01/May/2018        5           8          18           (N)th Value             31+(N)th Value  
07/May/2018        9           11          7             (N)th Value             27+(N)th Value  
编辑: 实际上,这个列表相当大,可以有100个名称,只有在加载到内存中后才能知道这些值。因此,不可能检查@TheGeneral提到的名称,尽管如果我们有有限的值集并且我们事先知道它们,那么它是有效的

我尝试使用分组来实现这一点,但这可能不是方法

var pivotList= customersList.GroupBy(cust => new { cust.Name, cust.Timestamp, cust.Value }).Select(x => new  {
                                TimeStamp = x.Key.Timestamp,
                                Circuit = x.Key.Name,
                                NumData = x.Sum(y=>x.Key.Value)
                            });

为了简洁起见,我粘贴了实际的格式,而不是C列表。

如果你知道之前有多少道具,你可以这样做

var query = myList
    .GroupBy(c => c.TimeStamp)
    .Select(g => new {
        TimeStamp = g.Key,
        Prop1 = g.Where(x => x.Name == "Prop1").Sum(x => x.Value),
        Prop2 = g.Where(x => x.Name == "Prop2").Sum(x => x.Value),
        Prop3 = g.Where(x => x.Name == "Prop3").Sum(x => x.Value),
        Value = g.Sum(c => c.Value)
    });

如果您想知道这个道具列表是动态的,那么您必须在服务器上调用pivot并手动查询它。或者使用子列表和groupby名称

我会在这个问题上加上我的5美分。我实现了一个简单的pivot表类,它完全满足您的需要

 class Program
    {
        static void Main(string[] args)
        {
            var elements = new Element[]
            {
                new Element
                {
                    TimeStamp = new DateTime(2018,5,1),
                    Name = "Prop1",
                    Value = 5,
                },
                 new Element
                {
                    TimeStamp = new DateTime(2018,5,7),
                    Name = "Prop1",
                    Value = 9,
                },
                  new Element
                {
                    TimeStamp = new DateTime(2018,5,1),
                    Name = "Prop2",
                    Value = 8,
                },
                   new Element
                {
                    TimeStamp = new DateTime(2018,5,7),
                    Name = "Prop2",
                    Value = 11,
                },
                    new Element
                {
                    TimeStamp = new DateTime(2018,5,1),
                    Name = "Prop3",
                    Value = 18,
                },
                     new Element
                {
                    TimeStamp = new DateTime(2018,5,7),
                    Name = "Prop3",
                    Value = 18,
                },
            };            
            var pivot = from line in elements
            group line by line.TimeStamp into g
            select new { g.Key, Props=g.Select(el=>new { el.Name, el.Value }).ToArray(), Total = g.Sum(line => line.Value) };
            int propCount = pivot.Max(line => line.Props.Count());
            string[] props = pivot.SelectMany(p => p.Props, (parent, c) => c.Name).Distinct().ToArray();
            Console.Write($"Date\t");
            for (int i = 0; i < propCount; i++)
            {
                Console.Write($"{props[i]}\t");
            }
            Console.Write($"Total");
            Console.WriteLine();

            foreach (var pivotLine in pivot)
            {
                Console.Write($"{pivotLine.Key.ToShortDateString()}\t");
                for (int i = 0; i < propCount; i++)
                {
                    Console.Write($"{pivotLine.Props.FirstOrDefault(p=>p.Name==props[i])?.Value}\t");
                }
                Console.Write($"{pivotLine.Total}\t");
                Console.WriteLine();
            }
        }

        class Element
        {
            public DateTime TimeStamp { get; set; }
            public string Name { get; set; }

            public int Value;
        }
 public static class PivotTable
    {
        public static PivotTable<TRow, TColumn, TValue> Create<TRow, TColumn, TValue>(Dictionary<TRow, Dictionary<TColumn, TValue>> dictionary)
        where TRow : IComparable, IEquatable<TRow>
        where TColumn : IComparable, IEquatable<TColumn>
        {
            return new PivotTable<TRow, TColumn, TValue>(dictionary);
        }
    }
    public class PivotTable<TRow, TColumn, TValue>
        where TRow : IComparable, IEquatable<TRow>
        where TColumn : IComparable, IEquatable<TColumn>
    {
        private readonly Dictionary<TRow, Dictionary<TColumn, TValue>> _dictionary;

        public PivotTable(Dictionary<TRow, Dictionary<TColumn, TValue>> dictionary)
        {
            _dictionary = dictionary;
        }

        public bool HasValue(TRow row, TColumn col)
        {
            return _dictionary.ContainsKey(row) && _dictionary[row].ContainsKey(col);
        }

        public TValue GetValue(TRow row, TColumn col)
        {
            return _dictionary[row][col];
        }

        public string Print()
        {
            var separator = " ";
            var padRight = 15;

            var rows = _dictionary.Keys;
            var columns = _dictionary.SelectMany(x => x.Value.Keys).Distinct().OrderBy(x => x).ToList();

            var sb = new StringBuilder();

            var columnsRow = new[] { "" }.ToList();

            columnsRow.AddRange(columns.Select(x => x.ToString()));

            sb.AppendLine(string.Join(separator, columnsRow.Select(x => x.PadRight(padRight))));

            foreach (var row in rows.OrderBy(x => x))
            {
                sb.Append(row.ToString().PadRight(padRight)).Append(" ");

                foreach (var col in columns.OrderBy(x => x))
                {
                    var val = HasValue(row, col) ? GetValue(row, col).ToString() : default(TValue).ToString();
                    sb.Append(val.PadRight(padRight)).Append(" ");
                }
                sb.AppendLine();
            }

            return sb.ToString();
        }
}

        public class Element
        {
            public DateTime TimeStamp { get; set; }
            public string Name { get; set; }
            public int Value { get; set; }
        }

 public static class Extensions
    {
        public static PivotTable<TRow, TColumn, TValue> ToPivot<TItem, TRow, TColumn, TValue>(
            this IEnumerable<TItem> source,
            Func<TItem, TRow> rowSelector,
            Func<TItem, TColumn> colSelector,
            Func<IEnumerable<TItem>, TValue> aggregatFunc
        )
            where TRow : IComparable, IEquatable<TRow>
            where TColumn : IComparable, IEquatable<TColumn>
        {
            var dic = source
                .GroupBy(rowSelector)
                .ToDictionary(x => x.Key, x => x.GroupBy(colSelector).ToDictionary(y => y.Key, y => aggregatFunc(y)));

            return PivotTable.Create(dic);
        }
如果不需要其他功能,请执行以下操作:

 var dic = elements //Dictionary<DateTime,Dictionary<string,int>>
                    .GroupBy(x=>x.TimeStamp)
                    .ToDictionary(x => x.Key, x => x.GroupBy(x=>x.Name).ToDictionary(y => y.Key, y => y=>y.Sum(z=>z.Value));

如果2018年5月1日Prop1出现两次怎么办?总结还是第一个?@fubo,如果日期重复,那么总结一下。谢谢。可能是重复的谢谢,它回答了这个问题,但有没有一种方法我可以不用手动检查属性名称?因为,在现实中,我会得到一个我无法控制的列表,可能有数百个value@Simsons是的,你可以使用子列表和groupby名称,最好更新你的问题并取消选中你的正确答案标志,这样其他人就可以给它一个提示shot@Simsons对我来说,这是一个新的开始question@fubo,同意,这就是为什么标记为答案。但正如将军建议的那样,答案是不屈不挠的。谢谢你的尝试,但它并没有修改和转换收藏。该对象不是在控制台应用程序上写入逻辑然后显示,而是对列表进行透视/转置。@Simsons透视对象是您要查找的对象。我不认为在没有字典或动态对象的情况下,将内部列表展平是可能的。
var date = new DateTime(2018,6,6);
var prop = "Prop1";

dic[date][prop] // will give you a sum for this particular date and prop