Pikku selvitys enste
$arr = array(0,4,8,12,16,20,24,28,32,36,40); $tulos = 25; #tässä pitäisi löytää arraysta eka-arvo joka on suurempi kuin $tulos eli arvo 28
Miten tuollainen etsintä tapahtuisi näppärimmin?
Tässä oletetaan taulukon olevan aina järjestyksessä. Suuremmille taulukoille voisi harkita jotakin fiksumpaa hakua. Esimerkiksi puolitushakua vaikka pari kertaa, jolloin hakujoukko olisi hiukan pienempi. Tosin tämäkin taitaa olla ihan tarpeeksi nopea muutaman sadan alkion taulukoille?
Kiitos.
Ei tässä varmaa kauheita määriä kannata tauluun laittaa.
Ja tuo haku tarvitsee tehdä yhden ainoan kerran...
Toimiva vastaus tuli jo yllä, mutta suosittelen käyttämään selkeämpää foreachia vanhanaikaisen forin tilalla:
Tässä on oma versiona. Tämä funktio mahdollistaa vielä sen, ettei taulukon alkioiden tarvitse olla edes järjestyksessä, tosin jos alkiot ovat jokatapauksessa järjestyksessä, niin silloin on tehokkaampaa käyttää jotain noista ylläolevista.
function lahin_arvo( $etsittava, $taulukko ) { foreach ( $taulukko as $alkio ) { if ( $alkio > $etsittava && ( $alkio < $suurempi || is_null( $suurempi ) ) ) { $suurempi = $alkio; } } return $suurempi; }
Chiman kirjoitti:
suosittelen käyttämään selkeämpää foreachia vanhanaikaisen forin tilalla
En kutsuisi for-rakennetta mitenkään vanhanaikaiseksi, sillä foreachin käyttäminen rajottuu vain tiettyihin erikoistapauksiin (taulukon läpikäyminen), tosin juuri tähän ongelmaan se käy mainiosti ratkaisuksi.
Triton kirjoitti:
En kutsuisi for-rakennetta mitenkään vanhanaikaiseksi, sillä foreachin käyttäminen rajottuu vain tiettyihin erikoistapauksiin (taulukon läpikäyminen), tosin juuri tähän ongelmaan se käy mainiosti ratkaisuksi.
Ilmaisin mielipiteeni epäselvästi. Tarkoitin vanhanaikaisuudella for-silmukan käyttöä juuri taulukon läpikäynnissä. Jos halutaan käydä läpi taulukon alkiot, selkein keino siihen (mm. PHP:ssä) on foreach. Jos kohteena on sarja kokonaislukuja, for on hyvä vaihtoehto.
Koodissasi vaihtaisin iffin kaksi viimeistä ehtoa keskenään. Ensin null-tarkistus, sitten suuruus.
Chiman kirjoitti:
vaihtaisin iffin kaksi viimeistä ehtoa keskenään. Ensin null-tarkistus, sitten suuruus.
Onks tolla jotain merkitystä? Mieluummin alustaa ton muuttujan funkkarin alussa ihan jo selkeyden takia, ja alustaa sen vaikka taulukon ekaan arvoon niin koko null-tarkistuksen voi jättää pois.
EDIT: Nii ja nykyäänhä voi käyttää kivoja lambda-funkkareita,
No onhan sillä väliä, että yrittääkö käyttää olematonta / alustamatonta muuttujaa vai ei. Joissain toisissa ohjelmointikielissä se johtaisi koko ohjelman kaatumiseen, ja parhaassakin tapauksessa lähdekoodi ei kääntyisi. PHP:ssä se aiheuttaa notification-tason ilmoituksen ("Undefined variable"). Huonoa ohjelmointia.
For-silmukan stoppiehtona ei kannata käyttää count-funktiota vaan ottaa kyseinen arvo talteen muuttujaan, koska ainakaan oma PHP-tulkkini ei osaa kyseisen funktion arvoa cachettaa vaan taulukon koko lasketaan joka kierroksella uudestaan. Tuloksena siis melkolailla hitaampi suoritus.
Simppelin silmukkatestin mukaan for olisi kolmisen kertaa foreachia hitaampi. Sinällään ihan ymmärrettävää, kun foreach on helpompi optimoida sisäisesti.
The Alchemist kirjoitti:
No onhan sillä väliä, että yrittääkö käyttää olematonta / alustamatonta muuttujaa vai ei.
Ei noiden ehtojen järjestely siihen mitään auta, vaa se alustaminen, niin kuin jo suosittelinkin.
PHP:ssä on pari funktiontapaista muuttujan olemassaolon tarkasteluun: isset ja empty. Is_null ei itse asiassa kelpaa, koska se vaatii olevaisen muuttujan.
Luepa nyt, mitä Chiman ehdotti
Chiman kirjoitti:
vaihtaisin iffin kaksi viimeistä ehtoa keskenään
Ihan saman E_NOTICEn
tuo heittää.
Totta kai on validi ratkaisu tutkia, että onko sitä muuttujaa olemassa, mutta järkevämpihän se on alustaa ettei joka kierroksella tarvitse tutkia.
Joo... monissa tilanteissa on hyvä tietää, tarvitseeko edes etsiä jotakin asiaa jostakin...jos sitä ei siellä ole, miksi ihmeessä etsiä ollenkaan..? :)
No, tähän minun hommaan soveltuu tuo ekahomma (chiman) hyvin. Lisäsin vaan vielä tarkistuksen, että jos $arvo on sama kuin $tulos, niin silloinkin tehdään jotakin... lisätään $arvon lukua neljällä.
Kyseessä on simppeli taulukko, jossa kullakin rivillä on neljä solua, arrayn jokainen arvo on taulukossa olevan kunkin rivin ensimmäinen solu. Koska tässä saattaa pikkusoluja tulostua jopa sata ja niiden tarkka määrä on etukäteeen arvaamaton, niin siksi tällainen viritelmä.
Kiitoksia vielä!
Hyvä pointti tuo noticen lentäminen is_nullista. Huolimattomuusvirhe minulta.
tsuriga kirjoitti:
Chiman kirjoitti:
vaihtaisin iffin kaksi viimeistä ehtoa keskenään. Ensin null-tarkistus, sitten suuruus.
Onks tolla jotain merkitystä? Mieluummin alustaa ton muuttujan funkkarin alussa ihan jo selkeyden takia, ja alustaa sen vaikka taulukon ekaan arvoon niin koko null-tarkistuksen voi jättää pois.
Tritonin koodin logiikka ei toimi, jos muuttuja alustetaan taulukon ekaan arvoon. Kyseinen koodi siis etsii koko taulukosta suuruudeltaan argumenttia seuraavan arvon, vaikka taulukon sisältö olisi järjestämätön. Alustaminen NULLiksi on kuitenkin paikallaan.
Aini :), unehtu hieman funkkarin käyttötarkoitus. Tonin koodin tapauksessa päästään ylimääräisestä tarkistuksesta silmukassa alustamalla $suurempi
arvoon PHP_INT_MAX
. Funktion lopussa pitää sitten miettiä, että verrataanko suurinta taas tuohon maksimiarvoon, vai käytetäänkö apumuuttujaa. Jälkimmäinen ehkä se semanttisempi vaihtoehto (TM). Jos halutaan toimia samoin kuin useimmat PHP:n omat funktiot (sanotaan nyt varauksella PHP:n ollessa kyseessä), voidaan etsinnän ollessa tulokseton palauttaa false
.
Joo, no tuo funktio nyt oli aika lennossa tehty ja koska en jaksanut sen enempää miettiä, että miten alusta tuon $suurempi
-muuttujan, päätin hoitaa sen tuossa if-lauseessa.
tsuriga kirjoitti:
Aini :), unehtu hieman funkkarin käyttötarkoitus. Tonin koodin tapauksessa päästään ylimääräisestä tarkistuksesta silmukassa alustamalla
$suurempi
arvoonPHP_INT_MAX
. Funktion lopussa pitää sitten miettiä, että verrataanko suurinta taas tuohon maksimiarvoon, vai käytetäänkö apumuuttujaa. Jälkimmäinen ehkä se semanttisempi vaihtoehto (TM). Jos halutaan toimia samoin kuin useimmat PHP:n omat funktiot (sanotaan nyt varauksella PHP:n ollessa kyseessä), voidaan etsinnän ollessa tulokseton palauttaafalse
.
Tarkoitus oli hakea taulukosta pienin annettua lukua suurempi luku. Loogisesti siis $suurempi kannattaisi alustaa vaikka arvoon $luku-1, koska se on automaattisesti mahdoton vastaus. Lopuksi tarkistaa, että onko $suurempi oikeasti suurempi, ja palauttaa sen mukaan.
Silloin alkiot ovat aina suurempia kuin kuin suurin, eikä suurinta koskaan uudelleenaseteta. Tai sitten joudutaan lisäämään taas jotain uutta sinne silmukan ehtolausekkeisiin.
Pekka Mansikka kirjoitti:
Kyseessä on simppeli taulukko, jossa kullakin rivillä on neljä solua, arrayn jokainen arvo on taulukossa olevan kunkin rivin ensimmäinen solu.
Siis onko taulukossa aina neljän kertotaulu? Miksi sitten kikkailet taulukon kanssa, kun kaiken voi helposti laskeakin? Luultavasti käytät suunnilleen seuraavia tietoja:
// Solun numero rivin alkukohdaksi: // 0..3 => 0, 4..7 => 4, 8..11 => 8 function rivin_alku($solu, $pituus = 4) { return $solu - $solu % $pituus; } // Solujen määrä rivien määräksi: // 0 => 0, 1..4 => 1, 5..8 => 2, 9..12 => 3 function riveja($soluja, $pituus = 4) { return intval(($soluja + $pituus - 1) / $pituus); // return rivin_alku($soluja - 1, $pituus) / $pituus + 1; }
tsuriga kirjoitti:
Silloin alkiot ovat aina suurempia kuin kuin suurin, eikä suurinta koskaan uudelleenaseteta. Tai sitten joudutaan lisäämään taas jotain uutta sinne silmukan ehtolausekkeisiin.
En ymmärrä yhtään, mitä yrität sanoa, mutta ratkaisuni on toimiva.
The Alchemist, jos $raja = 5 ja $suurempi = 4 ja $taulukko = array(6, 7), mitä silmukassa tapahtuu? Tähän mennessä ehdotetulla silmukalla tulokseksi tulisi 4, vaikkei sitä edes ole taulukossa.
Eihän tule. Ei ole mitään järkeä palauttaa kokonaislukua vastaukseksi, jos vastausta ei ole. Esimerkiksi se ehdotettu false tai sitten null kelpaa hyvin. $suurempi-muuttujaa ei voi alustaa kummaksikaan noista, jos haluaa tehdä asiat oikein ja lisäksi välttää turhia tarkisteluita, koska vertailu nullin kanssa aiheuttaa noticen ja false taas evaluoituu nollaksi.
The Alchemist kirjoitti:
Lopuksi tarkistaa, että onko $suurempi oikeasti suurempi, ja palauttaa sen mukaan.
Miten niin vastausta ei ole? Piti hakea pienin rajaa suurempi luku, joka tuossa tapauksessa on aivan yksiselitteisesti 6. Ehkäpä menet nyt lukemaan sen alkuperäisen tehtävän uudestaan.
Muotoillaan kysymykseni selvemmin:
function haku($raja = 4, $taulukko = array(6, 7)) { // The Alchemistin ehdottama alustus: $suurempi = $raja - 1; // Tutkitaan taulukko. foreach ($taulukko as $x) { // KYSYMYS: Mitä tänne? if ($raja < $x && $x < $suurempi) ei sovi! } // Palautetaan tulos. Tästä ei ollut mitään väittelyä. if ($suurempi > $raja) return $suurempi; if ($suurempi == $raja) return $raja + 4; return false; }
Mikä siinä nyt on niin vaikeaa?
$raja < $x && ($suurempi < $raja || $x < $suurempi)
Tuon kun olisit laittanu vastauksees niin olis säästytty paljolta. Tulevaisuudessa olis hienoa, jos viestiin vastatessasi ottaisit oikeasti huomioon sen viestin koko sisällön, johon olet vastaamassa. Nyt tuli seittemän viestiä myöhemmin tarkennus, että "ai niin, koodin pitää tehdä myös tällainen muutos...". Tossahan $suurempi
on sama alustaa nollaksi (positiivisilla luvuilla), säästytään siltäkin aritmetiikalta. Lisäksi tuo PHP_INT_MAXiin
alustaminen on nopeampi vaatiessaan vähemmän vertailuja silmukassa.
Ei olekaan vaikeaa, mutta mitä hyötyä tuosta on verrattuna aiempaan is_null- tai vaikka is_bool-ratkaisuun? Silloin säästyisi silmukan jälkeenkin yksi tarkistus, kun ei tarvitsisi tarkistaa, löytyikö nyt jotain vai ei.
"Loogisesti" ei siis kannata käyttää tuollaista arvoa, joka vaatii lisätarkistuksen. Loogisesti kannattaa käyttää tsurigan ehdottamaa PHP_MAX_INT-arvoa, jolloin silmukassa riittää tarkistus yhteen suuntaan. Jos on pienikin epäilys, että kyseinen arvo voi esiintyä taulukossa luonnostaan, kannattaa vaihtaa nulliin tai falseen, joiden merkityksen satunnainen koodin lukija ymmärtää ilman kommenttejakin paremmin kuin tuollaisen hatusta vedetyn $raja-1:n.
Sinun logiikallasi olisi aika kätevää laittaa siihen alkuarvoksi "porkkana", joka on sekin ilmeisen mahdoton vastaus itse kysymykseen ja vaatii aivan yhtä paljon turhaa koodia. >_>
Tässä tulee taas vastaan PHP:n huonous. Minusta ei ainakaan ole kovin loogista, että kokonaislukumuuttujaan asetetaan (tai relevantimmin, voi asettaa) arvoksi null tai boolean arvo. Tuo on muutenkin huono tapa, sillä sellaisissa kielessä, jotka ovat vahvasti sekä staattisesti tyypitetty, ei voi noin edes tehdä. Hyvä esimerkki on vaikka Java. Tietenkin tilanne on siinä mielessä eri, että PHP:ssä muuttujilla ei ole kiinteesti määritettyjä tyyppejä, mutta itse ainakin pyrin aina asettamaan muuttujaan vain tietynlaisia arvoja.
Minusta taas ei voi sanoa, että jokin ratkaisu olisi huono vain siksi, että jossain muussa kielessä ei voi tehdä niin. Vaikka useimmissa tilanteissa olenkin samaa mieltä sekä heikon että dynaamisen tyypityksen ongelmista, yleispätevä null-arvo on usein käytännöllinen. Jos null-vaihtoehtoa ei ole, käytetään usein apumuuttujaa tai ehdotettua PHP_MAX_INT-tyyppistä ratkaisua tai – tällaisessa tapauksessa – parhaan löydetyn arvon indeksiä tai osoitinta. Null-arvon kanssa ei kuitenkaan tarvitse miettiä, oliko juuri tämän muuttujan kohdalla tyhjän merkkinä 0, -1 vai MAX_INT tai tuliko se apumuuttujakin nyt asetettua oikein.
Mutta kun nyt mainitsit, niin näytänpä vielä ihan ilkeyttäni, että kyllähän se Javakin toimii aivan samalla tavalla:
int[] luvut = {1, 2, 3, 4}; int raja = 5; Integer suurempi = null; for (int i = 0; i < luvut.length; ++i) { if (luvut[i] >= raja && (suurempi == null || luvut[i] < suurempi)) { suurempi = luvut[i]; } } if (suurempi == null) { System.out.println("Ei tulosta: " + suurempi); } else { System.out.println("Tulos: " + suurempi); }
Triton kirjoitti:
Tässä tulee taas vastaan PHP:n huonous. Minusta ei ainakaan ole kovin loogista, että kokonaislukumuuttujaan asetetaan (tai relevantimmin, voi asettaa) arvoksi null tai boolean arvo.
Anteeksi mihin? Ei PHP:ssä ole kokonaislukumuuttujia, vaan ihan vaan muuttujia.
Metabolix: Olen kyllä tietoinen, että Javassa voi käyttää olioversioita primitiivisistä tietotyypeistäkin. Näitä nk. wrappereitähän joutuu käyttämään myös mm. geneeristen luokkien yhteydessä. ;)
Itse pidän siitä, että ohjelmointikielet ovat keskenään mahdollisimman yhdenmukaisia, etenkin kun kyseessä on saman sukuiset kielet (ja näinhän PHP:n ja Javan tapauksessa myöskin on).
Grez: Niin, kuten sanoin, pyrin itse käyttämään PHP:tä siten, että käytän muuttujia niin, etten aseta yhteen muuttujaan kuin kokonaislukuja ja toiseen vain liukulukuja jne... Vaikkei PHP:ssä teknisesti ottaen olekaan kuin vain muuttujia, niin oman ajattelu tapani takia kirjoitin mitä kirjoitin. Tosin olen siitä huolimatta melko varma, että ymmärsit tasan tarkkaan sen, mitä kirjoitin.
Kyllä minun mielestä olet ymmärtänyt hieman nurinkurisesti, kun sanot että PHP:n tapa toimia ei olisi kovin loogista.
Minusta olisi monta kertaluokkaa epäloogisempaa, jos tyypitön muuttuja, eli muuttuja mihin voi asettaa mitä tahansa, muuttuisi yhtäkkiä tyypitetyksi muuttujaksi esimerkiksi, kun siihen sijoitetaan kokonaisluku.
Se, että PHP:ssä muuttujat ei ole vahvasti tyypitettyjä ei ole mikään epäloogisuus vaan suunnittelupäätös. On monia muitakin kieliä, joissa muuttujat ei ole vahvasti tyypitettyjä. Toki voidaan olla sitä mieltä että suunnittelupäätös on huono, mutta ihan loogisesti ja johdonmukaisesti sitä suunnittelupäätöstä PHP:ssä noudatetaan.
Toki muuttujien käyttö PHP-koodissa voi olla epälogista, mutta sekään nyt taas ei ole mitenkään PHP:n huonous vaan koodarin huonous. Muuttujia voi käyttää monilla tavoilla epäloogisesti myös vahvasti tyypitetyissä kielissä. Jos koodari ei osaa koodata loogisesti tyypittämättömässä kielessä, niin koodarin kannattanee käyttää jotain muuta kieltä.
Jos kaikki tykkäisivät tehdä kaikki asiat samalla tavalla, niin meillä ei varmaan olisi kuin yksi ohjelmointikieli.
Ja itsehän en myöskään pidä PHP:stä.
Triton kirjoitti:
Itse pidän siitä, että ohjelmointikielet ovat keskenään mahdollisimman yhdenmukaisia, etenkin kun kyseessä on saman sukuiset kielet (ja näinhän PHP:n ja Javan tapauksessa myöskin on).
Toisaalta on rikkaus, että ohjelmointikielet ovat erilaisia, ja joka ratkaisussa on omat hyvät ja huonot puolensa. Kysymys ei ole siitä, että PHP:n tekijät ovat yrittäneet tehdä Javan kopion mutta epäonnistuneet siinä tyhmyyttään.
PHP on siinä mielessä monipuolisempi, että se tarjoaa molemmat vaihtoehdot: joko voi käyttää samaa muuttujaa aina samantyyppisenä (kuten itse teet) tai sitten vaihdella muuttujan tyyppiä tarpeen mukaan.
Antti Laaksonen kirjoitti:
PHP on siinä mielessä monipuolisempi, että se tarjoaa molemmat vaihtoehdot: joko voi käyttää samaa muuttujaa aina samantyyppisenä (kuten itse teet) tai sitten vaihdella muuttujan tyyppiä tarpeen mukaan.
Omasta mielestäni PHP:ssä ei voi johdonmukaisesti käyttää vaihtoehtoa, että muuttuja olisi aina samantyyppinen, koska silloin ei voisi käyttää PHP:hen sisältyviä funktioita jotka palauttavat milloin mitäkin.
Tai no tokihan funktioiden kanssa voisi käyttää aina tilapäismuuttujia joihin ja joista arvot sitten kopioitaisiin vakiotyyppisiin muuttujiin. Tämä tapa olisi minusta kuitenkin huonompi kuin vaan pelata PHP:n säännöillä ja tarkistaa muuttujan tyyppi tarpeen mukaan ja/tai käyttää tyypin huomioivia vertailuja yms.
Aihe on jo aika vanha, joten et voi enää vastata siihen.