5
votes

Comment trier une liste de chaînes composée de chiffres et d'alphabets en Java?

J'ai une liste d'éléments composée de chiffres et d'alphabets comme ci-dessous:

Liste d'origine:

Apple 1
Apple 1
Apple 10
Apple 11
Apple 1A
Apple 1B
Apple 1B
Apple 1C
Apple 1D
Apple 2
Apple 2A
Apple 2A
Apple 2C
Apple 4
Apple 5
Apple 8D
Banana 1
Banana 13
Banana 16
Banana 4
Banana 9C
Banana 9D
Banana 9E

C'est un résultat de recherche de une API mais uniquement triée par ordre alphabétique des pommes et bananes . Maintenant, j'aimerais le trier par chiffres (les chiffres viennent au hasard avec les lettres A, B, C, D, E) comme ci-dessous:

Les chiffres avec A, B, C, D , Les lettres E doivent être triées par ordre numérique et alphabétique.

Liste attendue:

private List<Location> sortLocationList(List<Location> locationArrayList){
  Collections.sort(locationArrayList, new Comparator<Location>(){
    @Override
    public int compare(Location o1, Location o2){
      return o1.getValue().compareToIgnoreCase(o2.getValue());
    }
  });
  return locationArrayList;
}

public class Location{

  public enum LocationType{ADDRESS, STREET, CITY}

  private JavascriptObject object;
  private LocationType locationType;
  private String value;

  public Location(LocationType locationType, String value, JavascriptObject object){
    this.locationType = locationType;
    this.value = value;
    this.object = object;
  }
}

J'ai essayé cette solution, mais elle commande tous les articles par l'article commençant par 0 à 9 chiffres comme ci-dessous:

Apple 1
Apple 1
Apple 1A
Apple 1B
Apple 1B
Apple 1C
Apple 1D
Apple 2
Apple 2A
Apple 2A
Apple 2C
Apple 4
Apple 5
Apple 8D
Apple 10
Apple 11
Banana 1
Banana 4
Banana 9C
Banana 9D
Banana 9E
Banana 13
Banana 16

Ma solution est renvoyer ceci:

Apple 1
Apple 1
Apple 4
Apple 1A
Apple 1B
Apple 1D
Apple 2A
Apple 2A
Apple 1C
Apple 1B
Apple 2C
Apple 10
Apple 11
Apple 5
Apple 11
Apple 8D
Banana 1
Banana 4
Banana 9D
Banana 9E
Banana 9C
Banana 13
Banana 16

Une meilleure solution pour trier cette liste?

Merci d'avance.


2 commentaires

Divisez l'emplacement en trois parties comme Apple, 2, C. Si elles sont différentes, triez par première partie, si égal par seconde. Si les deuxièmes sont égaux, par les troisièmes


Google "comparaison alphanumérique java". Vous trouverez de nombreuses questions et réponses et de nombreux algorithmes - beaucoup d'entre eux sont faux, certains corrects. Votre tâche serait alors d'en trouver un qui fonctionne correctement.


3 Réponses :


1
votes

par ordre alphabétique, les lettres sont après les chiffres et «2» après «10» Vous devez trier par nom, nombre et suffixe (String nullable), utilisez une nouvelle classe à la place d'une String ' avec ces attributs (nom, numéro et suffixe)

@Override
   public int compare(Location o1, Location o2){
      int c;
      // compare name
      c = o1.getValue().getName().compareTo(o12.getValue().getName());
      if (c == 0) {
           // if is the same name compare number
           c = o1.getValue().getNum().compareTo(o2.getValue().getNum());
               if (c ==0 && o1.getValue().getSufix() != null) {
               // if is the same number compare suffix
               c = o1.getValue().getSufix().compareTo(o2.getValue().getSufix());
           }
      }
      return c;
   }

et corrigez votre tri

// change String to a new type
private Product value;


2 commentaires

