1

I have an array like below, the size and element of array are not fixed its completely generated dynamicly

array(
    'marketplace'   => array(
        'browse request' => array('request type 1', 'request type 2'),
        'browse lab',
    ),
    'marketplace2'  => array('browse request2', 'browse lab2'),
    'submitrequest' => array(''),
    'aboutus'       => array('')
)

I want to get the path from given child node to root node

Let us say for 'request type 2' then the path will be 'marketplace -> browse request -> request type 2'

and one more 'submitrequest' then the path will be 'submitrequest'

Any help would be greatly appreciated. Thanks

hakre
  • 193,403
  • 52
  • 435
  • 836
Bajrang
  • 8,361
  • 4
  • 27
  • 40
  • "From given child node" => how exactly is it "given"? Is the input some value that exists *somewhere* in the array so that the solution includes finding it? Note that your "submitrequest" example does not agree with this description. Also, what if the value exists more than once? – Jon Sep 09 '13 at 10:09
  • Is your input - just string? – Alma Do Sep 09 '13 at 10:10
  • yes my input name is just a string and will be an element/key name of the array – Bajrang Sep 09 '13 at 10:11
  • @Bajrang: `"request type 2"` is not a key in this array. – Jon Sep 09 '13 at 10:11
  • yes but `submitrequest` is a key – Bajrang Sep 09 '13 at 10:12
  • 1
    The data construct(Array) does not good at such thing, [Tree](http://en.wikipedia.org/wiki/Tree_(data_structure)) does, may you should build a tree first. And then your question becomes a path search problem. – Drazzi Sep 09 '13 at 10:37

1 Answers1

0

If your input is a unique string and therefore clearly identifiable, you can just compare the value (and as you added: the key as well) against the string and if found obtain the path:

$string = 'request type 2';

$path = NULL;

$it = new RecursiveIteratorIterator(
    new RecursiveArrayIterator($array), RecursiveIteratorIterator::SELF_FIRST
);
foreach ($it as $key => $value) {
    if ($key !== $string and $value !== $string) {
        continue;
    }

    $path = [$string];
    for ($count = $it->getDepth(); $count && $count--;) {
        array_unshift($path, $it->getSubIterator($count)->key());
    }
    $path = implode(' -> ', $path);
    break;
}

var_dump($path); # string(47) "marketplace -> browse request -> request type 2"

Similar / Related Q&A:


Earlier answer: You are probably missing some points here. First of all you need to clearly identify the element/node (object) you want to find the path to.

You have not outlined in your question how you do that, you only give the array and then the string.

If you mean to have a reference to the node and you want to get the path to it, I give an example how it works in this answer.

First of all, let's reference the object (in the general sense) to get the path from:

// specify the node to search for
$node = &$array['marketplace']['browse request'][1];

As PHP does not allow to identify a string - and your array might contain the same string multiple times - this node needs to be turned into an object which is identifiable. To keep the original string value, it is stored into another variable:

// make the node identifiable (so that it can be searched independent to it's string value, e.g. duplicates)
$string = "$node";
$node   = new stdClass();

Now your original array has the node to be searched for to obtain the path from made identifiable. The print_r now looks as the following (shortened):

Array
(
    [marketplace] => Array
        (
            [browse request] => Array
                (
                    [0] => request type 1
                    [1] => stdClass Object
                    ...

This is necessary because if we search the array and find that object and we keep track of the path used so far in the search we have obtained the path when that object is found.

And this is exactly what we do right now with the help of iterators. PHP already knows how to traverse an array and with a little help from ourselves, this even works with arrays containing objects:

class MyRecursiveIterator extends RecursiveArrayIterator
{
    public function hasChildren() {
        return is_array($this->current());
    }
}

Using this RecursiveIterator with PHP's standard tree traversal RecursiveIteratorIterator we can just generate the path in case we find that object:

$path = NULL;

$it   = new RecursiveIteratorIterator(new MyRecursiveIterator($array));
foreach ($it as $value) {
    if ($value !== $node) {
        continue;
    }

    $path = [$string];
    for ($count = $it->getDepth(); $count && $count--;) {
        array_unshift($path, $it->getSubIterator($count)->key());
    }
    $path = implode(' -> ', $path);
    break;
}

var_dump($path); # string(47) "marketplace -> browse request -> request type 2"

The full example code at a glance (Demo):

<?php
/**
 * get path from child node to parent php array
 * @link https://stackoverflow.com/a/18696550/367456
 */

class MyRecursiveIterator extends RecursiveArrayIterator
{
    public function hasChildren()
    {
        return is_array($this->current());
    }
}


$array = array(
    'marketplace'   => array(
        'browse request' => array('request type 1', 'request type 2'),
        'browse lab',
    ),
    'marketplace2'  => array('browse request2', 'browse lab2'),
    'submitrequest' => array(''),
    'aboutus'       => array('')
);

// specify the node to search for
$node = & $array['marketplace']['browse request'][1];

// make the node identifiable (so that it can be searched independent to it's string value, e.g. duplicates)
$string = "$node";
$node   = new stdClass();

$path = NULL;

$it   = new RecursiveIteratorIterator(new MyRecursiveIterator($array));
foreach ($it as $value) {
    if ($value !== $node) {
        continue;
    }

    $path = [$string];
    for ($count = $it->getDepth(); $count && $count--;) {
        array_unshift($path, $it->getSubIterator($count)->key());
    }
    $path = implode(' -> ', $path);
    break;
}

var_dump($path); # string(47) "marketplace -> browse request -> request type 2"
Community
  • 1
  • 1
hakre
  • 193,403
  • 52
  • 435
  • 836