Kirjautuminen

Haku

Tehtävät

Keskustelu: Ohjelmointikysymykset: Java: compareTo

Sivun loppuun

hevonen [16.11.2008 00:06:23]

#

1. Miten compareTo toimii tarkalleen?
Toimiiko se kuin matematiikan miinus -merkki. Huomasin, että vaihtojärjestämisessä oltiin kirjoitettu vain yksi kohta eri tavalla:

Koodi1: Ilman compareTo:ta

if (taulu[i] > taulu[j]) {...

Koodi2: CompareTo:n kanssa

if (taulu[i].compareTo(taulu[j]) > 0) {...

Nämä koodipätkät tarkoittavat samaa.
Matemaattisesti Koodi1:sestä saadaan:
Koodi3:

if (taulu[i] - taulu[j] > 0) {...

mikä on mielestäni oikein, koska taulun solut ovat numeroita.

2. Käytetäänkö siis Koodi3:sta vain siksi, että taulun solut ovat joskus kirjaimia?

Eli compareTo:n tarkoitus on ilmeisesti: sama kuin "miinus-merkin numeroille", mutta kirjaimille. Ehkä compareTo laskee sanojen kirjamien määrän ja näin vertaus on mahdollinen. Javadocin mukaan tämä vertaus tapahtuu "lexicographically".

Metabolix [16.11.2008 01:28:42]

#

Yksi vertailu (<, = tai >) sisältää vain kaksi vaihtoehtoa: tosi ja epätosi. Tällaisella vertailulla sen sijaan saadaan aikaan kaikki kolme vaihtoehtoa yhdellä funktiokutsulla, jolloin ohjelmasta tulee tehokkaampi. Jos kyseessä on esimerkiksi teksti ja vertailu tapahtuu aakkosellisesti, voi olla, että pitkää tekstiä joudutaan tutkimaan tuhansia merkkejä ennen eron löytymistä. Jos ohjelmassa olisi erikseen vertailut a < b ja a == b, jouduttaisiin nämä tuhat merkkiä tutkimaan molemmilla kerroilla. Kun käytetään funktiota compareTo, saadaan toinen kerta optimoitua pois: kun (jos) eroa löytyy, saadaan suoraan selville oikea järjestys.

Funktio toimii juuri tällä logiikalla, jonka itsekin havaitsit. Vertailuperuste voi olla mikä tahansa, mutta joka tapauksessa ajatuksena on, että
a < b <=> a.compareTo(b) < 0
a > b <=> a.compareTo(b) > 0
a == b <=> a.compareTo(b) == 0.
Vertailutapa tietenkin luokasta. Tekstin tapauksessa usein vertaillaan merkkien ASCII-arvoja, mikä vastaa aakkosellista vertailua, jos teksti koostuu vain isoista tai vain pienistä kirjaimista.

Optimoinnista vielä käytännön esimerkki:

if (a < b) {
  // vertailtiin kerran kaikkia tuhatta merkkiä
} else if (a == b) {
  // vertailtiin uudestaan kaikkia tuhatta merkkiä
} else {
  // nyt onneksi loogisesti a > b
}
tulos = a.compareTo(b); // vertaillaan kerran
if (tulos < 0) {
  // a < b
} else if (tulos == 0) {
  // a == b
} else {
  // a > b
}

hevonen [16.11.2008 04:00:24]

#

Kiitos vastauksesta!

Itse pidän yhden vertailun käytöstä (<, > ja =).
Onko tilanteita, joissa minun on pakko käyttää compareTo:ta?

FooBat [16.11.2008 05:38:47]

#

Tuo optimointiesimerkki on hiukan harhaanjohtava, kun tuollaista tilannetta ei javassa oikein pääse tulemaan. <,= ja > operaattorit on määritelty vain luvuille eikä niitä siten voi käyttää stringien vertailuun. Lisäksi ne toimivat myös lukujen objekti wrappereille (Interger, Long yms.), jolloin virtuaalikone tekee luvuille automaattisen muunnoksen natiiveiksi lukutyypeiksi. Alkuperäisessä esimerkissä sinulla Hevonen oli varmaan taulukko Integer-olioita, joita voi vertailla sekä <,=,> -operattoreilla, että luokkan compareTo-metodilla.

compareTo-metodin oikea tarkoitus on siis mahdollistaa olioiden vertaileminen keskenään. Kaikille luokkien vertailuille pitää siis käyttää compareTo-metodia.

compareTo:n mielenkiintoisin ominaisuus on se, että voit toteuttaa omalle luokalle compareTo-metodin ja määritellä luokan perivän Comparable rajapinnan. Tällöin voit esimerkiksi käyttää suoraan omalla luokallasi java-apin mukana tulevia järjestely-luokkia tai tietorakenteita, jotka perustuvat olioiden järjestykseen. Oliosi järjestyvät automaattisesti haluamaasi järjestykseen, kunhan vain compareTo-metodissa osaat päättää onko parametrinä tuleva toinen olio pienempi (aikaisempi), yhtäsuuri tai suurempi (myöhempi) kuin nykyisen olio. Tämän päätöksen mukaan palauta esimerksi -1,0 tai 1 (mikä tahansa negatiivinen tai positiivinen luku käy ensimmäisessä ja viimeisessä tapauksessa). Tällöin voit tietenkin myös itse vertailla omia olioitasi compareTo metodin avulla.

Metabolix [16.11.2008 12:29:54]

#

FooBat kirjoitti:

Tuo optimointiesimerkki on hiukan harhaanjohtava, kun tuollaista tilannetta ei javassa oikein pääse tulemaan.

Joo, puhuin tosiaan hieman muiden kielten näkökulmasta. Vastaavia tapauksiahan ovat esimerkiksi C:n memcmp ja strcmp.

hevonen [16.11.2008 17:28:11]

#

FooBat kirjoitti:

compareTo-metodissa osaat päättää onko parametrinä tuleva toinen olio pienempi (aikaisempi), yhtäsuuri tai suurempi (myöhempi) kuin nykyisen olio

ja näin sama asia lukee java-apissa

java-api kirjoitti:

- - a value less than 0 if this string is lexicographically less than the string argument; and a value greater than 0 if this string is lexicographically greater than the string argument.

Mitä tarkoitat, että olio A on aikaisempi kuin olio B?
Ehkä tarkoitat, että olio A ilmestyy koodissa ennen olio b:tä. Toisin sanoen ilmeisesti tarkoitat, että java -tulkki lukee olio A:n ennen olio B:tä.

Metabolix [16.11.2008 17:39:27]

#

hevonen kirjoitti:

Mitä tarkoitat, että olio A on aikaisempi kuin olio B?

Onko se noin vaikea lukea noista pätkistä, joita itsekin lainasit? Olio "luku 1" on pienempi eli numerojärjestykseen järjestetyssä taulukossa aikaisempi kuin "luku 2", ja näitä molempia suurempi eli myöhäisempi on esimerkiksi "luku 513". Onko vaikeaa? Voidaan määritellä vaikkapa luokka "Ihminen", jolla on ominaisuudet "pituus" ja "paino" ja funktio compareTo, joka laskee näistä painoindeksit ja vertailee niitä. Kun ihmiset sitten järjestetään, voi olio "Pekka" olla ensimmäinen, "Liisa" toinen ja "Matti" kolmas, jos compareTo antaa tällaisen tuloksen (eli jos painoindeksit menevät tässä järjestyksessä).

Päärynämies [16.11.2008 18:04:30]

#

http://java.sun.com/javase/6/docs/api/java/lang/Comparable.html

Jos englanti taipuu, niin yllättäen dokumentaatiostakin voi olla apua, jos et tuota vielä oe lukennut. Eri luokat voivat siis toteuttaa tuon Comparable -rajapinnan toteuttamalla tuon CompareTo -metodin. Se on sitten jokaisen luokan oma asia, miten se sen tekee.

hevonen [16.11.2008 18:57:24]

#

@Metabolix: Nyt ymmärsin. Eli Ihmis -esimerkissä vertaus tapahtuu painoindeksin suhteen. Näin henkilöt voidaan järjestää.

@Päärynämies: Kiitos linkistä! Linkki antoi vahvistuksen sille, että compareTo "is an equivalence relation on" such that the natural ordering is a total order on C. C is a given class in Java api.


Sivun alkuun

Vastaus

Aihe on jo aika vanha, joten et voi enää vastata siihen.

Tietoa sivustosta