Sortowanie po wybranym kryterium

Odpowiedz Nowy wątek
2015-01-16 21:46
0

Cześć, mam taki mały problem jak napisać sortowanie po wybranym kryterium w javie. Mam klase osoba która ma pola imie, nazwisko, wiek. Obiekty są przechowywane w liście. Chciał bym je posortować po wybranym kryterium więc zaimplementowałem interfejs Comparable, a to jest kod z metody która ma sortować:

    @Override
    public int compareTo(Osoba o) {

        System.out.println("Po czym chesz sortowac " + "\n" + "1-imie" + "\n" + "2-nazwisko");
        Scanner in = new Scanner(System.in);
        int odp;
        odp = in.nextInt();
        if(odp==1)
        {
          int porownanieImienia = imie.compareTo(o.imie);
                return porownanieImienia;  
        }
        else if(odp==2)
        {
            int porownanieNazwiska = nazwisko.compareTo(o.nazwisko);
                return porownanieNazwiska;    
        }
        else 
            return -1;
    } 

Niestety w konsoli kilka razy się wypisuje linijka

Po czym chesz sortowac " + "\n" + "1-imie" + "\n" + "2-nazwisko
(pewnie metoda sie wywołuje sama w sobie) fakt faktem sortuje ale niezbyt elegancko to wygląda. Macie jakiś pomysł jak to napisać tak aby jeden raz tylko podawać kryterium sortowania, czy może trzeba samemu pisać sortowanie :P ?

edytowany 1x, ostatnio: bogdans, 2015-01-16 21:53
!Wstawiaj kod w znaczniki <code=java></code> - bogdans 2015-01-16 22:07

Pozostało 580 znaków

2015-01-16 22:05

W metodzie compareTo() powinieneś zaimplemenować tylko samo porównanie - czyli test i zwrócenie wyniku - nic więcej.
Podczas sortowania takie porównanie między różnymi obiektami zapewne będzie się wykonywało wiele razy. Dlatego pozostałe kwestie, np. zapytanie użykownika wg. jakiego kryterium chce sortować dane, powinieneś realizować w innym miejscu. Możesz sobie zrobić jakieś pole statyczne w klasie Osoba, w którym zapamiętasz kryterium i odwołasz się do niego podczas porównywania obiektów.

Pozostało 580 znaków

2015-01-16 22:14
0

Dodam jeszcze, że jeśli pytasz w metodzie compareTo(), to użytkownik może udzielać różnych odpowiedzi.
Drugi sposób (poza polem statycznym), to użycie tej https://docs.oracle.com/javas[...]st,%20java.util.Comparator%29 wersji metody sort. Domyślne sortowanie Stringów jest leksykograficzne, a nie alfabetyczne. Wyniki sortowania metodą tą https://docs.oracle.com/javas[...]html#sort%28java.util.List%29 wersją metody sort mogą Cię zaskoczyć: np. "adamski" po "Zagłobie", czy też "Łukasz" po "Zygmuncie**.


To smutne, że głupcy są tak pewni siebie, a ludzie mądrzy - tak pełni wątpliwości. Bertrand Russell

Pozostało 580 znaków

2015-01-17 12:12
0

Fajnie można to zrobić wykorzystując wzorzec Composite, robiłem kiedyś na studiach porównywanie osób za pomocą komparatora z możliwością sortowania po kilku atrybutach jednocześnie. Kod jest nieco "studencki" ale może Ci się przyda:

import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;

public class Person {

    private String LastName;
    private String FirstName;
    private String PESEL;
    private String City;
    private String Street;
    private int nr;

    public Person(String LastName, String FirstName, String PESEL, String City, String Street, int nr) {
        this.LastName = LastName;
        this.FirstName = FirstName;
        this.PESEL = PESEL;
        this.City = City;
        this.Street = Street;
        this.nr = nr;
    }

    public String toString() {
        return (LastName + "\t" + FirstName + "\t" + PESEL + "\t"+ City + "\t"+Street +"\t"+ nr + "\n");
    }

    public static class PersonComp implements Comparator<Person> {

        private List<Comparator<Person>> _child = new ArrayList<Comparator<Person>> ();
        private int wynik = 0;

