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