Question

Je souhaite implémenter une fonctionnalité de tri pour mon application de carnet d'adresses.

Je souhaite trier un ArrayList<Contact> contactArray. Contact est une classe qui contient quatre champs: nom, numéro de domicile, numéro de téléphone portable et adresse. Je veux trier sur name.

Comment puis-je écrire une fonction de tri personnalisée pour le faire?

Était-ce utile?

La solution

Voici un tutoriel sur la commande d'objets:

Même si je donnerai quelques exemples, je vous recommande de le lire quand même.

Il existe différentes manières de trier un ArrayList. Si vous souhaitez définir un naturel (valeur par défaut) pour passer une commande , vous devez laisser Contact mettre en œuvre Comparable . En supposant que vous souhaitiez trier par défaut sur name, faites (les vérifications nulles étant omises pour des raisons de simplicité):

public class Contact implements Comparable<Contact> {

    private String name;
    private String phone;
    private Address address;

    public int compareTo(Contact other) {
        return name.compareTo(other.name);
    }

    // Add/generate getters/setters and other boilerplate.
}

pour que vous puissiez simplement faire

List<Contact> contacts = new ArrayList<Contact>();
// Fill it.

Collections.sort(contacts);

Si vous souhaitez définir un ordre contrôlable externe (qui remplace l'ordre naturel), vous devez créer un Comparator :

List<Contact> contacts = new ArrayList<Contact>();
// Fill it.

// Now sort by address instead of name (default).
Collections.sort(contacts, new Comparator<Contact>() {
    public int compare(Contact one, Contact other) {
        return one.getAddress().compareTo(other.getAddress());
    }
}); 

Vous pouvez même définir les <=> dans le <=> lui-même afin de pouvoir les réutiliser au lieu de les recréer à chaque fois:

public class Contact {

    private String name;
    private String phone;
    private Address address;

    // ...

    public static Comparator<Contact> COMPARE_BY_PHONE = new Comparator<Contact>() {
        public int compare(Contact one, Contact other) {
            return one.phone.compareTo(other.phone);
        }
    };

    public static Comparator<Contact> COMPARE_BY_ADDRESS = new Comparator<Contact>() {
        public int compare(Contact one, Contact other) {
            return one.address.compareTo(other.address);
        }
    };

}

qui peut être utilisé comme suit:

List<Contact> contacts = new ArrayList<Contact>();
// Fill it.

// Sort by address.
Collections.sort(contacts, Contact.COMPARE_BY_ADDRESS);

// Sort later by phone.
Collections.sort(contacts, Contact.COMPARE_BY_PHONE);

Pour couronner le tout, vous pouvez envisager d'utiliser un comparateur générique javabean :

public class BeanComparator implements Comparator<Object> {

    private String getter;

    public BeanComparator(String field) {
        this.getter = "get" + field.substring(0, 1).toUpperCase() + field.substring(1);
    }

    public int compare(Object o1, Object o2) {
        try {
            if (o1 != null && o2 != null) {
                o1 = o1.getClass().getMethod(getter, new Class[0]).invoke(o1, new Object[0]);
                o2 = o2.getClass().getMethod(getter, new Class[0]).invoke(o2, new Object[0]);
            }
        } catch (Exception e) {
            // If this exception occurs, then it is usually a fault of the developer.
            throw new RuntimeException("Cannot compare " + o1 + " with " + o2 + " on " + getter, e);
        }

        return (o1 == null) ? -1 : ((o2 == null) ? 1 : ((Comparable<Object>) o1).compareTo(o2));
    }

}

que vous pouvez utiliser comme suit:

// Sort on "phone" field of the Contact bean.
Collections.sort(contacts, new BeanComparator("phone"));

(comme vous le voyez dans le code, des champs nuls sont peut-être déjà couverts pour éviter les NPE pendant le tri)

Autres conseils

En plus de ce qui a déjà été posté, sachez que depuis Java 8, nous pouvons raccourcir notre code et l'écrire comme suit:

Collection.sort(yourList, Comparator.comparing(YourClass::getFieldToSortOn));

ou depuis que la liste a maintenant la sort méthode

yourList.sort(Comparator.comparing(YourClass::getFieldToSortOn));

Explication:

Depuis Java 8, les interfaces fonctionnelles (interfaces avec une seule méthode abstraite - elles peuvent avoir plus de méthodes par défaut ou statiques) peuvent être facilement implémentées à l'aide de:

Étant donné que Comparator<T> n'a qu'une seule méthode abstraite int compare(T o1, T o2) c'est une interface fonctionnelle.

Donc au lieu de (exemple, tiré de @BalusC réponse )

Collections.sort(contacts, new Comparator<Contact>() {
    public int compare(Contact one, Contact other) {
        return one.getAddress().compareTo(other.getAddress());
    }
}); 

nous pouvons réduire ce code à:

Collections.sort(contacts, (Contact one, Contact other) -> {
     return one.getAddress().compareTo(other.getAddress());
});

Nous pouvons simplifier cela (ou n’importe quel) lambda en sautant

  • types d'arguments (Java les déduira en fonction de la signature de la méthode)
  • ou {return ... }

Donc au lieu de

(Contact one, Contact other) -> {
     return one.getAddress().compareTo(other.getAddress();
}

nous pouvons écrire

(one, other) -> one.getAddress().compareTo(other.getAddress())

De plus, Comparator a maintenant des méthodes statiques telles que comparing(FunctionToComparableValue) ou comparing(FunctionToValue, ValueComparator) que nous pourrions utiliser pour créer facilement des comparateurs qui devraient comparer certaines valeurs spécifiques d'objets.

En d'autres termes, nous pouvons réécrire le code ci-dessus en tant que

Collections.sort(contacts, Comparator.comparing(Contact::getAddress)); 
//assuming that Address implements Comparable (provides default order).

Cette page vous indique tout ce dont vous avez besoin connaître les collections de tri, telles que ArrayList.

Fondamentalement, vous devez

  • demandez à votre Contact classe de mettre en œuvre l'interface Comparable en:
    • créer une méthode public int compareTo(Contact anotherContact) à l'intérieur de celle-ci.
  • Une fois cela fait, vous pouvez simplement appeler Collections.sort(myContactList);,
    • myContactList est ArrayList<Contact> (ou toute autre collection de <=>).

Il existe également un autre moyen, qui consiste à créer une classe de comparaison, et vous pouvez en savoir plus à ce sujet sur la page liée.

Exemple:

public class Contact implements Comparable<Contact> {

    ....

    //return -1 for less than, 0 for equals, and 1 for more than
    public compareTo(Contact anotherContact) {
        int result = 0;
        result = getName().compareTo(anotherContact.getName());
        if (result != 0)
        {
            return result;
        }
        result = getNunmber().compareTo(anotherContact.getNumber());
        if (result != 0)
        {
            return result;
        }
        ...
    }
}

BalusC et bguiz ont déjà donné des réponses très complètes sur l’utilisation des comparateurs intégrés à Java.

Je veux juste ajouter que Google-Collections a un Classe de commande qui est plus &"; puissant & "; que les comparateurs standard. Il pourrait être intéressant de vérifier. Vous pouvez faire des choses cool telles que composer des commandes, les inverser, les commander en fonction du résultat d'une fonction pour vos objets ...

Voici un article de blog qui mentionne certains de ses avantages.

Vous devez faire en sorte que vos classes Contact implémentent Comparable , puis implémentez la méthode compareTo(Contact). De cette façon, Collections.sort pourra les trier pour vous. Selon la page à laquelle j'ai lié, compareTo 'renvoie un entier négatif, zéro ou un entier positif car cet objet est inférieur, égal ou supérieur à l'objet spécifié.'

Par exemple, si vous souhaitez trier par nom (A à Z), votre classe ressemblerait à ceci:

public class Contact implements Comparable<Contact> {

    private String name;

    // all the other attributes and methods

    public compareTo(Contact other) {
        return this.name.compareTo(other.name);
    }
}

En utilisant lambdaj , vous pouvez trier une collection de vos contacts (par exemple, leur nom) comme il suit

sort(contacts, on(Contact.class).getName());

ou par leur adresse:

sort(contacts, on(Contacts.class).getAddress());

et ainsi de suite. Plus généralement, il offre un accès DSL permettant d’accéder à vos collections et de les manipuler de différentes manières, telles que filtrer ou regrouper vos contacts en fonction de certaines conditions, agréger certaines de leurs valeurs de propriété, etc.

Collections.sort est une bonne implémentation. Si vous n'avez pas implémenté la fonctionnalité de comparaison pour Contact, vous devez passer un Implémentation du comparateur

À noter:

  

L'algorithme de tri est un mergesort modifié (dans lequel la fusion est omise si l'élément le plus élevé dans la sous-liste basse est inférieur à l'élément le plus bas dans la liste supérieure). Cet algorithme offre des performances garanties de n log (n). La liste spécifiée doit être modifiable, mais ne doit pas nécessairement être redimensionnable. Cette implémentation vide la liste spécifiée dans un tableau, trie le tableau et effectue une itération sur la liste en réinitialisant chaque élément à partir de la position correspondante dans le tableau. Cela évite les performances n2 log (n) qui résulteraient d'une tentative de tri d'une liste liée sur place.

Le type de fusion est probablement meilleur que la plupart des algorithmes de recherche que vous pouvez utiliser.

Je l'ai fait de la manière suivante. numéro et nom sont deux noms de artistes. Je dois trier le nom .Si un changement survient dans le nom de l'ordre arraliste, le numéro de la liste change également son ordre.

public void sortval(){

        String tempname="",tempnum="";

         if (name.size()>1) // check if the number of orders is larger than 1
            {
                for (int x=0; x<name.size(); x++) // bubble sort outer loop
                {
                    for (int i=0; i < name.size()-x-1; i++) {
                        if (name.get(i).compareTo(name.get(i+1)) > 0)
                        {

                            tempname = name.get(i);

                            tempnum=number.get(i);


                           name.set(i,name.get(i+1) );
                           name.set(i+1, tempname);

                            number.set(i,number.get(i+1) );
                            number.set(i+1, tempnum);


                        }
                    }
                }
            }



}

utilisez cette méthode:

private ArrayList<myClass> sortList(ArrayList<myClass> list) {
    if (list != null && list.size() > 1) {
        Collections.sort(list, new Comparator<myClass>() {
            public int compare(myClass o1, myClass o2) {
                if (o1.getsortnumber() == o2.getsortnumber()) return 0;
                return o1.getsortnumber() < o2.getsortnumber() ? 1 : -1;
            }
        });
    }
    return list;
}

`

et utiliser: mySortedlist = sortList(myList); Pas besoin d'implémenter un comparateur dans votre classe. Si vous souhaitez un échange d’ordre inverse 1 et -1

Vous devriez utiliser la fonction Arrays.sort. Les classes contenant doivent implémenter Comparable.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top