按列组计算从Linq WPF中的另一列中重复的值[英] Group by column to count duplicated values from another column in LINQ WPF

本文是小编为大家收集整理的关于按列组计算从Linq WPF中的另一列中重复的值的处理/解决方法,可以参考本文帮助大家快速定位并解决问题,中文翻译不准确的可切换到English标签页查看源文。

问题描述

我有以下表作为我的输入.

+--------+---------+-------+
|  Name  | Course  | Score |
+--------+---------+-------+
| John   | Math    |     5 |
| Hannah | Math    |     4 |
| Lilly  | Math    |     5 |
| John   | Science |     5 |
| Hannah | Science |     5 |
| Lilly  | Science |     5 |
| John   | Social  |     5 |
| Hannah | Social  |     4 |
| Lilly  | Social  |     3 |
+--------+---------+-------+

作为输出,我想拥有一张表格,可以显示名称,总分,得分平均值和星星.明星将是学生得分5/5的次数.因此,例如,约翰应该有3颗星,而汉娜应该有1星,莉莉应该有2.基本上,我想将下表作为我的输出:

+--------+-------+---------+------+
|  Name  | Score | Average | Star |
+--------+-------+---------+------+
| John   |    15 |       5 |    3 |
| Hannah |    13 |     4.3 |    1 |
| Lilly  |    13 |     4.3 |    2 |
+--------+-------+---------+------+

我能够获得得分和平均水平,但我无法弄清楚如何做星星.从编程上讲,我认为我需要按名称进行分组,然后计算重复的数字,我认为应该在LINQ中完成,但我不确定该怎么做:

这是我的代码:

public string Name { get; private set; }
public int Score { get; set; }
public decimal Average { get; set; }
public decimal Count { get; set; }

public Person(string name, int score, decimal avg, int count)
{
    Name = name;
    Score = score;
    Average = avg;
    Count = count;
}
public ObservableCollection<Person> Persons { get; set; }
filepath = scoresFile; 

public MainWindow()
{

    InitializeComponent();
    LoadTable();
}

private void datagrid_Sorting(object sender, DataGridSortingEventArgs e)
{
    if (e.Column.Header.Equals("Name") || e.Column.Header.Equals("Score"))
    {
        e.Handled = true;
    }
}

public void LoadTable()
{
    var lines = File.ReadAllLines(filepath);
    Persons = new ObservableCollection<Person>();
    var data = lines.Select(line =>
    {

        var column = line.Split(',');
        int c = column[1].Count(); 
              var name = column[1];
        int score = int.Parse(column[3]);
        decimal avg = decimal.Parse(column[3]);
        int count = 0; 
        return new { name, score, avg, count};

    }
    );
    var groupedData = data.GroupBy(p => p.name)
            .Select((g, i) => new { 
                    num= 0, name = g.Key, 
                    score = g.Sum(p => p.score), 
                    avg = decimal.Round(g.Average(p => p.avg), 1), 
                    count = g.Count() })
            .OrderByDescending(x => x.avg);

    var persons = groupedData.Select((p, i) => new Person(i + 1, p.name, p.score, p.avg, p.count));


    foreach (var person in persons)
    {
        Persons.Add(person);
    }

    datagrid.ItemsSource = Persons;  
}

我一直在尝试对Linq系列进行一些修改,但我认为这不是一个好主意:

        var groupedData = data.GroupBy(p => p.name, s=> s.score )
              .Where(p => p.Count() > 5).Select((g, i) => new { 
                    num= 0, 
                    name = g.Key, 
                    rank = i + 1, 
                    score = g.Sum(p => p.score), 
                    avg = decimal.Round(g.Average(p => p.avg), 1), 
                    count = g.Count() })
              .OrderByDescending(x => x.avg);

然后,我想到添加以下行并调用num,但这也没有起作用.

       var num = data.GroupBy(p => p.name, p =p.score).Any(g => g.Count() > 1);