        public void add( int i, Comparator<Person> arg1 ) {
            _child.add(i, arg1);
        }

        @Override
        public int compare(Person o1, Person o2) {
            for (int i=0; i<_child.size(); i++) {
                wynik = _child.get(i).compare(o1, o2);
                if (wynik != 0) return wynik;
            }
            return 0;
        }

    }

    public static class LastName implements Comparator<Person> {

        @Override
        public int compare(Person o1, Person o2) {
            return o1.LastName.compareToIgnoreCase(o2.LastName);
        }

    }

    public static class FirstName implements Comparator<Person> {

        @Override
        public int compare(Person o1, Person o2) {
            return o1.FirstName.compareToIgnoreCase(o2.FirstName);
        }

    }

    public static class City implements Comparator<Person> {

        @Override
        public int compare(Person o1, Person o2) {
            return o1.City.compareToIgnoreCase(o2.City);
        }

    }

    public static class Street implements Comparator<Person> {

        @Override
        public int compare(Person o1, Person o2) {
            return o1.Street.compareToIgnoreCase(o2.Street);
        }

    }

    public static class PESEL implements Comparator<Person> {

        @Override
        public int compare(Person o1, Person o2) {
            return o1.PESEL.compareToIgnoreCase(o2.PESEL);
        }

    } 

    public static class nr implements Comparator<Person> {

        @Override
        public int compare(Person o1, Person o2) {
            if (o1.nr > o2.nr) return 1;
            if (o1.nr == o2.nr) return 0;
            if (o1.nr < o2.nr) return -1;
            return 0;
        }

    }

}

a tutaj przykład wykorzystania:

import java.util.ArrayList;
import java.util.Collections;

public class Test { 

    public static void main(String[] args) {

        ArrayList<Person> arr = new ArrayList<Person>();

        arr.add(new Person("Kowalski", "Jan", "8511030788", "Kraków", "Karmelicka", 15));
        arr.add(new Person("Kowalski", "Grzegorz", "8510030788", "Kraków", "Karmelicka", 15));
        arr.add(new Person("Nowak", "Jan", "8511030789", "Kraków", "Karmelicka", 16));
        arr.add(new Person("Dudek", "Marian", "8609030008", "Poznań", "św. Marcina", 10));
        arr.add(new Person("Nowak", "Jan", "7509030008", "Poznań", "św. Marcina", 15));
        arr.add(new Person("Wiśniewska", "Justyna", "7001430008", "Poznań", "św. Marcina", 10));
        arr.add(new Person("Dudek", "Marian", "8609031111", "Warszawa", "Marszałkowska", 11));
        arr.add(new Person("Dudek", "Marian", "8609040008", "Poznań", "św. Marcina", 10));

        Person.PersonComp Comparator = new Person.PersonComp();
        Comparator.add(0, new Person.LastName());
        Comparator.add(1, new Person.FirstName());
        Comparator.add(2, new Person.PESEL());
        Comparator.add(3, new Person.City());
        Comparator.add(4, new Person.Street());
        Comparator.add(5, new Person.nr());

        System.out.println("Dane nieposortowane:");

        for (Person e :arr) 
            System.out.println(e);

        Collections.sort(arr, Comparator);
        System.out.println("\nDane posortowane:");
        for (Person e :arr) 
            System.out.println(e);
    }

}

Pozostało 580 znaków

2015-01-17 13:12
0

@Rafss1014 do sortowania stringów możesz sobie pomóc String.CASE_INSENSITIVE_ORDER.
jak dla mnie zamiast implementować Comparable klasie Osoba robisz w klasie osoba poszczególne statyczne finalne komparatory:

class Account {
    private String name, surname;

    public Account(String name, String surname) {
        this.name = name;
        this.surname = surname;
    }

    public String getName() {
        return name;
    }

    public String getSurname() {
        return surname;
    }

    @Override
    public String toString() {
        return name + " " + surname;
    }

    public static final Comparator<Account> NAME_CASE_INSENSITIVE = new Comparator<Account>() {
        @Override
        public int compare(Account o1, Account o2) {
            return o1.getName().compareToIgnoreCase(o2.getName());
        }
    };
}

potem używasz np. osoby.sort(Osoba.NAME_CASE_INSENSITIVE); albo np. Collections.sort(osoby,Osoba.NAME_CASE_INSENSITIVE);

