2
votes

Recherche de plusieurs correspondances uniques à partir de la liste où deux critères doivent être différents

J'ai du mal à sélectionner le premier élément dans une liste qui est unique basée sur deux champs, JOB_ID et EMPLOYEE_ID.

Chaque emploi ne doit être attribué qu'à un seul employé (celui avec le OVERALL_SCORE le plus bas), puis continuez et affectez le prochain employé.

Les objets de liste sont les suivants:

JobMatch.cs

var FirstOrder = (rankings.GroupBy(u => u.JOB_ID)
.Select(g => g.First())).ToList();

var SecondOrder = (FirstOrder.GroupBy(u => u.EMPLOYEE_ID)
.Select(g => g.First())).ToList(); 
EmployeeMatch.cs
+--------+-------------+---------------+
| JOB_ID | EMPLOYEE_ID | OVERALL_SCORE |
+--------+-------------+---------------+
|      4 |           3 |           800 |
|      3 |           1 |           800 |
|      2 |           2 |          1800 |
+--------+-------------+---------------+

Rankings.cs

+--------+-------------+---------------+
| JOB_ID | EMPLOYEE_ID | OVERALL_SCORE |
+--------+-------------+---------------+
|      4 |           3 |           800 |
|      4 |           4 |           800 |
|      3 |           1 |           800 |
|      3 |           2 |          1200 |
|      2 |           1 |          1600 |
|      2 |           2 |          1800 |
|      4 |           1 |          2000 |
|      4 |           2 |          2100 |
|      1 |           1 |          6400 |
+--------+-------------+---------------+

Rankings.cs obtient un score global basé sur le champ du temps de trajet et nombre de correspondances pour un employé / un poste.

EmployeeMatch.cs

+--------+-------------------+
| JOB_ID | JOB_MATCHES_COUNT |
+--------+-------------------+
|      1 |                 1 |
|      2 |                 2 |
|      3 |                 2 |
|      4 |                 4 |
+--------+-------------------+

+-------------+-------------------+
| EMPLOYEE_ID | EMP_MATCHES_COUNT |
+-------------+-------------------+
|           3 |                 1 |
|           4 |                 1 |
|           2 |                 3 |
|           1 |                 4 |
+-------------+-------------------+

