Trier une liste de classes personnalisée <T>

112

Je voudrais trier ma liste avec la datepropriété.

Ceci est ma classe personnalisée:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;

namespace Test.Web
{
    public class cTag
    {
        public int id { get; set; }
        public int regnumber { get; set; }
        public string date { get; set; }
    }
}

Et c'est celui Listque je veux trier:

List<cTag> Week = new List<cTag>();

Ce que je veux faire, c'est trier la liste par la datepropriété de la classe cTag. La date est au format: jj.MM.aaaa.

J'ai lu quelque chose sur l' IComparableinterface, mais je ne sais pas comment l'utiliser.

Loup-garou
la source

Réponses:

143

Une façon de faire est d'utiliser un delegate

List<cTag> week = new List<cTag>();
// add some stuff to the list
// now sort
week.Sort(delegate(cTag c1, cTag c2) { return c1.date.CompareTo(c2.date); });
Ahsteele
la source
98
Vous pouvez également écrire la même chose avec une expression lambda:list.Sort((a,b) => a.date.CompareTo(b.date));
Xavier Poinas
2
@Xavier pour une raison quelconque, mon esprit passe toujours d'abord par les prédicats, bien que vous ayez raison à 100% que votre expression Lambda ferait le travail et qu'elle est probablement plus facile à lire / à comprendre.
ahsteele
comment cela, ou comment feriez-vous, briser une cravate en utilisant systématiquement l'expression lambda? Et si a.date == b.date ici? list.Sort ((a, b) => a.date.CompareTo (b.date)); Cela créerait-il des problèmes lorsque les grilles de pagination et ces deux se trouvaient sur des pages différentes?
TheEmirOfGroofunkistan
1
@TheEmirOfGroofunkistan que tout dépend de la façon dont CompareToest mis en œuvre. IComparableaccorde qu'une classe aura la méthode, mais comment faire cette comparaison dépend du créateur de la classe. Je ne sais pas comment Date implémente ICompare, mais j'ai souvent vu des développeurs utiliser les paramètres de commande pour rompre une égalité lorsque les valeurs sont égales. hth
ahsteele
51

Vous avez raison de dire que votre classe cTag doit implémenter une IComparable<T>interface. Ensuite, vous pouvez simplement appeler Sort()sur votre liste.

Pour implémenter l' IComparable<T>interface, vous devez implémenter la CompareTo(T other)méthode. Le moyen le plus simple de le faire est d'appeler la méthode CompareTo du champ que vous souhaitez comparer, qui dans votre cas est la date.

public class cTag:IComparable<cTag> {
    public int id { get; set; }
    public int regnumber { get; set; }
    public string date { get; set; }
    public int CompareTo(cTag other) {
        return date.CompareTo(other.date);
    }
}

Cependant, cela ne tiendrait pas bien, car cela utiliserait un tri classique sur les chaînes (puisque vous avez déclaré la date sous forme de chaîne). Je pense donc que la meilleure chose à faire serait de redéfinir la classe et de déclarer la date non pas en tant que chaîne, mais en tant que DateTime. Le code resterait presque le même:

public class cTag:IComparable<cTag> {
    public int id { get; set; }
    public int regnumber { get; set; }
    public DateTime date { get; set; }
    public int CompareTo(cTag other) {
        return date.CompareTo(other.date);
    }
}

La seule chose que vous auriez à faire lors de la création de l'instance de la classe pour convertir votre chaîne contenant la date en type DateTime, mais cela peut être fait facilement, par exemple par DateTime.Parse(String)méthode.

Ondra C.
la source
38

Dans ce cas, vous pouvez également trier à l'aide de LINQ:

week = week.OrderBy(w => DateTime.Parse(w.date)).ToList();
Yakimych
la source
12
List<cTag> week = new List<cTag>();
week.Sort((x, y) => 
    DateTime.ParseExact(x.date, "dd.MM.yyyy", CultureInfo.InvariantCulture).CompareTo(
    DateTime.ParseExact(y.date, "dd.MM.yyyy", CultureInfo.InvariantCulture))
);
Darin Dimitrov
la source
9

Tout d'abord, si la propriété date stocke une date, stockez-la à l'aide d'un DateTime. Si vous analysez la date à travers le tri, vous devez l'analyser pour chaque élément comparé, ce n'est pas très efficace ...

Vous pouvez ensuite créer un IComparer:

public class TagComparer : IComparer<cTag>
{
    public int Compare(cTag first, cTag second)
    {
        if (first != null && second != null)
        {
            // We can compare both properties.
            return first.date.CompareTo(second.date);
        }

        if (first == null && second == null)
        {
            // We can't compare any properties, so they are essentially equal.
            return 0;
        }

        if (first != null)
        {
            // Only the first instance is not null, so prefer that.
            return -1;
        }

        // Only the second instance is not null, so prefer that.
        return 1;
    }
}

var list = new List<cTag>();
// populate list.

list.Sort(new TagComparer());

Vous pouvez même le faire en tant que délégué:

list.Sort((first, second) =>
          {
              if (first != null && second != null)
                  return first.date.CompareTo(second.date);

              if (first == null && second == null)
                  return 0;

              if (first != null)
                  return -1;

              return 1;
          });
Matthew Abbott
la source
6

Vous avez raison - vous devez implémenter IComparable. Pour ce faire, déclarez simplement votre classe:

public MyClass : IComparable
{
  int IComparable.CompareTo(object obj)
  {
  }
}

Dans CompareTo, vous implémentez simplement votre algorithme de comparaison personnalisé (vous pouvez utiliser des objets DateTime pour ce faire, mais assurez-vous simplement de vérifier d'abord le type de "obj"). Pour plus d'informations, voir ici et ici .

UN J.
la source
7
IComparable<T>serait probablement un meilleur choix, car il est vérifié de préférence à IComparable: msdn.microsoft.com/en-us/library/b0zbh7b6.aspx
Richard Szalay
5

Vous pouvez utiliser linq:

var q = from tag in Week orderby Convert.ToDateTime(tag.date) select tag;
List<cTag> Sorted = q.ToList()
SirDemon
la source
3

regardez la méthode de tri surchargée de la classe List. il existe des moyens d'y parvenir. l'un d'eux: votre classe personnalisée doit implémenter l'interface IComparable puis vous pouvez utiliser la méthode Sort de la classe List.

Arseny
la source
3

Merci pour toutes les réponses rapides.

Voici ma solution:

Week.Sort(delegate(cTag c1, cTag c2) { return DateTime.Parse(c1.date).CompareTo(DateTime.Parse(c2.date)); });

Merci

Loup-garou
la source
2
YourVariable.Sort((a, b) => a.amount.CompareTo(b.amount));
sansalk
la source