119 votes

Trier une liste d'objets en Flutter (Dart) par valeur de propriété

Comment trier une liste d'objets par l'ordre alphabétique d'une de ses propriétés (pas le nom mais la valeur réelle que la propriété contient) ?

2 votes

0 votes

@RichardHeap oui, la solution répond à ma question mais la question est posée différemment, je suppose. Merci pour votre aide!

1 votes

J'ai écrit une réponse ici stackoverflow.com/a/59350472/10409567

273voto

Nate Points 56

Vous pouvez passer une fonction de comparaison à List.sort.

someObjects.sort((a, b) => a.someProperty.compareTo(b.someProperty));

1 votes

Comment le trie-t-on dans l'ordre décroissant

13 votes

Pour le renverser, vous pourriez faire b.someProperty.compareTo(a.someProperty). Ou le trier puis utiliser .reversed.

2 votes

Pour inverser, il suffit d'utiliser (b,a) au lieu de (a,b). Il convient de noter que compareTo renvoie 1, 0 ou -1 si vous souhaitez réaliser des tris plus avancés.

28voto

Conner Points 317

Si vous voulez trier l'objet "objects" par la propriété "name", faites quelque chose comme ceci

objects.sort((a, b) {
  return a.value['name'].toString().toLowerCase().compareTo(b.value['name'].toString().toLowerCase());
});

14voto

RopAli Munshi Points 1770

Voici ma contribution à cette bonne question. Si quelqu'un éprouve des difficultés à comprendre comment fonctionne la réponse de @Nate Bosch et que vous souhaitez trier la liste de votre classe modèle personnalisée, vous pouvez le faire de cette manière.

1. Vous devez implémenter la classe abstraite Comparable dans votre classe modèle. Elle possède la méthode compareTo que vous devez remplacer. Par exemple, j'ai cette classe modèle StudentMarks qui a une propriété de notes.

class StudentMarks implements Comparable {
  int marks;

  StudentMarks({
    this.marks,
  });

  @override
  int compareTo(other) {

    if (this.marks == null || other == null) {
      return null;
    }

    if (this.marks < other.marks) {
      return 1;
    }

    if (this.marks > other.marks) {
      return -1;
    }

    if (this.marks == other.marks) {
      return 0;
    }

    return null;
  }
}

2. Maintenant, vous pouvez appeler la méthode compareTo à l'intérieur de la méthode sort.

void _sortStudents({bool reversed: false}) {
    _students.sort((a, b) {
      return a.compareTo(b);
    });

    if (reversed) {
      _students = _students.reversed.toList();
    }

    setState(() {});
  }

Référez-vous à ce lien si vous voulez en savoir plus sur la classe Comparable

https://api.dart.dev/stable/2.1.0/dart-core/Comparable-class.html

2 votes

Si vous triez une liste d'objets qui implémente correctement Comparable, vous ne devriez pas avoir besoin d'appeler explicitement List.sort avec un callback ; cela devrait être automatique.

13voto

jamesdlin Points 13455

En général, vous pouvez fournir une fonction de comparaison personnalisée à List.sort.

/// Relation souhaitée | Résultat
/// -------------------------------------------
///           a < b  | Renvoie une valeur négative.
///           a == b | Renvoie 0.
///           a > b  | Renvoie une valeur positive.
///
int mySortComparison(SomeClass a, SomeClass b) {
  final propertyA = someProperty(a);
  final propertyB = someProperty(b);
  if (propertyA < propertyB) {
    return -1;
  } else if (propertyA > propertyB) {
    return 1;
  } else {
    return 0;
  }
}

list.sort(mySortComparison);

Si vous triez une classe personnalisée que vous possédez, vous pouvez alternativement faire en sorte que votre classe implémente l'interface Comparable:

class MyCustomClass implements Comparable {
  ...

  @override
  int compareTo(MyCustomClass other) {
    if (someProperty < other.someProperty) {
      return -1;
    } else if (someProperty > other.someProperty) {
      return 1;
    } else {
      return 0;
    }
  }
}

