Arrays begrijpen: foreach met if

Overzicht Reageren

Sponsored by: Vacatures door Monsterboard

Peter Sanders

Peter Sanders

23/11/2011 10:11:48
Quote Anchor link
Hallo,


Ik ben al wel een tijd bezig met php, maar heb nooit echt iets met arrays gedaan. Nu wil ik wat wiskunde gaan doen met php en een soort van voorwaardes in een foreach-lus zetten die vergelijkbaar zijn met een WHERE-clausule uit een sql-query.

Ik zet om te beginnen een veld uit een databank in een array. Vervolgens draai ik daar een foreach-lus overheen waarin ik alle data die niet aan mijn voorwaardes voldoen weer uit het array haal. Uiteindelijk print ik het array weer om te kijken wat er in zit.

Code (php)
PHP script in nieuw venster Selecteer het PHP script
1
2
3
4
5
6
7
8
9
10
11
12
13
$SlotArray = array();
$sql = "SELECT * FROM aex";
$exec_sql = mysql_query($sql) or die("Foutmelding: ".mysql_error());
while($z = mysql_fetch_assoc($exec_sql)){
    $SlotArray[$z['Datum']] = $z['Slot'];
}
reset($SlotArray);
foreach($SlotArray as $waarde){
    if($waarde > 300 OR $waarde < 290){
        unset($SlotArray[key($SlotArray)]);
    }
}
print_r($SlotArray);

De eerste 10 resultaten van het array zijn echter de volgende:

[1983-01-03] => 45.38
[2011-02-25] => 366.77
[2011-02-28] => 369.13
[2011-03-01] => 367.95
[2011-03-02] => 364.86
[2011-03-03] => 367.60
[2011-03-04] => 367.95
[2011-03-07] => 366.08
[2011-03-08] => 366.38
[2011-03-09] => 366.25

Er zit dus ergens iets fout. Ik begrijp echter absoluut niet waar. Heeft iemand enig idee waar ik fout zit?

ps. Ik weet dat ik natuurlijk ook gewoon een "WHERE Slot < 300 AND Slot > 290" kan toevoegen aan de sql-query. In een later stadium in mijn berekeningen zal dat echter niet meer kunnen. Bovendien wil ik ook gewoon wat meer leren werken met arrays.. :-)
Gewijzigd op 23/11/2011 10:12:46 door Peter Sanders
 
PHP hulp

PHP hulp

25/11/2024 21:56:19
 
- SanThe -

- SanThe -

23/11/2011 10:31:47
Quote Anchor link
Code (php)
PHP script in nieuw venster Selecteer het PHP script
1
2
3
4
5
6
7
<?php
foreach($SlotArray as $key => $waarde){
    if($waarde > 300 OR $waarde < 290){
        unset($SlotArray[$key]);
    }
}

?>
 
Erwin H

Erwin H

23/11/2011 10:32:51
Quote Anchor link
Wat er precies mis gaat kan ik ook niet achterkomen, maar het zit in elk geval in het gebruik van "$SlotArray[key($SlotArray)]" Als je het iets anders schrijft krijg je het wel goed:

Code (php)
PHP script in nieuw venster Selecteer het PHP script
1
2
3
4
5
foreach($SlotArray as $k => $waarde){
    if($waarde > 300 OR $waarde < 290){
        unset($SlotArray[$k]);
    }
}

Op deze manier haal je dus zowel de waarde van het huidige element op (in $waarde), als de key (in $k).
 
Peter Sanders

Peter Sanders

23/11/2011 10:53:17
Quote Anchor link
@SanThe en Erwin

Dank! Die oplossing werkt inderdaad perfect. Handig inderdaad dat ik dan gewoon de key en de waarde allebei apart in een variabele heb. Zoals gezegd, ik begin net met arrays, dus ik moet het concept nog een beetje in mijn hoofd krijgen.

Nog een ander vraagje. Als ik nou een twee-dimensionaal array heb. Hoe zet ik dan de beide keys in een variabele?

