C # Получение самой популярной комбинации из 2 предметов в коллекции - PullRequest
0 голосов
/ 22 ноября 2018

У меня есть коллекция предметов, вот она:

    ID    ELECT1        ELECT2
    1      FDI           AED     
    2      BPG           AED
    3      AED           FDI
    4      FDI           AED 
    5      GPH           AED
    6      AED           BPG
    7      GPH           FDI

И я хотел бы сгруппировать elect1 и elect2, а затем вывести 2 самых популярных, например. Эти элементы выбираются 3 раза

FDI AED 
AED FDI
FDI AED

И вторая по популярности комбинация -

AED BPG
BPG AED

Таким образом, результат будет

2 Most popular combinations are
    FDI AED 
    AED BPG

Я написал некоторый код, но я не знаю, как ямог бы сделать это

var groups = cStudent.GroupBy(x => new { x.elective1, x.elective2 });    
foreach (var group in groups)
{
    Console.WriteLine("{0} / {1}:", group.Key.elective1, group.Key.elective2);
    foreach (var item in group)
    {
        Console.WriteLine("  {0} ({1})", item.elective1, item.elective2);
    }
}

Так вот, что я получаю с моим кодом, он уже на полпути, просто не знаю, как закончить. IMAGE

Ответы [ 3 ]

0 голосов
/ 22 ноября 2018

ИМХО, самый чистый способ решить эту проблему - реализовать пользовательский компаратор равенства, который обеспечивает необходимую семантику равенства для решения вашей текущей проблемы:

class IgnoreElectiveOrderStudentEqualityComparer 
    : IEqualityComparer<Student>
{
    public bool Equals(Student x, Student y)
        => (x.ElectiveOne == y.ElectiveOne &&
            x.ElectiveTwo == y.ElectiveTwo) ||
           (x.ElectiveOne == y.ElectiveTwo &&
            x.ElectiveTwo == y.ElectiveOne);

    public int GetHashCode(Student obj)
        => obj.ElectiveOne.GetHashCode() ^
           obj.ElectiveTwo.GetHashCode();
}

А теперь вы просто используете GroupBy и пользовательский компаратор:

var mostPopular = 
    students.GroupBy(s => s,
                     new IgnoreElectiveOrderStudentEqualityComparer())
            .OrderByDescending(g => g.Count())
            .Select(g => new
            {
                g.Key.ElectiveOne, 
                g.Key.ElectiveTwo
            })
            .Take(2);
0 голосов
/ 22 ноября 2018

Хитрость в том, чтобы иметь порядок двух факультативов, не имеющих значения, поэтому альфа-первый всегда первый (таким образом, если у вас есть (математика, искусство), он такой же, как (искусство, математика):

var most_pop = cStudent.GroupBy(x => { if (string.Compare(x.elective1,x.elecitive2) > 0) 
                                         return(new Tuple(x.elective1.x.elective2);
                                       else
                                         return(new Tuple(x.elective2,x.elective1);
                                     },
                                (b, a) => new {  Key = b, Count = a.Count() })
                .OrderyByDesending(x => x.Count).Take(2);

Вы можете добавить выбор ключа, если вы не хотите, чтобы объект с количеством.

0 голосов
/ 22 ноября 2018

Это должно работать для вас:

cStudent
    .Select(x => new[] { x.elective1, x.elective2 }.OrderBy(y => y).ToArray())
    .GroupBy(x => Tuple.Create(x[0], x[1]), (k, g) => new { Elective = k, Count = g.Count() })
    .OrderByDescending(x => x.Count)
    .Select(x => new { elective1 = x.Elective.Item1, elective2 = x.Elective.Item2 })
    .Take(2)
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...