Reputation: 30
I have a list of article data List<Article>
class Article
{
....
public string Author{get; set}
public int ReadingNumber{get; set}
public int LikeNumber{get; set}
public int ForwardingNumber{get; set}
....
}
inputData
List<Article> input = new List<Article>
{
new Article { Author = "author1", ReadingNumber = 49, LikeNumber = 55, ForwardingNumber = 21 },
new Article { Author = "author1", ReadingNumber = 11, LikeNumber = 35, ForwardingNumber = 79 },
new Article { Author = "author2", ReadingNumber = 25, LikeNumber = 77, ForwardingNumber = 39 },
};
Now I don't know how to use Linq or anything others to convert this into Highchart column table data, which is like this:
categories: ['author1','author2']
series: [{
name: 'TotalReadingNumber',
data: [60, 25]
}, {
name: 'TotalLikeNumber',
data: [90, 77]
}, {
name: 'TotalForwardNumber',
data: [100, 39]
}]
I've tired to use linq and Foreach Method to generate data:
var authorData=
(from a in articleList
group a by a.Author into g
select new {
Author = g.Key,
TotalReading = g.Sum(a=>a.ReadingNumber),
TotalLikes = g.Sum(a=>a.LikeNumber),
.......
}).ToList()
Then I use ForEach
Method to get every property I need
var totalReading = new AuthorData()
{
name = "TotalReading",
data = new List<string>()
};
authorData.ForEach(a => totalRead.data.Add(a.TotalRead.ToString()));
At last I combine them into result,
var result =
{
Authors=authorData.Select(a=>a.Author).ToList(),
series = new List<AuthorData>{totalReading,totalLike,totalForwrad.....}
}
I think it's so complicated. How can I simplify this solution?
Upvotes: 1
Views: 78
Reputation: 8743
Unfortunately, you did not specify what your input is and why it should look like the expected output. But I guess this solution should build your expected output. I used reflection to build it. If you add or remove any integer properties, they will automatically be added or removed from your output string.
EDIT: After you edited your question, I saw that you need to calculate sums of your properties. This was not clear in your original question. This is the updated code:
List<Article> input = new List<Article>
{
new Article { Author = "author1", ReadingNumber = 49, LikeNumber = 55, ForwardingNumber = 74 },
new Article { Author = "author1", ReadingNumber = 141, LikeNumber = 78, ForwardingNumber = 38 },
new Article { Author = "author2", ReadingNumber = 106, LikeNumber = 38, ForwardingNumber = 39 },
};
var grouped = input.GroupBy(x => x.Author).Select(x => new
{
Author = x.Key,
TotalReadingNumber = x.Sum(y=>y.ReadingNumber),
TotalLikeNumber = x.Sum(y=>y.LikeNumber),
TotalForwardingNumber = x.Sum(y=>y.ForwardingNumber),
}).ToList();
StringBuilder output = new StringBuilder();
output.AppendLine("xAxis: {");
output.AppendLine("categories: [");
output.AppendLine(string.Join(",", input.Select(x => $"'{x.Author}'")));
output.AppendLine("]");
output.AppendLine("},");
output.Append("series: [");
bool first = true;
foreach(var property in grouped.GetType().GetGenericArguments().First().GetProperties().Where(x => x.PropertyType == typeof(int)))
{
if(!first)
{
output.Append(", ");
}
output.AppendLine("{");
output.AppendLine("name: 'Total" + property.Name + "',");
output.AppendLine("data: [" + string.Join(",", grouped.Select(x => property.GetValue(x))) + "]");
output.Append("}");
first = false;
}
output.AppendLine("]");
If you don't want to use reflection, because you need performance or because you don't want to change your output dynamically when you change your Article
class, you can also use several string.Join
calls like I did with the categories, and hardcode the values like TotalReadingNumber
, TotalLikeNumber
etc.
Online demo: https://dotnetfiddle.net/I88ZHD
Upvotes: 1