Dus ik heb bijvoorbeeld een twee-dimensionaal array waarin één key de datum is, en één key de tijd. De inhoud van het array is de koers van de aex op dat tijdstip.

Dus zoiets:
$koers['1996-12-27']['16:35:00'] = 290.01;
$koers['1996-12-27']['16:36:00'] = 290.46;

Hoe zou ik dit nu inladen in een foreach-lus? Ik heb het volgende geprobeerd.
Code (php)
PHP script in nieuw venster Selecteer het PHP script
1
2
3
foreach($koers as $datum => $tijd => $waarde){
    echo "op ".$datum." om ".$tijd." was de koers van de aex ".$waarde;
}


Daarop krijg ik echter een foutmelding: Parse error: syntax error, unexpected T_DOUBLE_ARROW, expecting ')'

Enige tip hoe ik dit zou kunnen doen?
Gewijzigd op 23/11/2011 10:54:02 door Peter Sanders
 
- SanThe -

- SanThe -

23/11/2011 10:58:08
Quote Anchor link
Code (php)
PHP script in nieuw venster Selecteer het PHP script
1
2
3
4
5
6
7
8
9
<?php
foreach($koers as $datum => $value)
{

    foreach($value as tijd => $waarde)
    {

        echo "op ".$datum." om ".$tijd." was de koers van de aex ".$waarde;
    }
}

?>
 
Erwin H

Erwin H

23/11/2011 11:00:39
Quote Anchor link
Dubbele foreach loop. De waarde die je uit de eerste loop krijgt is weer een array, dus die kan je op dezelfde manier aanpakken als de eerste:

Code (php)
PHP script in nieuw venster Selecteer het PHP script
1
2
3
4
5
6
7
<?php
foreach($koers as $datum => $waarde1){
    foreach( $waarde1 as $tijd => $waarde2){
        echo "op ".$datum." om ".$tijd." was de koers van de aex ".$waarde2;
    }
}

?>
 
Peter Sanders

Peter Sanders

23/11/2011 11:34:26
Quote Anchor link
Ah, met een dubbele foreach dus. Ok! Dat heb ik ook weer geleerd!

Als ik zo vrij mag zijn om nog twee vraagjes te stellen (ik leer zo lekker veel hier);

1) Is het mogelijk om met dat laatste array alle resultaten uit 2004 te verwijderen? Dus iets in de trant van
Code (php)
PHP script in nieuw venster Selecteer het PHP script
1
2
3
4
5
6
7
8
9
10
11
<?php
foreach($koers as $datum => $value)
{

    foreach($value as tijd => $waarde)
    {

        if($datum == '2004%'){
            unset($koers[$datum][$tijd]);
        }
    }
}

?>

Ik begrijp alleen niet hoe je een wildcard doet zoals je dat in sql met een % doet. Jullie (of iemand anders) toevallig enig idee?



Vraag 2) Is het mogelijk om met de resultaten uit een array, de resultaten uit een ander array op te halen? Zo heb ik twee arrays:

$aex['1996-12-27']['16:35:00'] = 290.01;
$aex['1996-12-27']['16:36:00'] = 290.46;
etc.
en
$dowjones['1996-12-27']['16:35:00'] = 2090;
$dowjones['1996-12-27']['16:36:00'] = 2095;

Nu wil ik alle elementen uit het $aex-array unsetten waarvan de datum niet voorkomt in het $dowjones-array. Dus zoiets als dit:
Code (php)
PHP script in nieuw venster Selecteer het PHP script
1
2
3
4
5
6
7
8
9
10
11
12
<?php
foreach($aex as $aex_datum => $value)
{

    foreach($dowjones as $dowjones_datum => $waarde)
    {

        if($dowjones_datum != $aex_datum)
        {

            unset($aex[$aex_datum]);
        }
    }
}

?>

Maar dat zou volgens mij alles unsetten, aangezien er voor elke $aex_datum wel een $dowjones_datum is die er niet aan gelijk is. Enig idee hoe ik dit zou kunnen oplossen?
Gewijzigd op 23/11/2011 11:35:57 door Peter Sanders
 
