Looping through array

This is a discussion on Looping through array within the alt.comp.lang.php forums, part of the PHP Programming Forums category; Consider the following array and string: $trail = array('products/veggies', 'products', 'services/cleaning'); $path = 'products/veggies/1243/more'; I am ...


Go Back   Usenet Forums > PHP Programming Forums > alt.comp.lang.php

FAQ Members List Calendar Search Today's Posts Mark Forums Read
  #1 (permalink)  
Old 02-23-2007
dennis.sprengers@gmail.com
 
Posts: n/a
Default Looping through array

Consider the following array and string:

$trail = array('products/veggies', 'products', 'services/cleaning');
$path = 'products/veggies/1243/more';

I am trying to write a function that matches $path with a value in
$trail. If no match is found, it should chop off "more" and compare
again. Then, chop off "1243" and compare again. Now a match is found:
"products/veggies". The function should return true.

Let's take another example: $path = 'services/industrial/gardening'.
There is no match for $path in $trail. Chopping off "gardening" leaves
"services/industrial". Again, no match. Chopping off "industrial"
leaves "services". No match will be found; the function should return
false.

This is what I have so far:

function in_trail($path) {
global $trail;

while ($path && !in_array($path, $trail)) {
$path = substr($path, 0, strrpos($path, '/'));
}

return $path ? true : false;

}

But this function always returns true! Could someone explain this to
me and tell me how to fix it? Your help is much appreciated :-)

Reply With Quote
  #2 (permalink)  
Old 02-23-2007
Steve
 
Posts: n/a
Default Re: Looping through array


<dennis.sprengers@gmail.com> wrote in message
news:1172189473.962693.113080@m58g2000cwm.googlegr oups.com...
| Consider the following array and string:
|
| $trail = array('products/veggies', 'products', 'services/cleaning');
| $path = 'products/veggies/1243/more';
|
| I am trying to write a function that matches $path with a value in
| $trail. If no match is found, it should chop off "more" and compare
| again. Then, chop off "1243" and compare again. Now a match is found:
| "products/veggies". The function should return true.
|
| Let's take another example: $path = 'services/industrial/gardening'.
| There is no match for $path in $trail. Chopping off "gardening" leaves
| "services/industrial". Again, no match. Chopping off "industrial"
| leaves "services". No match will be found; the function should return
| false.
|
| This is what I have so far:
|
| function in_trail($path) {
| global $trail;
|
| while ($path && !in_array($path, $trail)) {
| $path = substr($path, 0, strrpos($path, '/'));
| }
|
| return $path ? true : false;
|
| }
|
| But this function always returns true! Could someone explain this to
| me and tell me how to fix it? Your help is much appreciated :-)

because $path will eventually be a value without a '/', yes? that means
strrpos will return -1. consequently, $path will equal the last letter of
the final value. in that case, it will always be true (not 0, not null, not
'', etc.). ex.

$path = 'products/veggies/1234/more';
//your while function processing here
echo '<pre>' . $path '</pre>';

browser displays the letter s. even if you began your path with a '/' (as in
'/products/veggies/'), the final value of $path would be '/'...which is
true. i've not run your code, but this is what i immediately see as faulty
in the code. consider this as an alternative:

function inTrail($path, $trail)
{
if (!is_array($trail)){ return ''; }
if (!strlen($path)){ return ''; }
$match = '';
$path = explode('/', $path);
$length = count($trail);
for ($i = 0; $i < $length; $i++)
{
if ($path[$i] != $trail[$i]){ break; }
$match .= $path[$i] . '/';
}
return $match;
}

notice the missing global def. of $trail...get out of bad habits. you should
also adjust this so that you explicitly allow case-less matching or note in
the function that 'a' is not the same thing as 'A'. this evaluates to false
if $match is '', but returns the amended path as well which comes in handy
if you plan on handling the delima of one a path only partially matching the
trail...you will be able to replace the original with the ammended and end
up with what portion didn't match.

again, i'm just thinking out loud...so there may be syntax or other errors
in the code i just wrote. the code should give you an idea of what i'm
trying to express.

hth,

me


Reply With Quote
  #3 (permalink)  
Old 02-23-2007
Steve
 
Posts: n/a
Default Re: Looping through array

| function inTrail($path, $trail)
| {
| if (!is_array($trail)){ return ''; }
| if (!strlen($path)){ return ''; }
| $match = '';
| $path = explode('/', $path);
| $length = count($trail);
| for ($i = 0; $i < $length; $i++)
| {
| if ($path[$i] != $trail[$i]){ break; }
| $match .= $path[$i] . '/';
| }
| return $match;
| }

i just noticed that $trail is not an exploded path but an array of strings
representing paths. that's an interesting delima because you can have
similar values (paths)...so which should be correct? to make it easy, you
could just do this in your while loop (suppose i should have just kept it
simple ;^):