inna wersja tego co wrzucił @dymul:

import java.util.Arrays;
import java.util.Comparator;
import java.util.List;

class Account {
    private String name, surname;

    public Account(String name, String surname) {
        this.name = name;
        this.surname = surname;
    }

    public String getName() {
        return name;
    }

    public String getSurname() {
        return surname;
    }

    @Override
    public String toString() {
        return name + " " + surname;
    }
}

enum AccountComparator implements Comparator<Account> {
    BY_NAME_CASE_INSENSITIVE {
        @Override
        public int compare(Account o1, Account o2) {
            return o1.getName().compareToIgnoreCase(o2.getName());
        }
    },

    BY_SURNAME_CASE_INSENSITIVE {
        @Override
        public int compare(Account o1, Account o2) {
            return o1.getSurname().compareToIgnoreCase(o2.getSurname());
        }
    };

    public static Comparator<Account> chain(final AccountComparator... comparators) {
        return new Comparator<Account>() {
            @Override
            public int compare(Account o1, Account o2) {
                for (AccountComparator ac : comparators) {
                    int result = ac.compare(o1, o2);
                    if (result != 0) {
                        return result;
                    }
                }
                return 0;
            }
        };
    }
}

public class Main {
    public static void main(String[] args) {
        List<Account> accounts = Arrays.asList(
                new Account("adamski", "gerg"),
                new Account("Zagłobie", "cccc"),
                new Account("Adamski", "GERG"),
                new Account("Adamski", "bebe")
        );
        accounts.sort(AccountComparator.chain(
                AccountComparator.BY_NAME_CASE_INSENSITIVE,
                AccountComparator.BY_SURNAME_CASE_INSENSITIVE
        ));
        System.out.println(accounts);
    }
}

lecz gdy mamy Java8, Guave to te rozwiązania są bez sensu.


PROGRAMY NA ZAMÓWIENIE, ZALICZENIA STUDENCKIE, KONFIGURACJA SERWERÓW, SYSTEMÓW I BAZ DANYCH, STRONY INTERNETOWE, POMOC W PROGRAMOWANIU, POPRAWIENIE I OPTYMALIZACJA APLIKACJI
JAVA, C++, LINUX, WWW, SQL, PYTHON
POSIADAM KOMERCYJNE DOŚWIADCZENIE
TANIO, SZYBKO I PORZĄDNIE
Z KOMENTARZAMI OBJAŚNIAJĄCYMI KOD
PISZ NA PRYWATNĄ WIADOMOŚĆ
CENY JUŻ OD 49,99ZŁ ZA PROGRAM
ZAJMIJ SIĘ TYM CO CIĘ NAPRAWDĘ INTERESUJE!

Pozostało 580 znaków

2015-01-17 14:45
0

To rozwiązania jest mało przydatne - źle sortuje polskie litery. Poniższe dobrze sortuje polskie litery i jest case insensitive

import java.text.Collator;

public class Osoba implements Comparable
{
    private String nazwisko = "";
    private String imie = "";
    public static int kryterium = 1;
    private static Collator kolator = Collator.getInstance();

    public Osoba(String nazwisko, String imie)
    {
        this.nazwisko = nazwisko;
        this.imie = imie;
    }
    @Override
    public int compareTo(Object ob)
    {
        Osoba osoba = (Osoba)ob;
        if(kryterium == 1)
        {
            return kolator.compare(this.nazwisko,osoba.nazwisko);
        }
        else
        {
            return kolator.compare(this.imie,osoba.imie);
        }
    }
    public String toString()
    {
        return imie+" "+nazwisko;
    }
}

To smutne, że głupcy są tak pewni siebie, a ludzie mądrzy - tak pełni wątpliwości. Bertrand Russell
edytowany 1x, ostatnio: bogdans, 2015-01-17 14:53
o dobrze wiedzieć. jedynie imho te statyczne pole kryterium i takie sterowanie tym jest słabe.. - karolinaa 2015-01-17 16:33
mi się podoba :P. tylko bym uodpornił na błędne użycie - bogdans 2015-01-18 07:47

Pozostało 580 znaków

2015-01-18 07:51
0