Erwin H

Erwin H

23/11/2011 12:27:28
Quote Anchor link
Vraag 1: die zou ik oplossen met een substr dus:
if( substr($datum,0,4) == '2004' )
Moet je wel alle elementen door. Ik ken geen simpelere oplossing (wat niet betekent dat die er niet is natuurlijk).

Vraag 2: Op die manier is het heel er langzaam ( O(n*m) )en waarschijnlijk wordt alles eruitgehaald.
Wat je wel kan, met de functie isset() is checken of key "aex_datum" bestaat in de array $dowjones. Dus:

Code (php)
PHP script in nieuw venster Selecteer het PHP script
1
2
3
4
5
6
7
<?php
foreach($aex $aex_datum => $value){
  if (!isset($dowjones[$aex_datum])){
    unset($aex[$aex_datum]);
  }
}

?>

Nu weet ik alleen niet hoe isset precies door de array heen gaat en daarmee of het enigszins snel is. Misschien is het van dezelfde orde.

Als je de arrays gesorteerd op datum krijgt (bijvoorbeeld uit de database) dan kan het wel veel sneller ( O(n+m) ). Begin bij beide arrays bij het eerste element, check of ze gelijk zijn. Zo nee, controleer of de aex_datum lager is dan de dowjones datum. Zo ja, verwijder de aex waarde en ga in die array naar de volgende. Zo nee, ga in de dowjones array naar de volgende. Zijn beide data wel gelijk, ga in beide arrays naar de volgende waarde. Ga zo door tot je het laatste element heb gehad in de aex array
In pseudo code:
Code (php)
PHP script in nieuw venster Selecteer het PHP script
1
2
3
4
5
6
7
8
9
10
11
12
13
14
reset(aex_array);
reset(dowjones_array);
while ( !end of array(aex_array) ){
  if (aex_array[datum] == dowjones[datum]){
    go to next element in aex_array, go to next element in dowjones_array
  } else {
    if (aex_array[datum] < dowjones[datum]){
      unset(aex_array[datum])
      go to next element in aex_array
    } else {
      go to next element in dowjones_array
    }
  }
}
 
- SanThe -

- SanThe -

23/11/2011 12:35:34
Quote Anchor link
Peter Sanders op 23/11/2011 11:34:26:
1) Is het mogelijk om met dat laatste array alle resultaten uit 2004 te verwijderen? Dus iets in de trant van
Code (php)
PHP script in nieuw venster Selecteer het PHP script
1
2
3
4
5
6
7
8
9
10
11
<?php
foreach($koers as $datum => $value)
{

    foreach($value as tijd => $waarde)
    {

        if($datum == '2004%'){
}
            unset($koers[$datum][$tijd]);
        }
    }
}

?>


Om alles uit 2004 te verwijderen heb je maar één loop nodig omdat je dan de datum al weet.

Code (php)
PHP script in nieuw venster Selecteer het PHP script
1
2
3
4
5
6
7
8
9
<?php
foreach($koers as $datum => $value)
{

    if(substr($datum, 0, 4) == '2004')
    {

        unset($koers[$datum]);
        }
}

?>


Peter Sanders op 23/11/2011 11:34:26:
Vraag 2) Is het mogelijk om met de resultaten uit een array, de resultaten uit een ander array op te halen? Zo heb ik twee arrays:

$aex['1996-12-27']['16:35:00'] = 290.01;
$aex['1996-12-27']['16:36:00'] = 290.46;
etc.
en
$dowjones['1996-12-27']['16:35:00'] = 2090;
$dowjones['1996-12-27']['16:36:00'] = 2095;

Nu wil ik alle elementen uit het $aex-array unsetten waarvan de datum niet voorkomt in het $dowjones-array. Dus zoiets als dit:
Code (php)
PHP script in nieuw venster Selecteer het PHP script
1
2
3
4
5
6
7
8
9
10
11
12
<?php
foreach($aex as $aex_datum => $value)
{

    foreach($dowjones as $dowjones_datum => $waarde)
    {

        if($dowjones_datum != $aex_datum)
        {

            unset($aex[$aex_datum]);
        }
    }
}

