Listen natürlich sortieren

Veröffentlicht von

Hier mal ein example, womit man Listen, natürlich nach Namen sortieren kann.

In dem Fall handelt es sich um ein „JavaFX TreeView“, der Dateien anzeigen soll.

Die selbe Klasse kann auch für ein „JavaFX TableView “ genutzt werden.


TreeView:

Collections.sort(children, new Comparator<TreeItem<PathItem>>() {
    private final Comparator<String> NATURAL_SORT = new WindowsExplorerComparator();

    @Override
    public int compare(TreeItem<PathItem> o1, TreeItem<PathItem> o2) {;
        return NATURAL_SORT.compare(o1.getValue().toString(), o2.getValue().toString());
    }
});

WindowsExplorerComparator.java

import java.util.ArrayList;
import java.util.Comparator;
import java.util.Iterator;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class WindowsExplorerComparator implements Comparator<String> {

    private static final Pattern splitPattern = Pattern.compile("\\d+|\\.|\\s");

    @Override
    public int compare(String str1, String str2) {
        Iterator<String> i1 = splitStringPreserveDelimiter(str1).iterator();
        Iterator<String> i2 = splitStringPreserveDelimiter(str2).iterator();
        while (true) {
            //Til here all is equal.
            if (!i1.hasNext() && !i2.hasNext()) {
                return 0;
            }
            //first has no more parts -> comes first
            if (!i1.hasNext() && i2.hasNext()) {
                return -1;
            }
            //first has more parts than i2 -> comes after
            if (i1.hasNext() && !i2.hasNext()) {
                return 1;
            }

            String data1 = i1.next();
            String data2 = i2.next();
            int result;
            try {
                //If both datas are numbers, then compare numbers
                result = Long.compare(Long.valueOf(data1), Long.valueOf(data2));
                //If numbers are equal than longer comes first
                if (result == 0) {
                    result = -Integer.compare(data1.length(), data2.length());
                }
            } catch (NumberFormatException ex) {
                //compare text case insensitive
                result = data1.compareToIgnoreCase(data2);
            }

            if (result != 0) {
                return result;
            }
        }
    }

    private List<String> splitStringPreserveDelimiter(String str) {
        Matcher matcher = splitPattern.matcher(str);
        List<String> list = new ArrayList<String>();
        int pos = 0;
        while (matcher.find()) {
            list.add(str.substring(pos, matcher.start()));
            list.add(matcher.group());
            pos = matcher.end();
        }
        list.add(str.substring(pos));
        return list;
    }
}

TableView:

ObservableList<Versionen> items = searchVersionen(dokumente);
final ObjectProperty<Comparator<? super Versionen>> comparator = new SimpleObjectProperty<>(new WindowsExplorerComparator());
		
SortedList<Versionen> sortedData = new SortedList<>(items);
sortedData.comparatorProperty().bind(comparator);

WindowsExplorerComparator.java

import java.util.ArrayList;
import java.util.Comparator;
import java.util.Iterator;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import app.model.Versionen;
 
public class WindowsExplorerComparator implements Comparator<Versionen> {
 
    private static final Pattern splitPattern = Pattern.compile("\\d+|\\.|\\s");
 
    @Override
    public int compare(Versionen version1, Versionen version2) {
    	
    	String str1 = version1.getVersionen();
    	String str2 = version2.getVersionen();
    	
        Iterator<String> i1 = splitStringPreserveDelimiter(str1).iterator();
        Iterator<String> i2 = splitStringPreserveDelimiter(str2).iterator();
        while (true) {
            //Til here all is equal.
            if (!i1.hasNext() && !i2.hasNext()) {
                return 0;
            }
            //first has no more parts -> comes first
            if (!i1.hasNext() && i2.hasNext()) {
                return -1;
            }
            //first has more parts than i2 -> comes after
            if (i1.hasNext() && !i2.hasNext()) {
                return 1;
            }
 
            String data1 = i1.next();
            String data2 = i2.next();
            int result;
            try {
                //If both datas are numbers, then compare numbers
                result = Long.compare(Long.valueOf(data1), Long.valueOf(data2));
                //If numbers are equal than longer comes first
                if (result == 0) {
                    result = -Integer.compare(data1.length(), data2.length());
                }
            } catch (NumberFormatException ex) {
                //compare text case insensitive
                result = data1.compareToIgnoreCase(data2);
            }
 
            if (result != 0) {
                return result;
            }
        }
    }
 
    private List<String> splitStringPreserveDelimiter(String str) {
        Matcher matcher = splitPattern.matcher(str);
        List<String> list = new ArrayList<String>();
        int pos = 0;
        while (matcher.find()) {
            list.add(str.substring(pos, matcher.start()));
            list.add(matcher.group());
            pos = matcher.end();
        }
        list.add(str.substring(pos));
        return list;
    }
}