有什么想法?

推荐答案

您可以在计数之前使用子句. 尝试以下查询

        var Output = StudentCourseDetails.GroupBy(a => a.Name).Select(ag => new
        {
            Name = ag.Key,
            Score = ag.Sum( i => i.Score),
            Average = ag.Average(i => i.Score),
            Star = ag.Where(i=> i.Score == 5).Count()
        });

其他推荐答案

您可以尝试一下,您不需要分数,因为您想总结所有这些,并且要计算收到的5星数,您只需要做

var data = from std in students
 group by std.Name
 into grp 
 select new {
   name = grp.key,
   score = grp.Sum(s=> s.Score),
   avg = decimal.Round(grp.Average(s => s.avg), 1),
   star = grp.Count(s=> s.Score == 5)
   Report = ReviewText(grp.Count(s=> s.Score == 5) )
 };

private string ReviewText(int count)
{
  if(count >= 3)
   return "Excellent";
  else if (count ==2)
      return "Good";
  else 
      return string.Empty;
}

或其他方式

var Output = students.GroupBy(std => std.Name)
             .Select(grp => new
             {
               Name = grp.Key,
               Score = grp.Sum( i => i.Score),
               Average = decimal.Round(grp.Average(s => s.avr),1),
               Star = grp.Count(i=> i.Score == 5)
            });

其他推荐答案

以下代码将对您有所帮助,

var result = (from s in data
              group s by  s.Name 
              into grp 
              select new {
                 name =  grp.Key,
                 score = grp.Sum(s=> s.Score),
                 avg =   decimal.Round(grp.Average(s =>Convert.ToDecimal(s.Score)),1,MidpointRounding.AwayFromZero),
                 star =  grp.Where(s=> s.Score == 5).Count()
              }).ToList();
Console.WriteLine(result);

var result =  data.GroupBy(s=>s.Name).Select(g=>new{g.Key,score = g.Sum(s=> s.Score),avg= decimal.Round(g.Average(s =>Convert.ToDecimal(s.Score)),1,MidpointRounding.AwayFromZero),star =  g.Where(s=> s.Score == 5).Count()});
Console.WriteLine(result);

本文地址:https://www.itbaoku.cn/post/1557000.html

问题描述

I have the below table as my input.

+--------+---------+-------+
|  Name  | Course  | Score |
+--------+---------+-------+
| John   | Math    |     5 |
| Hannah | Math    |     4 |
| Lilly  | Math    |     5 |
| John   | Science |     5 |
| Hannah | Science |     5 |
| Lilly  | Science |     5 |
| John   | Social  |     5 |
| Hannah | Social  |     4 |
| Lilly  | Social  |     3 |
+--------+---------+-------+

and as an output, I want to have a table that will show the name, total score, average of the score and star. The star will be the number of times the student scored 5/5. So for example, John should have 3 stars, whereas Hannah should have 1 and Lilly should have 2. Basically, I want to have the below table as my output:

+--------+-------+---------+------+
|  Name  | Score | Average | Star |
+--------+-------+---------+------+
| John   |    15 |       5 |    3 |
| Hannah |    13 |     4.3 |    1 |
| Lilly  |    13 |     4.3 |    2 |
+--------+-------+---------+------+

I was able to get the score and average, but i just cant figure out how to do the stars part. Programatically, I think i need to group by names and then count duplicated numbers, and I think it should be done in linq but i am not sure how to do that yet:

Here's my code:

public string Name { get; private set; }
public int Score { get; set; }
public decimal Average { get; set; }
public decimal Count { get; set; }

public Person(string name, int score, decimal avg, int count)
{
    Name = name;
    Score = score;
    Average = avg;
    Count = count;
}
public ObservableCollection<Person> Persons { get; set; }
filepath = scoresFile; 

public MainWindow()
{

    InitializeComponent();
    LoadTable();
}

