Kuinka luen merkkijonosta (String) helposti merkin (ensimmäisen) indeksin, kun merkki on joku neljästä eri vaihtoehdosta?
Merkki on joko tai - tai * tai /
Merkki on joko tai - tai * tai /
Turvaa tilisi vahvistamalla puhelinnumerosi. Voit silloin palauttaa unohtuneen salasanan tekstiviestillä.
Näihin keskusteluihin ei ole vielä vastattu. Ole ensimmäinen.
Vastaukset 18
Vanhimmat
public void testREIndexOf()
{
Pattern pattern = Pattern.compile("[*/ -]");
Matcher matcher = pattern.matcher("Hello world! */ -");
boolean flag = matcher.find();
Assert.assertTrue(flag);
int index = matcher.start();
Assert.assertEquals(index, 13);
}
int index="12 34".split("[*/ -]")[0].length();
Suorituskyvyllisesti täysin järjetön koodinpätkä, mutta menee tosiaan yhdelle riville :)
Näppärä keino tehdä itsestään korvaamaton kirjoittamalla spagettia, josta kukaan muu ei saa mitään selvää. Tosimieshän ei dokumentoi...
Tuo matcher menee kaaliin jotenkin. Toinen vaihtoehto ????
Teen vasta approa!!!
Tämä ei ole selkein/paras tapa lähestyä ongelmaa:
==========================================
int index="12 34".split("[*/ -]")[0].length();
Alla edellinen purettuna:
==========================================
String lasku="12 34";
// Paloitellaan lasku operandien kohdilta
// Tulos on {"12"," ","34"}
String laskunOsat[]=lasku.split("[*/ -]");
// Ensimmäinen operandi tulee sitä edeltävän
// osan jälkeen. Indeksi alkaa nollasta ja
// pituus on numeroa suurempi
int ensimmaisenOperandinIndeksi=laskunOsat[0].length();
Tuota split-metodia *ei* todellakaan kannata käyttää indeksin hakuun.
Miten ongelma ratkaistaan siten että muutkin saavat koodista selvää ja ratkaisu on mahdollisimman tyylikäs?
Mikä olisi suorituskyvyllisesti tehokkain ratkaisu? Otetaanko neljä kertaa indexOf ja tuloksista pienin positiivinen vai...?
...että char[]:n läpikäynti muutamalla if:llä on suorituskyvyltään nopein vaihtoehto. Sen päivittäminen uusiin hakuehtoihin tosin on työläämpää kuin regexpin.
Eli jotain tämänsuuntaista:
public int fastIndexOf(String text)
{
if (text == null) return -1;
char[] chars = text.toCharArray();
for (int i = 0; i < chars.length; i)
if (chars[i] == '*' ||
chars[i] == '/' ||
chars[i] == ' ' ||
chars[i] == '-') return i;
return -1;
}
public int indexOf(String text, char[] chars) {
for (int i=0;i
Jos text:issä on useita "pysäytinmerkkejä" niin koodinpätkä saattaa palauttaa muunkin kuin ensimmäisen indeksin. Mikäli Java:n indexOf-metodi on hyvin optimoitu niin tämä on nopea ratkaisu.
Korjausehdotus:
============================================
public int indexOf(String text, char[] chars) {
int minIndex=-1;
for (int i=0;i
Hyvä huomio! ;)
indexOf skannaa läpi Stringin sisältämän char-taulukon, kunnes osuu haettuun merkkiin. Tuossa kirjoittamassasi koodissa taulukkoa siis skannataan niin monta kertaa läpi kuin haettavia merkkejä on.
Eli ei ole järin tehokas.
Testailin nopeuksia ja kolmesta ratkaisusta sain seuraavat ajat (silmukka 10 milj. kertaa, apuolioiden luonnit silmukassa):
36 s, yhdellä rivillä
20 s, eka regexp
4 s, indexOf
2 s, toCharArray
Ja se yhden rivin hirviö-splitti (#1) vie sitä enemmän aikaa ja muistia, mitä pidempi stringi.
Regexpin (#2) suorituskyky paranisi luultavasti huomattavasti, jos patternin alustus tehtäisiin metodin ulkopuolella:
Pattern pattern = Pattern.compile("[*/ -]");
public int reIndexOf(String text)
{
Matcher matcher = pattern.matcher(text);
if (matcher.find())
return matcher.start();
else
return -1;
}
Looppi miljoonaan kertaan (hidas kone):
char[i]: 807 ms.
indexOf(): 2403 ms.
reIndexOf(): 5267 ms.
Yhden rivin split-hirviö tukehtui jo 30-merkkiseen stringiin (meni reippaasti yli minuutin), joten jätin sen tästä viimeisestä testistä suosiolla pois (1800 merkkiä stringissä).
Jos split-metodiin lisää parametrin 2 (eli splittejä ei tehdä kuin ensimmäisestä osumasta), saadaan siitäkin tulos 100 000 iteraatiolla:
char[i]: 100 ms.
indexOf(): 337 ms.
reIndexOf(): 593 ms.
split(): 71559 ms.
Mutta surkea se on silti.