Ranking.cs (raccourci pour ne pas remplir l'écran)

public int JOB_ID { get; set; }
public int EMPLOYEE_ID { get; set; }
public int TRAVEL_TIME_MINUTES { get; set; }
public int PRIORITY { get; set; }
public int OVERALL_SCORE { get; set; }

Fondamentalement, l'idée est de sélectionner le premier Employé et poste uniques dans cette liste, puis les meilleures correspondances seront placées dans une liste séparée, quelque chose comme ce qui suit pour le scénario ci-dessus:

public int EMPLOYEE_ID { get; set; }
public int EMPLOYEE_MATCHES_COUNT { get; set; }

J'ai essayé ce qui suit mais n'a pas fonctionné comme prévu:

public int JOB_ID { get; set; }
public int JOB_MATCHES_COUNT { get; set; }


0 commentaires

3 Réponses :


0
votes

En gros, vous pouvez utiliser la méthode System.Linq.Distinct renforcée avec le comparateur d'égalité personnalisé IEqualityComparer . Le System.Linq fournit cette méthode prête à l'emploi.

rankings.Distinct(new Comparer())

L'astuce ici est avec la méthode GetHashCode , puis aussi simple comme ceci

public class Comparer : IEqualityComparer<Ranking>
{
    public bool Equals(Ranking l, Ranking r)
    {
        return l.JOB_ID == r.JOB_ID || l.EMPLOYEE_ID == r.EMPLOYEE_ID;
    }

    public int GetHashCode(Ranking obj)
    {
        return 1;
    }
}


0 commentaires

1
votes

L'idée est de choisir le premier élément, puis de supprimer les éléments correspondants de la liste pour s'assurer que le prochain choix est unique, comme ci-dessous:

+--------+-------------+---------------+
| JOB_ID | EMPLOYEE_ID | OVERALL_SCORE | 
+--------+-------------+---------------+
|      4 |           3 |           800 |
|      3 |           1 |           800 |   
|      2 |           2 |          1800 |
+--------+-------------+---------------+

résultat:

var rankings = new List<Rankings> {
    new Rankings{  JOB_ID= 4,EMPLOYEE_ID= 3, OVERALL_SCORE=  800 },
    new Rankings{  JOB_ID= 4,EMPLOYEE_ID= 4, OVERALL_SCORE=  800 },
    new Rankings{  JOB_ID= 3,EMPLOYEE_ID= 1, OVERALL_SCORE=  800 },
    new Rankings{  JOB_ID= 3,EMPLOYEE_ID= 2, OVERALL_SCORE= 1200 },
    new Rankings{  JOB_ID= 2,EMPLOYEE_ID= 1, OVERALL_SCORE= 1600 },
    new Rankings{  JOB_ID= 2,EMPLOYEE_ID= 2, OVERALL_SCORE= 1800 },
    new Rankings{  JOB_ID= 4,EMPLOYEE_ID= 1, OVERALL_SCORE= 2000 },
    new Rankings{  JOB_ID= 4,EMPLOYEE_ID= 2, OVERALL_SCORE= 2100 },
    new Rankings{  JOB_ID= 1,EMPLOYEE_ID= 1, OVERALL_SCORE= 6400 },
};
var cpy = new List<Rankings>(rankings);
var result = new List<Rankings>();
while (cpy.Count() > 0)
{
    var first = cpy.First();
    result.Add(first);
    cpy.RemoveAll(r => r.EMPLOYEE_ID == first.EMPLOYEE_ID || r.JOB_ID == first.JOB_ID);
}


1 commentaires

je vois. c'est parce que j'ai assigné JOB_ID, EMPLOYEE_ID dans le mauvais ordre pour l'initiation de la liste, je l'ai corrigé.



1
votes

Vraiment, si vous essayez d'obtenir le meilleur score pour le poste, vous n'avez pas besoin de sélectionner par JOB_ID / EMPLOYEE_ID unique, vous devez trier par JOB_ID / OVERALL_SCORE , et choisissez le premier employé correspondant par JOB_ID (qui ne figure pas déjà dans la "liste attribuée").

Vous pouvez mettre les articles dans l'ordre en utilisant LINQ:

public class Ranking : IComparable<Ranking>
{
  int IComparable<Ranking>.CompareTo( Ranking other )
  {
    var jobFirst = this.JOB_ID.CompareTo( other.JOB_ID );
    return
      jobFirst == 0?
        this.OVERALL_SCORE.CompareTo( other.OVERALL_SCORE ):
        jobFirst;
  } 

  //--> other stuff...

}

... puis décoller les employés que vous voulez ...

  var best = new List<Ranking>( );
  sorted.ForEach( r1 => 
  {
    if ( !best.Any
    ( 
      r2 => 
        r1.JOB_ID == r2.JOB_ID 
        || 
        r1.EMPLOYEE_ID == r2.EMPLOYEE_ID
    ) )
    {
      best.Add( r1 );
    }
  } );

Au lieu d'utiliser Linq em > pour produire une liste triée, vous pouvez implémenter IComparable sur Ranking puis trier simplement vos classements:

var sorted = new List<Ranking>
( 
  rankings
    .OrderBy( r => r.JOB_ID )
    .ThenBy( r => r.OVERALL_SCORE ) 
);

Ensuite, lorsque vous triez () les classements, ils seront dans l'ordre JOB_ID / OVERALL_SCORE. La mise en œuvre de IComparable est probablement plus rapide et utilise moins de mémoire.

Notez que vous avez des problèmes ... peut-être un objectif non déclaré. Est-il plus important de pourvoir le plus d'emplois ... ou est-il plus important de trouver du travail pour le plus d'employés? L’itinéraire que j’ai emprunté correspond à ce que vous suggérez, et il vous suffit de prendre le meilleur employé pour le poste au fur et à mesure ... mais peut-être que le seul employé du poste 2 peut être le même que le meilleur employé pour job 1 ... et si vous le mettez au job 1, vous n'aurez peut-être plus personne pour le job 2. Cela pourrait devenir compliqué :-)


0 commentaires