Solution idea
First, you have to see that the file names have the format prefix + suffix, where the suffix is a number. With this, we can arrange your files, first by prefix and then by suffix.
Implementation of the solution
Therefore, you will need a function that knows how to sort the filenames correctly. Here’s a:
public static int comparaNomesDeArquivos(String nome1, String nome2) {
if (Objects.equals(nome1, nome2)) return 0;
if (nome1 == null) return -1;
if (nome2 == null) return 1;
int sufixo1 = 0, sufixo2 = 0;
int n;
int p = 1;
for (n = nome1.length() - 1; n >= 0; n--) {
char c = nome1.charAt(n);
if (c < '0' || c > '9') break;
sufixo1 += (c - '0') * p;
p *= 10;
}
p = 1;
String prefixo1 = nome1.substring(0, n + 1);
for (n = nome2.length() - 1; n >= 0; n--) {
char c = nome2.charAt(n);
if (c < '0' || c > '9') break;
sufixo2 += (c - '0') * p;
p *= 10;
}
String prefixo2 = nome2.substring(0, n + 1);
int a = prefixo1.compareTo(prefixo2);
if (a != 0) return a;
int b = sufixo1 - sufixo2;
if (b != 0) return b;
return nome1.compareTo(nome2);
}
The explanation of this function is as follows:
As any comparison function in Java, it has as its parameter two elements to be compared. Returns a positive number if the first element is after the second, negative if it is before, or zero if the two are equal.
For the sake of optimization, it is initially verified that the String
are identical, and in this case it is known that they are equal. This case is determined with the Objects.equals(Object, Object)
. This check also works if both String
s are null
.
Case one of String
s be null
(and it is already known that only one of them could be because the case where the two are treated in step 2), then considers that null
precedes anything else, returning -1 or 1 in these cases.
To separate the prefix from the suffix, this function traverses each string back-to-front in order to determine them for
for each.
If the prefix of String
s is different, so the sort is given by the prefix.
Since the prefixes are equal, then the ordering is given by the suffix, which is a number.
Prefixes and suffixes being equal, which can happen if you compare batatinha123
with batatinha0123
, that is, when the difference is only given by the zeros to the left of the number, then it uses the standard comparison form.
Knowing how to compare the String
s, you can mount a function to compare files. I don’t know exactly how you are repressing a file. If it is directly by their names, then you can ignore that part. Otherwise, assuming the method getFilename()
whatever determines the file name, do this:
public static int comparaArquivosPorNome(Arquivo arquivo1, Arquivo arquivo2) {
String nome1 = arquivo1 == null ? null : arquivo1.getFilename();
String nome2 = arquivo2 == null ? null : arquivo2.getFilename();
return comparaNomesDeArquivos(nome1, nome2);
}
Ah, and let’s assume that the above methods are in a class called Ordenacao
.
Finally, you can order your List<Arquivo>
using the method sort(List<T>, Comparator<? super T>)
:
Collections.sort(suaArrayList, Ordenacao::comparaArquivosPorNome);
If you are using only one List<String>
instead of List<Arquivo>
, use this:
Collections.sort(suaArrayList, Ordenacao::comparaNomesDeArquivos);
Testing
To test all this, let’s assume that this is the class Arquivo
:
public class Arquivo {
private String nome;
public Arquivo(String nome) {
this.nome = nome;
}
public String getFilename() {
return nome;
}
@Override
public String toString() {
return "arquivo {" + nome + "}";
}
}
And that this is the class that makes our tests:
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.stream.Collectors;
public class Teste {
public static void main(String[] args) {
// 1. Cria as listas.
List<String> lista1 = Arrays.asList(
"batata", "batata0", "batata000", "batata3", null, "azul 6", "azul 50", "azul 51", "batata", "azul 051", "azul 5", "laranja"
);
List<Arquivo> lista2 = lista1.stream().map(Arquivo::new).collect(Collectors.toList());
// 2. Ordena as listas.
Collections.sort(lista1, Ordenacao::comparaNomesDeArquivos);
Collections.sort(lista2, Ordenacao::comparaArquivosPorNome);
// 3. Mostra as listas ordenadas.
System.out.println(lista1);
System.out.println(lista2);
}
}
Here is the output produced:
[null, azul 5, azul 6, azul 50, azul 051, azul 51, batata, batata, batata0, batata000, batata3, laranja]
[arquivo {null}, arquivo {azul 5}, arquivo {azul 6}, arquivo {azul 50}, arquivo {azul 051}, arquivo {azul 51}, arquivo {batata}, arquivo {batata}, arquivo {batata0}, arquivo {batata000}, arquivo {batata3}, arquivo {laranja}]
See all this working on the tutorialspoint site. (Do the test by clicking the compile button and then the run button.)
is probably treating this number as a string, and 1 comes before 9.
– GabrielLocalhost
@neto Add the code you’ve already developed.
– Marcos Sousa