Z dedykacją dla @karolinaa, w klasie Osoba

//pola
    public enum rules
    {
        SORTING_BY_NAME,SORTING_BY_SURNAME
    };
    private static rules rule = rules.SORTING_BY_NAME;
...
    public int compareTo(Object ob)
    {
        Osoba osoba = (Osoba)ob;
        if(rule == rules.SORTING_BY_NAME)
        {
            return kolator.compare(this.nazwisko,osoba.nazwisko);
        }
        else
        {
            return kolator.compare(this.imie,osoba.imie);
        }
    }
...
    public static void setSortingRule(rules kryterium)
    {
        rule = kryterium;
    }

Na zewnątrz tej klasy

Osoba.setSortingRule(Osoba.rules.SORTING_BY_SURNAME);

To smutne, że głupcy są tak pewni siebie, a ludzie mądrzy - tak pełni wątpliwości. Bertrand Russell
edytowany 1x, ostatnio: bogdans, 2015-01-18 07:58
@bogdans a gdy mam dwie listy osób i jedną chcę posortować wdg nazwisk a drugą wdg imion ;? jednoczesnie na dwa wątki - karolinaa 2015-01-18 20:37

Pozostało 580 znaków

2015-01-20 15:12
0

Może, żeby nie kombinować zaktualizowana do Javy 8 paczka podstawowych komparatorów sortujących po każdym alfabecie narodowym znanym przez JVM z uwzględnieniem poziomów szczegółowości Unikodu. I na końcu przykładowe wykorzystania w metodzie main z użyciem lambd i referencji do metod.
Kod do wykorzystania przez każdego (wywalony tylko javadoc). Korzysta wyłącznie ze standardowych klas.

package com.olamagato.util.text;

import java.text.CollationKey;
import java.text.Collator;
import java.util.Arrays;
import java.util.Comparator;
import java.util.HashMap;
import java.util.Locale;
import java.util.Map;
import java.util.function.Function;

public class StringComparators
{
    public static <ELEMENT> Comparator<ELEMENT> compareIgnoreCase()
    {
        return compareIgnoreCase(Locale.getDefault());
    }

    public static <ELEMENT>
        Comparator<ELEMENT> compareIgnoreCase(Function<ELEMENT, String> by)
    {
        return new LocaleComparator<>(by, getInsensitiveCaseCollator(
            Locale.getDefault()));
    }

    public static <ELEMENT> Comparator<ELEMENT> compareIgnoreCase(Locale locale)
    {
        return new LocaleComparator<>(getInsensitiveCaseCollator(locale));
    }

    public static <ELEMENT> Comparator<ELEMENT>
        compareIgnoreCase(Function<ELEMENT, String> by, Locale locale)
    {
        return new LocaleComparator<>(by, getInsensitiveCaseCollator(locale));
    }

    public static <ELEMENT> Comparator<ELEMENT> compare()
    {
        return compare(Locale.getDefault());
    }

    public static <ELEMENT>
        Comparator<ELEMENT> compare(Function<ELEMENT, String> by)
    {
        return new LocaleComparator<>(by, getSensitiveCaseCollator(
            Locale.getDefault()));
    }

    public static <ELEMENT> Comparator<ELEMENT> compare(Locale locale)
    {
        return new LocaleComparator<>(getSensitiveCaseCollator(locale));
    }

    public static <ELEMENT>
        Comparator<ELEMENT> compare(Function<ELEMENT, String> by, Locale locale)
    {
        return new LocaleComparator<>(by, getSensitiveCaseCollator(locale));
    }

    //właściwy obiekt komparatora
    private static class LocaleComparator<ELEMENT>
        implements Comparator<ELEMENT>
    {
        private final Map<ELEMENT, CollationKey> cache = new HashMap<>();
        private final Collator collator;
        private final Function<ELEMENT, String> by;

        protected LocaleComparator(Collator collator)
        {
            this.collator = collator;
            this.by = ELEMENT::toString;
        }

        protected LocaleComparator(Function<ELEMENT, String> by,
            Collator collator)
        {
            this.collator = collator;
            this.by = by;
        }

        @Override public int compare(ELEMENT left, ELEMENT right)
        {
            CollationKey leftCollatorKey =
                cache.get(left), rightCollationKey = cache.get(right);
            if(leftCollatorKey == null)
            {
                leftCollatorKey = collator.getCollationKey(by.apply(left));
                cache.put(left, leftCollatorKey);
            }
            if(rightCollationKey == null)
            {
                rightCollationKey = collator.getCollationKey(by.apply(right));
                cache.put(right, rightCollationKey);
            }
            return leftCollatorKey.compareTo(rightCollationKey);
        }

    }

