[PHP] Structuur van array verandert; hoe functie aanpassen?

Pagina: 1
Acties:

Onderwerpen


  • Reveller
  • Registratie: Augustus 2002
  • Laatst online: 05-12-2022
De array $nodes bevat alle nodes uit de database, met properties per node:
code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
Array
(
  [groenten] => Array
    (
      [nid] => 1
      [path] => story/view/1
    )

  [groenten/winter] => Array
    (
      [nid] => 2
      [path] => story/view/2
    )
)

Op elke request lees ik de url uit, en match deze met de array-keys. Vervolgens retourneert onderstaande functie de goede path:
PHP:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
function get_true_path($path, $nodes) {
  $map = $nodes;
  $url = $path;
  
  while ($url && !$map[$url])
    $url = substr($url, 0, strrpos($url, '/'));

  if ($map[$url]['path'])
  {
    $arg = substr($_GET['q'], strlen($url) + 1);

    if (isset($arg))
      return $map[$url]['path'].'/'.$arg;
    else
      return $map[$url]['path'];
  }
  else
  {
    return $path;
  }
}

//get_true_path('groenten/winter/22', $nodes) geeft 'story/view/2/22' terug.

Om diverse redenen heb ik de $nodes array nu anders opgezet. De array-keys bestaan nu uit de node id's. De url is van key naar propertie gegaan:
code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
Array
(
  [1] => Array
    (
      [url] => groenten
      [path] => story/view/1
    )

  [2] => Array
    (
      [url] => groenten/winter
      [path] => story/view/2
    )
)

Als laatste moet ik de get_true_path() functie aanpassen, maar ik loop tegen enkele problemen aan:
  • while ($url && !$map[$url]): de $map[$url] controle kan ik nu niet meer uitvoeren. Ik kan dit veranderen in in_array($url, $map), maar dan heb ik later in de code weer een probleem;
  • if ($map[$url]['path']): ik kan niet meer vergelijken op $url. Hoe kan ik toch de array even efficient als met deze regel doorlopen en de werking van get_true_path() gelijk houden?

"Real software engineers work from 9 to 5, because that is the way the job is described in the formal spec. Working late would feel like using an undocumented external procedure."


  • Janoz
  • Registratie: Oktober 2000
  • Laatst online: 02:21

Janoz

Moderator Devschuur®

!litemod

Je moet gewoon zorgen dat je functies schrijft waarmee je de index kunt ophalen binnen de array gezocht op url, of op map.

Ken Thompson's famous line from V6 UNIX is equaly applicable to this post:
'You are not expected to understand this'


  • Reveller
  • Registratie: Augustus 2002
  • Laatst online: 05-12-2022
Janoz schreef op donderdag 24 februari 2005 @ 10:54:
Je moet gewoon zorgen dat je functies schrijft waarmee je de index kunt ophalen binnen de array gezocht op url, of op map.
Ik dacht dus dat array_search() in dit geval zou werken [...] Blijkt na wat proberen niet te kloppen...ik denk verder...

[ Voor 49% gewijzigd door Reveller op 24-02-2005 11:57 ]

"Real software engineers work from 9 to 5, because that is the way the job is described in the formal spec. Working late would feel like using an undocumented external procedure."


  • Reveller
  • Registratie: Augustus 2002
  • Laatst online: 05-12-2022
Op aanraden van Janoz probeer ik een functie te schrijven die een multi-dimensionale array recursief doorloopt op de te zoeken string:
PHP:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
$nodes = array();

$nodes[1] = array('pid' => 0, 'path' => '', 'url' => ''); // pid = parent_id
$nodes[2] = array('pid' => 1, 'path' => 'story/view/2', 'url' => 'groenten');
$nodes[5] = array('pid' => 2, 'path' => 'story/view/5', 'url' => 'groenten/zomer');
$nodes[9] = array('pid' => 5, 'path' => 'story/view/6', 'url' => 'groenten/zomer/groen');

function multi_array($needle, $haystack)
{
  foreach ($haystack as $key => $value)
  {
    if (is_array($value))
    {
      multi_array($needle, $value);
    }
    else
    {
      if ($value == $needle)
      {
        echo $key;
      }
    }
  }
}

echo multi_array('groenten/zomer', $nodes);

