代码之家  ›  专栏  ›  技术社区  ›  Simsons

如何在C中透视列表#

  •  0
  • Simsons  · 技术社区  · 6 年前

    我有一份清单,结构如下,

    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)
                                });
    

    3 回复  |  直到 6 年前
        1
  •  4
  •   TheGeneral    6 年前

    如果你事先知道你有多少道具,你可以这样做

    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名称

        2
  •  1
  •   MistyK    6 年前

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

     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);
            }
    

    然后可以对实现IEnumerable的任何类型调用它。您可以选择如何聚合元素。它还支持漂亮的打印,按行/列获取元素。

    In your case you need to do this:
    
     var elements = new List<Element>();
                //fill in with some data
     var pivot = elements.ToPivot(x => x.TimeStamp, x => x.Name, x => x.Sum(y => y.Value));
    

    核心功能就是这个。

    var dic = source
                    .GroupBy(rowSelector)
                    .ToDictionary(x => x.Key, x => x.GroupBy(colSelector).ToDictionary(y => y.Key, y => aggregatFunc(y)));
    

    如果不需要其他功能,请执行以下操作:

     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));
    

    var date = new DateTime(2018,6,6);
    var prop = "Prop1";
    
    dic[date][prop] // will give you a sum for this particular date and prop
    
        3
  •  0
  •   Access Denied    6 年前
     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;
            }