Ou Collections.sort (locationArrayList, comparant (Location :: getValue, comparant (Product :: getName) .thenComparing (Product :: getNum) .t‌ henComparing (Product‌ :: getSuffix))); mais il serait plus facile de faire en sorte que Product implémente Comparable et ensuite simplement Collections.sort (locationArrayList, comparant (Location :: getValue))


Salut, merci pour vos efforts. Votre solution semble bonne, mais @forpas m'a donné la solution parfaitement adaptée à mon problème.



5
votes

Je suppose qu'il y aura toujours un modèle comme:

private List<Location> sortLocationList(List<Location> locationArrayList){
    Collections.sort(locationArrayList, new Comparator<Location>(){
        @Override
        public int compare(Location o1, Location o2){
            String s1 = o1.getValue();
            String s2 = o2.getValue();

            if (s1.equalsIgnoreCase(s2))
                return 0;

            String[] tokens1 = s1.split(" ");
            String[] tokens2 = s2.split(" ");

            if (!tokens1[0].equalsIgnoreCase(tokens2[0]))
                return s1.compareToIgnoreCase(s2);

            int number1 = Integer.parseInt(tokens1[1].replaceAll("\\D", ""));
            int number2 = Integer.parseInt(tokens2[1].replaceAll("\\D", ""));

            if (number1 != number2)
                return number1 - number2;

            String suffix1 = tokens1[1].replaceAll("\\d", "");
            String suffix2 = tokens2[1].replaceAll("\\d", "");

            return suffix1.compareToIgnoreCase(suffix2);
        }
    });

    return locationArrayList;
}

pour toutes les valeurs renvoyées par la méthode getValue ()
et que le 2ème "quelque chose" commencera toujours par un nombre avec ou sans caractères de fin.
Le code ci-dessous divise chaque valeur en 3 parties et compare
la 1ère partie par ordre alphabétique
la 2ème partie numériquement et
la partie 3d par ordre alphabétique:

"something something"


1 commentaires

Salut @forpas, merci pour votre attention et vos efforts. Votre solution a parfaitement résolu mon problème.



0
votes

Comme @forpas l'a mentionné, divisez la valeur en 3 parties.

private List<Location> sortLocationList(List<Location> locationArrayList) {
    Collections.sort(locationArrayList, new Comparator<Location>() {
        @Override
        public int compare(Location o1, Location o2) {
            String[] objArr1 = o1.getValue().split(" ");
            String[] objArr2 = o2.getValue().split(" ");

            if(objArr1[0].equalsIgnoreCase(objArr2[0])) {//if Part1 is same

                //split digits and letters separately
                String[] digLetArr1 = objArr1[1].split("(?<=\\D)(?=\\d)|(?<=\\d)(?=\\D)");
                String[] digLetArr2 = objArr2[1].split("(?<=\\D)(?=\\d)|(?<=\\d)(?=\\D)");
                Integer digit1 = Integer.parseInt(digLetArr1[0]);
                Integer digit2 = Integer.parseInt(digLetArr2[0]);

                //compare digit part (part2)
                if(digit1 == digit2) {

                    //Compare part3
                    if(digLetArr1.length == 1) {
                        return -1;
                    }
                    if(digLetArr2.length == 1) {
                        return 1;
                    }
                    return digLetArr1[1].compareTo(digLetArr2[1]);
                }
                else {
                    return digit1-digit2;
                }
            }
            else {
                return o1.getValue().compareToIgnoreCase(o2.getValue());
            }
        }
    });
    return locationArrayList;
}

Le code de tri est ci-dessous

for example : "Apple 10AB"
Part1 - Apple (Alphabet)
Part2 - 10  (Digit)
Part3 - AB  (Alphabet)

Then 1. Compare Part1, if not equal do String Compare. If equals goto next step.
     2. Compare Part2(convert them to int), If not equal do int compare. If equals goto next step.
     3. Compare Part3, do String Compare.

p>


1 commentaires

Salut @NGV, merci pour vos efforts. Votre solution semble bonne, mais forpas m'a donné la solution parfaitement adaptée à mon problème.