Группировка по столбцу для подсчета повторяющихся значений из другого столбца в LINQ WPF

В качестве ввода я использую приведенную ниже таблицу.

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

Любые идеи?

Count принимает предикат, поэтому измените его на count = g.Count(p => p.Score == 5). Полный код будет 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(p => p.Score == 5) }).OrderByDescending(x => x.avg);
user1672994 02.05.2018 14:10

дайте мне знать, отвечу вам работать или нет

Pranay Rana 02.05.2018 14:12

это сработало для вас ???

Pranay Rana 02.05.2018 15:43

@PranayRana Ваше решение разрешит мою проблему, большое спасибо! :) Мне было интересно, знаете ли вы, можно ли добавить оператор if в строку LINQ? Например, если количество баллов, равных 5, равно 3, выведите «Отлично», если 2, то «Хорошо» и так далее ... знаете ли вы, выполнимо ли это? Еще раз спасибо :)

Dr.Bake 06.05.2018 09:09

@ Dr.Bake - обновил мой ответ, пожалуйста, попробуйте, пожалуйста, примите, если сработало для вас

Pranay Rana 07.05.2018 07:22
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
1
5
75
4

Ответы 4

Можете ли вы попробовать это, вам не нужна группа по счету, так как вы хотите суммировать их все, и для подсчета количества полученных 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)
            });

Зачем форсировать реализацию данных с помощью .ToList()?

Mark Schultheiss 02.05.2018 14:34

@MarkSchultheiss - не понимаю ... но если это связано с ToList (), я добавил ToList (), например, если ему нужны данные немедленно

Pranay Rana 02.05.2018 14:35

@MarkSchultheiss - я знаю это, это просто, например, в основном я хочу показать OP, что как он может решить проблему с подсчетом, здесь нет ничего общего с ToList () ... удалено сейчас

Pranay Rana 02.05.2018 14:40

@PranayRana Ваше решение разрешит мою проблему, большое спасибо! :) Мне было интересно, знаете ли вы, можно ли добавить оператор if в строку LINQ? Например, если количество баллов, равных 5, равно 3, выведите «Отлично», если 2, то «Хорошо» и так далее ... знаете ли вы, выполнимо ли это? Еще раз спасибо :)

Dr.Bake 06.05.2018 08:58

Если вы хотите использовать LINQ только для решения этой проблемы, следующее поможет:

 var grp = emp.GroupBy(p => p.Name).Select((g) => new { Name = g.Key, Total = g.Sum(p=>p.Score),
            Star = g.All(p=>p.Score==5)?3:(g.Count(p=>p.Score==5)==2?2:1)});

Спасибо за ответ :) Star = g.All (p => p.Score == 5)? 3: (g.Count (p => p.Score == 5) == 2? 2: 1)}) ; Но не могли бы вы объяснить мне эту строчку? Я этого не совсем понял. еще раз спасибо!

Dr.Bake 06.05.2018 09:00

Вы можете использовать предложение where перед подсчетом. Попробуйте запрос ниже

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

Если вы установите для Traget .NET-Version значение выше 4.7, вы можете использовать ...Select(ag => (Name: ag.Key, Score: ag.Sum(...)...));

RoJaIt 02.05.2018 15:26

Следующий код будет вам полезен,

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

Другие вопросы по теме