Bovenstaande retourneert 'url'. Dat is ook logisch: 'groenten/zomer' wordt gevonden en de key van 'groenten/zomer' is 'url'. Ik wil echter de top-itemkey, in dit geval '5' geretourneerd krijgen, maar begrijp niet hoe ik dat moet doen. Moet ik een teller bijhouden in de foreach loop die bijhoudt in welke array (1, 2, 5 of 9) we bezig zijn? Of moet ik nadat de match gemaakt is, weer omhoog kruipen door de array?

"Real software engineers work from 9 to 5, because that is the way the job is described in the formal spec. Working late would feel like using an undocumented external procedure."


  • Janoz
  • Registratie: Oktober 2000
  • Laatst online: 02:21

Janoz

Moderator Devschuur®

!litemod

Je hebt toch een duidelijke structuur in je arrays? Waarom ga je dan zo'n generieke functie maken? Je kunt toch gewoon je array doorlopen (met foreach) en kijken of het path of de url (afhankelijk van welke functie je aan het implementeren bent natuurlijk) gelijk is aan hetgeen je zoekt, en dan de index terug geven?

Ken Thompson's famous line from V6 UNIX is equaly applicable to this post:
'You are not expected to understand this'


  • Reveller
  • Registratie: Augustus 2002
  • Laatst online: 05-12-2022
Janoz - wat ontzettend stom dat ik daar zo moeilijk over deed, zeg! Om de goede key terug te geven heb ik niets meer nodig dan
PHP:
1
2
3
foreach ($nodes as $nid => $node)
  if (in_array('groenten/zomer', $node))
    echo $nid;

Wel heb ik nog een probleem om de while met de foreach loop te combineren. Ik zal kort uitleggen wat get_true_path uit de topic start doet: binnen mijn cms worden alle url's (site.com/groenten/zomer) mbv mod_rewrite herschreven naar de vorm site.com?q=groenten/zomer. De array $nodes bevat alle url's die in de database zitten. Stel nu dat iemand naar groenten/zomer/20 surft, dan is de bedoeling dat get_true_path $_GET['q'] (hier: groenten/zomer/20) vergelijkt met de urls uit $nodes en dan de eerste gevonden match retourneert. Zolang er geen match gevonden is, wordt er telkens een / van $_GET['q'] (= $path input) afgehaald. Met het herschrijven ben ik nu zover:

PHP:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
function get_true_path($path)
{
  global $nodes;

  $url = $path;

  foreach ($nodes as $nid => $node)
  {
    while ($url && !$node[$nid][$url])
    {
      $url = substr($url, 0, strrpos($url, '/'));
    }
  }
  
  echo $url;
}

Maar hier wordt niets ge'echod. Ik weet ook niet zeker of de while loop wel op deze manier in de foreach moet staan om een goede werking te krijgen. Ik hoop dat iemand mij hiermee kan helpen; ik zit er nu al bijna een dag mee :X

"Real software engineers work from 9 to 5, because that is the way the job is described in the formal spec. Working late would feel like using an undocumented external procedure."


  • Janoz
  • Registratie: Oktober 2000
  • Laatst online: 02:21

Janoz

Moderator Devschuur®

!litemod

Ik snap nog steeds niet waarom je zo ingewikkeld doet. Dat eerste script vind ik sowieso al een beetje vreemd. Waarom gebruik je de in_array? Je weet welke van de velden je wilt controleren. Waarom roep je die dan niet gelijk aan?

Als je dat nu eens in een functie duwt. Dan laat je deze een index terug geven of -1 als hij niet bestaat. Vervolgens kun je binnen een while waar je telkens wat eraf snoept telkens die functie aanroepen.

Ken Thompson's famous line from V6 UNIX is equaly applicable to this post:
'You are not expected to understand this'


Acties:
  • 0 Henk 'm!

  • Reveller
  • Registratie: Augustus 2002
  • Laatst online: 05-12-2022
Janoz schreef op donderdag 24 februari 2005 @ 16:25:
Ik snap nog steeds niet waarom je zo ingewikkeld doet. [...] Als je dat nu eens in een functie duwt. Dan laat je deze een index terug geven of -1 als hij niet bestaat. Vervolgens kun je binnen een while waar je telkens wat eraf snoept telkens die functie aanroepen.
Dat is dus wat ik probeer, maar ik krijg maar niet de output die ik nodig heb - mijn while loop raakt of in een eeuwige loop of geeft niets terug (zoals onderstaande):
PHP:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
$nodes[2] = array('path' => 'story/view/2', 'url' => 'groenten');
$nodes[5] = array('path' => 'story/view/5', 'url' => 'groenten/zomer');
$nodes[6] = array('path' => 'story/view/6', 'url' => 'groenten/zomer/groen');