et ensuite vous pouvez utiliser list.sort() directement sans fournir de rappel.

Remarquez que si vous triez par une seule propriété qui implémente déjà l'interface Comparable, implémenter les fonctions de comparaison est beaucoup plus simple. Par exemple :

class MyCustomClass implements Comparable {
  ...

  @override
  int compareTo(MyCustomClass other) =>
    someProperty.compareTo(other.someProperty);
}

Inversion

Si vous souhaitez inverser l'ordre de tri, vous pouvez faire en sorte que votre fonction de comparaison renvoie une valeur avec le signe opposé. Alternativement, inversez explicitement la liste après le tri :

list = (list..sort()).reversed.toList();

Tri par plusieurs propriétés (également appelé sous-tri)

Si vous souhaitez trier par plusieurs propriétés, une manière générale consiste à effectuer un tri stable pour chaque propriété dans l'ordre inverse de l'importance. Par exemple, si vous souhaitez trier les noms principalement par nom de famille et ensuite trier les prénoms au sein des noms de famille, vous trieriez d'abord par prénoms, puis effectueriez un tri stable par nom de famille. Voir ci-dessous comment effectuer un tri stable.

Alternativement, vous pourriez trier avec une fonction de comparaison qui tient compte de plusieurs propriétés. Par exemple :

class Name {
  Name({String surname, String givenName})
    : surname = surname ?? "",
      givenName = givenName ?? "";

  final String surname;
  final String givenName;
}

int compareNames(Name name1, Name name2) {
  var comparisonResult = name1.surname.compareTo(name2.surname);
  if (comparisonResult != 0) {
     return comparisonResult;
  }
  // Les noms de famille sont les mêmes, donc on trie par prénom.
  return name1.givenName.compareTo(name2.givenName);
}

D'accord, je veux un tri stable

List.sort n'est pas garanti d'être un tri stable. Si vous avez besoin d'un tri stable, le package:collection fournit des implémentations de insertionSort et de mergeSort qui sont stables.


Mais la comparaison pourrait être coûteuse

Supposons que vous avez une fonction de comparaison personnalisée qui ressemble à ceci :

int compareMyCustomClass(MyCustomClass a, MyCustomClass b) {
  var a0 = computeValue(a);
  var b0 = computeValue(b);
  return a0.compareTo(b0);
}

Le tri pourrait appeler computeValue() sur chaque élément plusieurs fois, ce qui est particulièrement gaspilleur si computeValue() est coûteux. Dans de tels cas, une transformée de Schwartzian pourrait être plus rapide (au détriment de l'utilisation de plus de mémoire). Cette approche mappe vos objets à des clés directement triables, trie les clés et extrait les objets d'origine. (C'est ainsi que fonctionnent les fonctions de tri et de tri de Python.)

Voici une implémentation possible :

class _SortableKeyPair>
    implements Comparable<_SortableKeyPair> {
  _SortableKeyPair(this.original, this.key);

  final T original;
  final K key;

  @override
  int compareTo(_SortableKeyPair other) => key.compareTo(other.key);
}

List sortedWithKey>(
  Iterable items,
  K Function(E) toKey,
) {
  final keyPairs = [
    for (var element in items) _SortableKeyPair(element, toKey(element)),
  ]..sort();

  return [
    for (var keyPair in keyPairs) keyPair.original,
  ];
}

void main() {
  final list = [ ... ];
  final sorted = sortedWithKeys(list, computeValue);
}

0 votes

J'étais en train de penser quand je suis arrivé à "mais les comparaisons pourraient être coûteuses" quelque chose comme "je me demande comment l'auteur abordera cela?" Et voilà. :)

12voto

comm1x Points 1070

Immutable extension sortedBy pour List.

extension MyIterable on Iterable {
  Iterable sortedBy(Comparable key(E e)) =>
      toList()..sort((a, b) => key(a).compareTo(key(b)));
}

Et utiliser

list.sortedBy((it) => it.name);

0 votes

Faites attention à la bibliothèque dartx. Elle est très populaire et offre de nombreuses extensions utiles, principalement conçues comme en Kotlin.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X