ichPotatodeCXY
ichPotatodeCXY

Reputation: 30

Using LINQ to generate Highchart column table data

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

Answers (1)

SomeBody
SomeBody

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

Related Questions