function get_true_path($path) {
  global $nodes;

  foreach ($nodes as $node)
    while ($path && $node['url'] != $path)
      $path = substr($path, 0, strrpos($path, '/'));

  return $path;
}

echo get_true_path($input);

Als jij (of iemand anders) mij met wat (pseudo-)code op weg zou kunnen helpen, dan heel graag. Omdat ik bang ben dat we wat langs elkaar heen praten, hieronder een aantal voorbeelden van input en output zoals deze zou moeten zijn:
PHP:
1
2
3
4
$input = 'groenten/zomer/2004/lekker'  // output: story/view/5/2004/lekker
$input = 'groenten'                    // output: story/view/2
$input = 'groenten/zomer/groen/anders' // output: story/view/6/anders
$input = 'fruit/rood'                  // output: fruit/rood (geen match)

Ik vraag niet om kant-en-klare code, maar zou wel graag wat concrete aanwijzingen krijgen omdat ik nu toch al urenlang op dit probleem zit :)

"Real software engineers work from 9 to 5, because that is the way the job is described in the formal spec. Working late would feel like using an undocumented external procedure."


Acties:
  • 0 Henk 'm!

  • Janoz
  • Registratie: Oktober 2000
  • Laatst online: 02:21

Janoz

Moderator Devschuur®

!litemod

Je maakt je code nog steeds te lang. Je mag best een functie in een functie gebruiken. Dat houd de code veel overzichtelijker. Die 3 regeltjes code die bovenaan je in je voorlaatste post hebt neergezet kun je heel mooi ombouwen tot een functie 'getIndexOf(truepath)'. Deze functie kun je vervolgens telkens aanroepen binnen je while lus die telkens ene stukje van de url afschaaft. Zolang hij -1 terug geeft is hij niet gevonden. Let daarbij wel op dat je wel moet stoppen waneer truepath helemaal leeg is he ;).

Als je teveel algoritmen binnen die functie probeert te proppen zoals je nu doet verlies je al snel het overzicht en kun jij niet meer exact vertellen wat elke regel code precies doet.

Ken Thompson's famous line from V6 UNIX is equaly applicable to this post:
'You are not expected to understand this'


Acties:
  • 0 Henk 'm!

  • Reveller
  • Registratie: Augustus 2002
  • Laatst online: 05-12-2022
Janoz - ik snap niet dat je zegt dat mijn code te lang is. Zoals ik het zie heb ik bij elke oplossing in ieder geval een foreach loop nodig om door de array te lopen en een while loop daarbinnen om te zien of er een match is. Ik heb de code uit mijn voorlaatste post "omgebouwd":
PHP:
1
2
3
4
5
6
7
function get_index_of($path) {
  global $nodes;

  foreach ($nodes as $nid => $node)
    if (in_array($path, $node))
      return $nid;
}

Ik zie alleen niet hoe dit het probleem van mijn vorige post helpt op te lossen, want get_true_path() verandert nu nauwelijks volgens mij. Ik heb nu:
PHP:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
function get_true_path($path)
{
  global $nodes;

  foreach ($nodes as $nid => $node)
  {
    while ($path && $node['url'] != $path)
    {
      echo $path;
      $path = substr($path, 0, strrpos($path, '/'));
    }
  }
}

get_true_path('groenten/zomer/groen/witlof/2004');

De output hiervan is keurig
code:
1
2
3
4
5
groenten/zomer/groen/witlof/2004
groenten/zomer/groen/witlof
groenten/zomer/groen
groenten/zomer
groenten

Ik snap alleen niet waarom deze functie niet stopt als hij in de $nodes array 'groenten/zomer/groen' tegenkomt... :?

[ Voor 83% gewijzigd door Reveller op 25-02-2005 12:22 ]

"Real software engineers work from 9 to 5, because that is the way the job is described in the formal spec. Working late would feel like using an undocumented external procedure."

Pagina: 1