    private static Collator getSensitiveCaseCollator(Locale locale)
    {
        final Collator result = Collator.getInstance(locale);
        result.setStrength(Collator.SECONDARY);
        return result;
    }

    private static Collator getInsensitiveCaseCollator(Locale locale)
    {
        final Collator result = Collator.getInstance(locale);
        result.setStrength(Collator.TERTIARY);
        return result;
    }

    private StringComparators() {}

    @SuppressWarnings("UseOfSystemOutOrSystemErr")
    public static void main(String[] args)
    {
        class Osoba implements Comparable<Osoba>
        {
            public Osoba(String imię, String nazwisko, int wiek)
            {
                this.imię = imię;
                this.nazwisko = nazwisko;
                this.wiek = wiek;
            }
            @Override public int compareTo(Osoba other)
            {
                return this.imię.compareToIgnoreCase(other.imię);
            }
            @Override public String toString()
            {
                return imię + ' '+ nazwisko + ' ' + wiek + " lat";
            }
            public String getImię() { return imię; }
            public String getNazwisko() { return nazwisko; }
            public int getWiek() { return wiek; }

            private final String imię;
            private final String nazwisko;
            private final int wiek;
        }

        int wiek = 27;
        Osoba[] osoby =
        {
            new Osoba("Jan", "Kowalski", wiek += 3),
            new Osoba("Ola", "Englert", wiek += 3),
            new Osoba("Ola", "Łasica", wiek),
            new Osoba("Ryszard", "Ludwik", wiek -= 15),
            new Osoba("Tadeusz", "Nidzicki", wiek),
            new Osoba("Tadeusz", "Ówczesny", wiek),
            new Osoba("Kizia", "Mizia", wiek += 3),
            new Osoba("Jurek", "Pachoł", wiek -= 12),
            new Osoba("Jurek", "Łomnicki", wiek -= 2),
            new Osoba("Michał", "Jasienica", wiek += 3),
            new Osoba("Dariusz", "Ryk", wiek -= 8),
            new Osoba("Tomek", "Kowalski", wiek += 3),
        };

        System.out.println("Kolejność oryginalna:");
        Arrays.stream(osoby).forEachOrdered(osoba -> System.out.println(osoba));

        System.out.println("\nWg niczego oryginalnie:");
        Arrays.<Osoba>sort(osoby);
        Arrays.stream(osoby).forEachOrdered(osoba -> System.out.println(osoba));

        System.out.println("\nWg niczego zlokalizowane:");
        Arrays.<Osoba>sort(osoby, StringComparators.compareIgnoreCase());
        Arrays.stream(osoby).forEachOrdered(osoba -> System.out.println(osoba));

        System.out.println("\nWg imienia i nazwiska:");
        Arrays.<Osoba>sort(osoby, StringComparators
            .compare(osoba -> osoba.imię + " " + osoba.nazwisko));
        Arrays.stream(osoby).forEachOrdered(osoba -> System.out.println(osoba));

        System.out.println("\nWg nazwisk:");
        Arrays.<Osoba>sort(osoby, StringComparators
            .compare(Osoba::getNazwisko));
        Arrays.stream(osoby).forEachOrdered(osoba -> System.out.println(osoba));

        System.out.println("\nWg wieku i imienia:");
        Arrays.<Osoba>sort(osoby, StringComparators.compare(osoba -> String
            .format("%02d%s", osoba.wiek, osoba.imię))
        );
        Arrays.stream(osoby).forEachOrdered(osoba -> System.out.println(osoba));
    }
}

Jeżeli ktoś komuś coś, ewentualnie nikt nikomu nic, to właściwie po co...?

Pozostało 580 znaków

Odpowiedz
Liczba odpowiedzi na stronę

1 użytkowników online, w tym zalogowanych: 0, gości: 1, botów: 0