while (true)
{
if (in_array($path, $trail){ return $path; }
$length = strrpos($path, '/');
if ($length === false){ return false; }
$path = substr($path, 0, $length);
}

that should do it.


Reply With Quote
  #4 (permalink)  
Old 02-23-2007
dennis.sprengers@gmail.com
 
Posts: n/a
Default Re: Looping through array

Thanks, your function works great. However, it boggled my mind why it
didn't do the job in my website, then. After hacking away for like an
hour, it occured to me: the function should do more than just chopping
and comparing. Please consider:

$trail = array('products/veggies/winter', 'products/veggies',
'products');

$path_1 = 'products'; // true
$path_2 = 'products/423'; // false
$path_3 = 'products/veggies'; // true
$path_4 = 'products/meat'; // false
$path_5 = 'products/veggies/23'; // false
$path_6 = 'products/veggies/winter'; // true
$path_7 = 'products/veggies/winter/23/edit'; // true
$path_8 = 'products/meat/cow/dried/54/edit'; // false

The longest element in $trail is 'products/veggies/winter'. It has 3
parts (products, veggies and winter). I will call this element "A".

The function compares $path with $trail. if $path consists of 3 parts
or less, try finding a direct match. If there is a direct match,
return true. This is the case with $path_1, $path_3 and $path_6.
$path_2, $path_4 and $path_5 also have 3 or less parts, and there is
no direct match with $trail, so we return false.

If $path has more element-parts than A (in this case: 3), chop off the
extra parts and look if we now have a match. Two examples are $path_7
and $path_8:

- $path_7 has 5 parts, which is 2 more than A. We chop off "23/edit"
and compare "products/veggies/winter" to A, which will match and thus
return true
- $path_8 has 6 parts, which is 3 more than A. We chop off "dried/54/
edit" and compare "products/meat/cow" to A, which will return false

Could you please help me putting this into a function? I have no
trouble describing what should happen, but find it difficult
translating it into an efficient function.

Thanks in advance for any reply :-)

Reply With Quote
  #5 (permalink)  
Old 02-23-2007
Steve
 
Posts: n/a
Default Re: Looping through array


<dennis.sprengers@gmail.com> wrote in message
news:1172229933.456121.312580@q2g2000cwa.googlegro ups.com...
| Thanks, your function works great. However, it boggled my mind why it
| didn't do the job in my website, then. After hacking away for like an
| hour, it occured to me: the function should do more than just chopping
| and comparing. Please consider:
|
| $trail = array('products/veggies/winter', 'products/veggies',
| 'products');
|
| $path_1 = 'products'; // true
| $path_2 = 'products/423'; // false
| $path_3 = 'products/veggies'; // true
| $path_4 = 'products/meat'; // false
| $path_5 = 'products/veggies/23'; // false
| $path_6 = 'products/veggies/winter'; // true
| $path_7 = 'products/veggies/winter/23/edit'; // true
| $path_8 = 'products/meat/cow/dried/54/edit'; // false
|
| The longest element in $trail is 'products/veggies/winter'. It has 3
| parts (products, veggies and winter). I will call this element "A".
|
| The function compares $path with $trail. if $path consists of 3 parts
| or less, try finding a direct match. If there is a direct match,
| return true. This is the case with $path_1, $path_3 and $path_6.
| $path_2, $path_4 and $path_5 also have 3 or less parts, and there is
| no direct match with $trail, so we return false.
|
| If $path has more element-parts than A (in this case: 3), chop off the
| extra parts and look if we now have a match. Two examples are $path_7
| and $path_8:
|
| - $path_7 has 5 parts, which is 2 more than A. We chop off "23/edit"
| and compare "products/veggies/winter" to A, which will match and thus
| return true
| - $path_8 has 6 parts, which is 3 more than A. We chop off "dried/54/
| edit" and compare "products/meat/cow" to A, which will return false
|
| Could you please help me putting this into a function? I have no
| trouble describing what should happen, but find it difficult
| translating it into an efficient function.
|
| Thanks in advance for any reply :-)


so what you're saying is that if, from left to right, path is equal to trail
(where path or trail is partially compared), then true else false? in that
case, the fix is easy:

$pathLength = strlen($path);
foreach ($trail as $comparison)
{
$length = min($pathLength, strlen($comparison));
if ($length < 1){ continue; }
if (substr($path, 0, $length) == substr($comparison, $length)){ return
true; }
}
return false;

this assumes, by your description of course, that we don't care to which
trail path most closely resembles...we just want at least either the full
path to meet a partial trail or, a partial trail to equal a full path. this
is the gist, however you do want to put in one other validation - to make
sure $path and $comparison are a full directory name... such that:

$path = 'j';
$trail = 'jennifer/is/a/hottie';

won't return true...which it should based on the code example i just gave.

hth


Reply With Quote
Reply
Thread Tools Search this Thread
Search this Thread:

Advanced Search
Display Modes

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are Off
[IMG] code is Off
HTML code is Off
Trackbacks are On
Pingbacks are On
Refbacks are On



All times are GMT +1. The time now is 12:00 PM.


Powered by vBulletin® Version 3.7.3
Copyright ©2000 - 2008, Jelsoft Enterprises Ltd.
Content Relevant URLs by vBSEO 3.0.0