indexOf

Kuinka luen merkkijonosta (String) helposti merkin (ensimmäisen) indeksin, kun merkki on joku neljästä eri vaihtoehdosta?

Merkki on joko tai - tai * tai /
18731
Äänestä

Muut lukivat myös

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);
}

Äänestä
  • int index="12 34".split("[*/ -]")[0].length();

    Äänestä

  • juu kirjoitti:

    int index="12 34".split("[*/ -]")[0].length();

    Suorituskyvyllisesti täysin järjetön koodinpätkä, mutta menee tosiaan yhdelle riville :)

    Äänestä

  • ~~~ kirjoitti:

    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...

    Äänestä

  • zustus kirjoitti:

    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!!!

    Äänestä

  • RailiXZ kirjoitti:

    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();

    Äänestä

  • juu kirjoitti:

    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.

    Äänestä

Miten ongelma ratkaistaan siten että muutkin saavat koodista selvää ja ratkaisu on mahdollisimman tyylikäs?

Äänestä

Mikä olisi suorituskyvyllisesti tehokkain ratkaisu? Otetaanko neljä kertaa indexOf ja tuloksista pienin positiivinen vai...?

Äänestä
  • ...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;
    }

    Äänestä

  • ~~~ kirjoitti:

    ...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

    Äänestä

  • fani__ kirjoitti:

    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

    Äänestä

  • juu kirjoitti:

    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! ;)

    Äänestä

  • juu kirjoitti:

    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

    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.

    Äänestä

  • ~~~ kirjoitti:

    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

    Äänestä

  • juu kirjoitti:

    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;
    }

    Äänestä

  • juu kirjoitti:

    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

    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ä).

    Äänestä

  • ~~~ kirjoitti:

    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.

    Äänestä

Kommentoi aloitusta


RailiXZ kirjoitti:

Kuinka luen merkkijonosta (String) helposti merkin (ensimmäisen) indeksin, kun merkki on joku neljästä eri vaihtoehdosta?

Merkki on joko tai - tai * tai /

Anonyymi
5000

Ilmoita asiaton sisältö

  • Sisältää materiaalia, joka on loukkaavaa, herjaavaa, rasistista, uhkailevaa tai ahdistelevaa.

  • Materiaali sisältää nimiä, yhteystietoja tai muita henkilökohtaisia tietoja. Julkisuuden henkilöistä, julkisissa viroissa toimivista ihmisistä sekä yritysten vastuuhenkilöistä saa keskustella työhön liittyen. Myös yksityiselämään liittyvistä asioista voi keskustella siltä osin, kuin niistä on julkisesti kerrottu.

  • Sisältää lapsille haitallista tai heiltä kiellettyä materiaalia. Seksuaalinen sisältö on sallittua aiheeseen tarkoitetuilla palstoilla, joiden ikäraja on 18 vuotta.

  • Lainvastaista sisältöä voi olla mm. yksityiselämää loukkaavan tiedon levitys, kiihottaminen kansanryhmää vastaan, laiton uhkaaminen, alaikäisiin liittyvä seksuaalinen sisältö/grooming, petokset, identiteettivarkaudet, kunnianloukkaukset ja tekijänoikeusrikkomukset.

  • Sisältö ei liity palstan tai keskusteluketjun aiheeseen.

  • Viesti ei ole suomea tai ruotsia (pl. International Forums), se sisältää mainontaa, se sisältää tekijänoikeuksin suojattua materiaalia, se on massapostitus tai jokin muu syy.

Jaa keskustelu