private void datagrid_Sorting(object sender, DataGridSortingEventArgs e)
{
    if (e.Column.Header.Equals("Name") || e.Column.Header.Equals("Score"))
    {
        e.Handled = true;
    }
}

public void LoadTable()
{
    var lines = File.ReadAllLines(filepath);
    Persons = new ObservableCollection<Person>();
    var data = lines.Select(line =>
    {

        var column = line.Split(',');
        int c = column[1].Count(); 
              var name = column[1];
        int score = int.Parse(column[3]);
        decimal avg = decimal.Parse(column[3]);
        int count = 0; 
        return new { name, score, avg, count};

    }
    );
    var groupedData = data.GroupBy(p => p.name)
            .Select((g, i) => new { 
                    num= 0, name = g.Key, 
                    score = g.Sum(p => p.score), 
                    avg = decimal.Round(g.Average(p => p.avg), 1), 
                    count = g.Count() })
            .OrderByDescending(x => x.avg);

    var persons = groupedData.Select((p, i) => new Person(i + 1, p.name, p.score, p.avg, p.count));


    foreach (var person in persons)
    {
        Persons.Add(person);
    }

    datagrid.ItemsSource = Persons;  
}

I have been trying to make some modifications to the linq line but i dont think it would be a good idea:

        var groupedData = data.GroupBy(p => p.name, s=> s.score )
              .Where(p => p.Count() > 5).Select((g, i) => new { 
                    num= 0, 
                    name = g.Key, 
                    rank = i + 1, 
                    score = g.Sum(p => p.score), 
                    avg = decimal.Round(g.Average(p => p.avg), 1), 
                    count = g.Count() })
              .OrderByDescending(x => x.avg);

then i thought of adding the below line and calling num, but that didnt work either.

       var num = data.GroupBy(p => p.name, p =p.score).Any(g => g.Count() > 1);

any ideas?

推荐答案

You can use where clause before taking count. Try below query

        var Output = StudentCourseDetails.GroupBy(a => a.Name).Select(ag => new
        {
            Name = ag.Key,
            Score = ag.Sum( i => i.Score),
            Average = ag.Average(i => i.Score),
            Star = ag.Where(i=> i.Score == 5).Count()
        });

其他推荐答案

can you try this out , you dont need group on score as you want to sum all of them and for counting number of 5 star received you just need to do count of it

var data = from std in students
 group by std.Name
 into grp 
 select new {
   name = grp.key,
   score = grp.Sum(s=> s.Score),
   avg = decimal.Round(grp.Average(s => s.avg), 1),
   star = grp.Count(s=> s.Score == 5)
   Report = ReviewText(grp.Count(s=> s.Score == 5) )
 };

private string ReviewText(int count)
{
  if(count >= 3)
   return "Excellent";
  else if (count ==2)
      return "Good";
  else 
      return string.Empty;
}

or other way

var Output = students.GroupBy(std => std.Name)
             .Select(grp => new
             {
               Name = grp.Key,
               Score = grp.Sum( i => i.Score),
               Average = decimal.Round(grp.Average(s => s.avr),1),
               Star = grp.Count(i=> i.Score == 5)
            });

其他推荐答案

Following code will be helpful to you,

var result = (from s in data
              group s by  s.Name 
              into grp 
              select new {
                 name =  grp.Key,
                 score = grp.Sum(s=> s.Score),
                 avg =   decimal.Round(grp.Average(s =>Convert.ToDecimal(s.Score)),1,MidpointRounding.AwayFromZero),
                 star =  grp.Where(s=> s.Score == 5).Count()
              }).ToList();
Console.WriteLine(result);

Or

var result =  data.GroupBy(s=>s.Name).Select(g=>new{g.Key,score = g.Sum(s=> s.Score),avg= decimal.Round(g.Average(s =>Convert.ToDecimal(s.Score)),1,MidpointRounding.AwayFromZero),star =  g.Where(s=> s.Score == 5).Count()});
Console.WriteLine(result);