?>

Maar dat zou volgens mij alles unsetten, aangezien er voor elke $aex_datum wel een $dowjones_datum is die er niet aan gelijk is. Enig idee hoe ik dit zou kunnen oplossen?


Je kijkt of de datum een key is in het andere array().
Zo niet, verwijderen.

Code (php)
PHP script in nieuw venster Selecteer het PHP script
1
2
3
4
5
6
7
8
9
<?php
foreach($aex as $aex_datum => $value)
{

    if(!in_array($aex_datum, array_keys($dowjones)))
    {

        unset($aex[$aex_datum]);
    }
}

?>
 
Peter Sanders

Peter Sanders

23/11/2011 12:42:17
Quote Anchor link
Over vraag 1) Okee, dankjewel. Daarmee zal het wel lukken denk ik.

Over vraag 2) Het zal uiteindelijk om een redelijk groot array gaan (ongeveer 3,6 miljoen waardes) waar ik mbv een paar (zelfgeschreven) functies een aantal berekeningen op wil doen. Die berekeningen zal ik ook nog ongeveer een miljoen keer moeten loopen, dus het zal al met al wel eventjes duren. Ik denk echter dat dit sneller zal gaan dan met sql aangezien ik zo alles in het geheugen heb staan en het daardoor naar mijn weten vooral zwaar is voor de CPU.

Ik zal in ieder geval eens wat tests doen met isset, en kijken hoe lang dat duurt. Als dat erg lang is dan zal ik het proberen met het tweede idee wat je voorsteld (wat ik overigens redelijk briljant vind).

Heel erg bedankt in ieder geval!
 
- SanThe -

- SanThe -

23/11/2011 12:48:51
Quote Anchor link
Mijn versie maar dan sneller:
Code (php)
PHP script in nieuw venster Selecteer het PHP script
1
2
3
4
5
6
7
8
9
10
<?php
$keys
= array_keys($dowjones);
foreach($aex as $aex_datum => $value)
{

    if(!in_array($aex_datum, $keys))
    {

        unset($aex[$aex_datum]);
    }
}

?>
 
Ger van Steenderen
Tutorial mod

Ger van Steenderen

23/11/2011 12:52:08
Quote Anchor link
Code (php)
PHP script in nieuw venster Selecteer het PHP script
1
2
3
4
<?php
$temparray
= array_diff_key($aex, $dowjones);
foreach ($temparray as $key => $value) unset($aex[$key]);
?>
Gewijzigd op 23/11/2011 12:52:34 door Ger van Steenderen
 
Peter Sanders

Peter Sanders

23/11/2011 12:56:25
Quote Anchor link
@SanThe
Ik had jouw reacties nog niet gezien toen ik mijn bovenstaande reactie schreef. Jouw oplossing ziet er inderdaad wel erg goed uit. Ik ga er eens wat tests mee doen.

Ik kwam ook nog de functie array_key_exists tegen. Misschien dat ik het daarmee ook wel zou kunnen doen?

Ik heb in ieder geval weer genoeg lees- en probeerwerk.. :-)

Dank aan jullie beiden!
 
Erwin H

Erwin H

23/11/2011 14:33:47
Quote Anchor link
@Santhe
Ziet er goed uit, alleen blijft het wel de vraag hoe snel het is. Weet jij hoe in_array (net als isset) werkt?
Mijn ervaring met een aantal voorgebouwde php array functies is is dat ze geweldig werken op kleine arrays, maar zodra het een beetje groot wordt (in de orde van 100.000 elementen) dan wordt het erg langzaam.
 



Overzicht Reageren

 
 

Om de gebruiksvriendelijkheid van onze website en diensten te optimaliseren maken wij gebruik van cookies. Deze cookies gebruiken wij voor functionaliteiten, analytische gegevens en marketing doeleinden. U vindt meer informatie in onze privacy statement.