পিতা-সন্তানের সম্পর্কের একটি সিরিজকে একটি শ্রেণিবিন্যাসের গাছে রূপান্তর করবেন?


100

আমার কাছে নাম-পিতামাতার জুড়ি রয়েছে, আমি যতটা সম্ভব কয়েকটি বৃত্তাকার গাছের কাঠামোতে রূপান্তর করতে চাই। সুতরাং উদাহরণস্বরূপ, এগুলি জুটিগুলি হতে পারে:

Child : Parent
    H : G
    F : G
    G : D
    E : D
    A : E
    B : C
    C : E
    D : NULL

যাকে (ক) উত্তরাধিকারী গাছ (গুলি) এ রূপান্তরিত করা দরকার:

D
├── E
   ├── A
      └── B
   └── C   
└── G
    ├── F
    └── H

আমি যে পরিণতিটি চাই তা হ'ল <ul>উপাদানগুলির একটি নেস্টেট সেট , এতে প্রতিটি <li>সন্তানের নাম রয়েছে।

জুটিগুলির মধ্যে কোনও অসঙ্গতি নেই (শিশুটি তার নিজস্ব পিতা বা মাতা, সন্তানের সন্তান ইত্যাদি), তাই সম্ভবত একগুচ্ছ অপ্টিমাইজেশন করা যায়।

কীভাবে, পিএইচপি-তে, আমি বাচ্চা => পিতামাতার জোড় যুক্ত অ্যারে থেকে নেস্টেড এসের সেটতে যাব <ul>?

আমার অনুভূতি আছে যে পুনরাবৃত্তি জড়িত, তবে আমি এটিকে ভাবার পক্ষে যথেষ্ট জাগ্রত নই।

উত্তর:


129

শিশু / পিতামাতার জুটিকে গাছের কাঠামোর সাথে পার্স করার জন্য এটির একটি খুব প্রাথমিক পুনরাবৃত্ত ফাংশন এবং এটি মুদ্রণের জন্য অন্য পুনরাবৃত্ত ফাংশন প্রয়োজন। কেবল একটি ফাংশনই যথেষ্ট হবে তবে স্বচ্ছতার জন্য এখানে দুটি রয়েছে (একটি সম্মিলিত ফাংশন এই উত্তরটির শেষে পাওয়া যাবে)।

প্রথমে শিশু / পিতামাতার জুটির অ্যারে শুরু করুন:

$tree = array(
    'H' => 'G',
    'F' => 'G',
    'G' => 'D',
    'E' => 'D',
    'A' => 'E',
    'B' => 'C',
    'C' => 'E',
    'D' => null
);

তারপরে যে ক্রিয়াটি সেই অ্যারেটিকে শ্রেণিবিন্যাসের কাঠামোর কাঠামোর মধ্যে পার্স করে:

function parseTree($tree, $root = null) {
    $return = array();
    # Traverse the tree and search for direct children of the root
    foreach($tree as $child => $parent) {
        # A direct child is found
        if($parent == $root) {
            # Remove item from tree (we don't need to traverse this again)
            unset($tree[$child]);
            # Append the child into result array and parse its children
            $return[] = array(
                'name' => $child,
                'children' => parseTree($tree, $child)
            );
        }
    }
    return empty($return) ? null : $return;    
}

এবং একটি ক্রিয়াকলাপ যা একটি গাছটিকে একটি নিরবচ্ছিন্ন তালিকার জন্য মুদ্রণ করতে পারে:

function printTree($tree) {
    if(!is_null($tree) && count($tree) > 0) {
        echo '<ul>';
        foreach($tree as $node) {
            echo '<li>'.$node['name'];
            printTree($node['children']);
            echo '</li>';
        }
        echo '</ul>';
    }
}

এবং আসল ব্যবহার:

$result = parseTree($tree);
printTree($result);

এখানে লিখিত সামগ্রী রয়েছে $result:

Array(
    [0] => Array(
        [name] => D
        [children] => Array(
            [0] => Array(
                [name] => G
                [children] => Array(
                    [0] => Array(
                        [name] => H
                        [children] => NULL
                    )
                    [1] => Array(
                        [name] => F
                        [children] => NULL
                    )
                )
            )
            [1] => Array(
                [name] => E
                [children] => Array(
                    [0] => Array(
                        [name] => A
                        [children] => NULL
                    )
                    [1] => Array(
                        [name] => C
                        [children] => Array(
                            [0] => Array(
                                [name] => B
                                [children] => NULL
                            )
                        )
                    )
                )
            )
        )
    )
)

আপনি যদি আরও কিছু দক্ষতা চান তবে আপনি সেই ফাংশনগুলিকে একটিতে একত্রিত করতে পারেন এবং তৈরি পুনরাবৃত্তির সংখ্যা হ্রাস করতে পারেন:

function parseAndPrintTree($root, $tree) {
    $return = array();
    if(!is_null($tree) && count($tree) > 0) {
        echo '<ul>';
        foreach($tree as $child => $parent) {
            if($parent == $root) {                    
                unset($tree[$child]);
                echo '<li>'.$child;
                parseAndPrintTree($child, $tree);
                echo '</li>';
            }
        }
        echo '</ul>';
    }
}

আপনি কেবলমাত্র এটির চেয়ে ছোট একটি ডেটাसेटে 8 টি পুনরাবৃত্তি সংরক্ষণ করতে পারবেন তবে বড় সেটগুলিতে এটি কোনও পার্থক্য করতে পারে।


2
Tatu থেকে। গাছের এইচটিএমএল সরাসরি প্রতিধ্বনিত না করে সমস্ত আউটপুট এইচটিএমএলকে একটি ভেরিয়েবলে সংরক্ষণ করে এটি ফিরিয়ে দিতে কীভাবে আমি মুদ্রণযন্ত্রটি পরিবর্তন করতে পারি? ধন্যবাদ
এনরিক

হাই, আমি মনে করি ফাংশন ঘোষণা অবশ্যই পার্সএন্ডপ্রিন্টট্রি ($ গাছ, $ মূল = নাল) এবং পুনরাবৃত্ত কলটি পার্সএন্ডপ্রিন্ট ট্রি ($ শিশু, $ ট্রি) হতে হবে; শুভেচ্ছা
রেজার 7

55

তবুও একটি গাছ বানাতে অন্য কাজ (কোনও পুনরাবৃত্তি জড়িত নয়, পরিবর্তে উল্লেখগুলি ব্যবহার করে):

$array = array('H' => 'G', 'F' => 'G', ..., 'D' => null);

function to_tree($array)
{
    $flat = array();
    $tree = array();

    foreach ($array as $child => $parent) {
        if (!isset($flat[$child])) {
            $flat[$child] = array();
        }
        if (!empty($parent)) {
            $flat[$parent][$child] =& $flat[$child];
        } else {
            $tree[$child] =& $flat[$child];
        }
    }

    return $tree;
}

এটির মতো একটি শ্রেণিবিন্যাসের অ্যারে প্রদান করে:

Array(
    [D] => Array(
        [G] => Array(
            [H] => Array()
            [F] => Array()
        )
        ...
    )
)

যা সহজেই পুনরাবৃত্ত ফাংশন ব্যবহার করে এইচটিএমএল তালিকা হিসাবে মুদ্রণ করা যায়।


+1 - খুব চালাক। যদিও আমি পুনরাবৃত্তির সমাধানটিকে আরও যুক্তিযুক্ত বলে মনে করি। তবে আমি আপনার ফাংশনের আউটপুট ফর্ম্যাটটিকে পছন্দ করি না।
এরিক ২

@ এরিক আরও যৌক্তিক? আমি আলাদা করতে অনুরোধ। পুনরাবৃত্তিতে 'যৌক্তিক' কিছুই নেই; পুনরাবৃত্ত ফাংশন / কল পার্স করার ক্ষেত্রে ওটওহ একটি গুরুতর জ্ঞানীয় ওভারহেড রয়েছে। যদি কোনও স্পষ্ট স্ট্যাক বরাদ্দ না থাকে তবে আমি প্রতিদিন পুনরাবৃত্তির উপর পুনরাবৃত্তি গ্রহণ করতাম।


29

আরেকটি, সমতল কাঠামোটিকে $treeশ্রেণিবিন্যাসে রূপান্তর করার আরও সহজ উপায় । এটি প্রকাশের জন্য কেবলমাত্র একটি অস্থায়ী অ্যারে প্রয়োজন:

// add children to parents
$flat = array(); # temporary array
foreach ($tree as $name => $parent)
{
    $flat[$name]['name'] = $name; # self
    if (NULL === $parent)
    {
        # no parent, is root element, assign it to $tree
        $tree = &$flat[$name]; 
    }
    else
    {
        # has parent, add self as child    
        $flat[$parent]['children'][] = &$flat[$name];
    }
}
unset($flat);

শ্রেণিবিন্যাসকে বহুমাত্রিক অ্যারে রূপান্তর করার জন্য এগুলিই:

Array
(
    [children] => Array
        (
            [0] => Array
                (
                    [children] => Array
                        (
                            [0] => Array
                                (
                                    [name] => H
                                )

                            [1] => Array
                                (
                                    [name] => F
                                )

                        )

                    [name] => G
                )

            [1] => Array
                (
                    [name] => E
                    [children] => Array
                        (
                            [0] => Array
                                (
                                    [name] => A
                                )

                            [1] => Array
                                (
                                    [children] => Array
                                        (
                                            [0] => Array
                                                (
                                                    [name] => B
                                                )

                                        )

                                    [name] => C
                                )

                        )

                )

        )

    [name] => D
)

যদি আপনি পুনরাবৃত্তি এড়াতে চান তবে আউটপুট কম তুচ্ছ হয় (বড় কাঠামোর সাথে বোঝা হতে পারে)।

অ্যারে আউটপুট দেওয়ার জন্য আমি সবসময়ই ইউএল / এলআই "দ্বিধা" সমাধান করতে চেয়েছিলাম। দ্বিধাটি হ'ল, প্রতিটি আইটেমই জানে না বাচ্চারা অনুসরণ করবে কি না বা পূর্ববর্তী কতগুলি উপাদান বন্ধ করা দরকার। অন্য উত্তরে আমি ইতিমধ্যে সমাধান করেছি যে আমার নিজের লিখিত প্রদত্ত একটি মেটা-তথ্য RecursiveIteratorIteratorব্যবহার করে getDepth()এবং অন্যান্য মেটা-তথ্য সন্ধান করে Iterator: নেস্টেড সেট মডেলটিকে একটি <ul>"বদ্ধ" সাবট্রিজ লুকিয়ে রাখা । এই উত্তর পাশাপাশি দেখায় যে পুনরাবৃত্তকারীদের সাথে আপনি বেশ নমনীয়।

তবে এটি একটি পূর্ব-সাজানো তালিকা ছিল, সুতরাং আপনার উদাহরণের জন্য উপযুক্ত হবে না। অতিরিক্তভাবে আমি সর্বদা এক ধরণের স্ট্যান্ডার্ড ট্রি স্ট্রাকচার এবং এইচটিএমএল <ul>এবং এর জন্য এটি সমাধান করতে চেয়েছিলাম<li> উপাদানগুলির ।

আমি যে প্রাথমিক ধারণাটি সামনে এলাম তা হ'ল:

  1. TreeNode- প্রতিটি উপাদানকে একটি সরল TreeNodeপ্রকারে বিমুক্ত করে যা এর মান (যেমন Name) সরবরাহ করতে পারে এবং এতে বাচ্চা আছে কি না।
  2. TreeNodesIterator- RecursiveIteratorএগুলির মধ্যে একটি সেট (অ্যারে) এর মাধ্যমে পুনরাবৃত্তি করতে সক্ষম TreeNodes। এটি মোটামুটি সহজ কারণ TreeNodeটাইপটি ইতিমধ্যে জানে যে এর কোনও সন্তান রয়েছে এবং কোনটি।
  3. RecursiveListIterator- RecursiveIteratorIteratorএটির যে কোনও ইভেন্টের পুনরাবৃত্তভাবে যে কোনও ধরণের পুনরুক্তি ঘটে যখন প্রয়োজনীয় সমস্ত ইভেন্ট রয়েছে RecursiveIterator:
    • beginIteration/ endIteration- মূল তালিকার শুরু এবং শেষ।
    • beginElement/ endElement- প্রতিটি উপাদানটির শুরু এবং শেষ।
    • beginChildren/ endChildren- প্রতিটি বাচ্চার তালিকার শুরু এবং শেষ। এটি RecursiveListIteratorকেবলমাত্র ফাংশন কলগুলির আকারে এই ইভেন্টগুলি সরবরাহ করে। শিশুদের তালিকাগুলি, যেমন এটি তালিকার পক্ষে সাধারণ <ul><li>, তত্ক্ষণাত এটির মূল <li>উপাদানটির ভিতরে খোলা এবং বন্ধ করা হয় । অতএব endElementঘটনাটি সেই endChildrenইভেন্টের পরে বরখাস্ত করা হয় । এই শ্রেণীর ব্যবহারকে প্রশস্ত করতে এটি পরিবর্তন বা কনফিগারযোগ্য তৈরি করা যেতে পারে। ঘটনাগুলি আলাদা রাখার জন্য ইভেন্টগুলি তখন ডেকরেটর অবজেক্টে ফাংশন কল হিসাবে বিতরণ করা হয়।
  4. ListDecorator- একটি "সজ্জাকারী" শ্রেণি যা কেবলমাত্র ইভেন্টগুলির গ্রহণযোগ্য RecursiveListIterator

আমি মূল আউটপুট যুক্তি দিয়ে শুরু করি। এখন শ্রেণিবদ্ধ $treeঅ্যারে নেওয়া , চূড়ান্ত কোড নীচের মত দেখাচ্ছে:

$root = new TreeNode($tree);
$it = new TreeNodesIterator(array($root));
$rit = new RecursiveListIterator($it);
$decor = new ListDecorator($rit);
$rit->addDecorator($decor);

foreach($rit as $item)
{
    $inset = $decor->inset(1);
    printf("%s%s\n", $inset, $item->getName());
}

প্রথমে আসুন এটি খতিয়ে দেখি ListDecoratorযা কেবল <ul>এবং <li>উপাদানগুলিকে আবৃত করে এবং কীভাবে তালিকা কাঠামোটি আউটপুট হয় সে সম্পর্কে সিদ্ধান্ত নিচ্ছে:

class ListDecorator
{
    private $iterator;
    public function __construct(RecursiveListIterator $iterator)
    {
        $this->iterator = $iterator;
    }
    public function inset($add = 0)
    {
        return str_repeat('  ', $this->iterator->getDepth()*2+$add);
    }

কনস্ট্রাক্টর এটিতে কাজ করা তালিকার পুনরাবৃত্তি গ্রহণ করে। insetআউটপুটটির সুন্দর ইন্ডেন্টেশনের জন্য কেবল একটি সহায়ক ফাংশন। বাকি প্রতিটি ইভেন্টের জন্য আউটপুট ফাংশন:

    public function beginElement()
    {
        printf("%s<li>\n", $this->inset());
    }
    public function endElement()
    {
        printf("%s</li>\n", $this->inset());
    }
    public function beginChildren()
    {
        printf("%s<ul>\n", $this->inset(-1));
    }
    public function endChildren()
    {
        printf("%s</ul>\n", $this->inset(-1));
    }
    public function beginIteration()
    {
        printf("%s<ul>\n", $this->inset());
    }
    public function endIteration()
    {
        printf("%s</ul>\n", $this->inset());
    }
}

এই আউটপুট ফাংশনগুলি মাথায় রেখে, এটি আবার প্রধান আউটপুট মোড়ানো / লুপ, আমি ধাপে ধাপে এটি দিয়ে যাচ্ছি:

$root = new TreeNode($tree);

মূলটি তৈরি করুন TreeNodeযা পুনরাবৃত্তি শুরু করতে ব্যবহৃত হবে:

$it = new TreeNodesIterator(array($root));

এটি TreeNodesIteratorএমন একটি RecursiveIteratorযা একক $rootনোডের মাধ্যমে পুনরাবৃত্তির পুনরাবৃত্তি সক্ষম করে । এটি অ্যারে হিসাবে পাস করা হয়েছে কারণ সেই শ্রেণীর পুনরাবৃত্তি করার জন্য কিছু দরকার এবং বাচ্চাদের একটি সেট দিয়ে পুনরায় ব্যবহারের অনুমতি দেয় যা TreeNodeউপাদানগুলির একটি অ্যারেও ।

$rit = new RecursiveListIterator($it);

এটি RecursiveListIteratorএমন একটি RecursiveIteratorIteratorযা বলা ঘটনাগুলি সরবরাহ করে। এটির ব্যবহার করতে, কেবলমাত্র ListDecorator(উপরের শ্রেণি) সরবরাহ করতে হবে এবং এর সাথে নিযুক্ত করা হবে addDecorator:

$decor = new ListDecorator($rit);
$rit->addDecorator($decor);

তারপরে সবকিছু ঠিকঠাক foreachহয়ে যায় এবং প্রতিটি নোড আউটপুট করে:

foreach($rit as $item)
{
    $inset = $decor->inset(1);
    printf("%s%s\n", $inset, $item->getName());
}

যেমন এই উদাহরণটি দেখায়, পুরো আউটপুট যুক্তি ListDecoratorক্লাসে এবং এই এককটিতে আবদ্ধforeach । সম্পূর্ণ পুনরাবৃত্তির ট্র্যাভারসাল পুরোপুরি এসপিএল পুনরাবৃত্ত পুনরাবৃত্তকারীগুলিতে সম্পূর্ণভাবে আবদ্ধ করা হয়েছে যা একটি স্ট্যাকড পদ্ধতি সরবরাহ করে, এর অর্থ অভ্যন্তরীণভাবে কোনও পুনরাবৃত্তি ফাংশন কল করা হয় না।

ইভেন্ট ভিত্তিক ListDecoratorআপনাকে বিশেষভাবে আউটপুট পরিবর্তন করতে এবং একই ডেটা কাঠামোর জন্য একাধিক ধরণের তালিকা সরবরাহ করতে দেয় allows এমনকি অ্যারে ডেটাটি ইনপ্যাপুলেট করা হওয়ায় ইনপুটটি পরিবর্তন করা এমনকি সম্ভবTreeNode

সম্পূর্ণ কোড উদাহরণ:

<?php
namespace My;

$tree = array('H' => 'G', 'F' => 'G', 'G' => 'D', 'E' => 'D', 'A' => 'E', 'B' => 'C', 'C' => 'E', 'D' => null);

// add children to parents
$flat = array(); # temporary array
foreach ($tree as $name => $parent)
{
    $flat[$name]['name'] = $name; # self
    if (NULL === $parent)
    {
        # no parent, is root element, assign it to $tree
        $tree = &$flat[$name];
    }
    else
    {
        # has parent, add self as child    
        $flat[$parent]['children'][] = &$flat[$name];
    }
}
unset($flat);

class TreeNode
{
    protected $data;
    public function __construct(array $element)
    {
        if (!isset($element['name']))
            throw new InvalidArgumentException('Element has no name.');

        if (isset($element['children']) && !is_array($element['children']))
            throw new InvalidArgumentException('Element has invalid children.');

        $this->data = $element;
    }
    public function getName()
    {
         return $this->data['name'];
    }
    public function hasChildren()
    {
        return isset($this->data['children']) && count($this->data['children']);
    }
    /**
     * @return array of child TreeNode elements 
     */
    public function getChildren()
    {        
        $children = $this->hasChildren() ? $this->data['children'] : array();
        $class = get_called_class();
        foreach($children as &$element)
        {
            $element = new $class($element);
        }
        unset($element);        
        return $children;
    }
}

class TreeNodesIterator implements \RecursiveIterator
{
    private $nodes;
    public function __construct(array $nodes)
    {
        $this->nodes = new \ArrayIterator($nodes);
    }
    public function  getInnerIterator()
    {
        return $this->nodes;
    }
    public function getChildren()
    {
        return new TreeNodesIterator($this->nodes->current()->getChildren());
    }
    public function hasChildren()
    {
        return $this->nodes->current()->hasChildren();
    }
    public function rewind()
    {
        $this->nodes->rewind();
    }
    public function valid()
    {
        return $this->nodes->valid();
    }   
    public function current()
    {
        return $this->nodes->current();
    }
    public function key()
    {
        return $this->nodes->key();
    }
    public function next()
    {
        return $this->nodes->next();
    }
}

class RecursiveListIterator extends \RecursiveIteratorIterator
{
    private $elements;
    /**
     * @var ListDecorator
     */
    private $decorator;
    public function addDecorator(ListDecorator $decorator)
    {
        $this->decorator = $decorator;
    }
    public function __construct($iterator, $mode = \RecursiveIteratorIterator::SELF_FIRST, $flags = 0)
    {
        parent::__construct($iterator, $mode, $flags);
    }
    private function event($name)
    {
        // event debug code: printf("--- %'.-20s --- (Depth: %d, Element: %d)\n", $name, $this->getDepth(), @$this->elements[$this->getDepth()]);
        $callback = array($this->decorator, $name);
        is_callable($callback) && call_user_func($callback);
    }
    public function beginElement()
    {
        $this->event('beginElement');
    }
    public function beginChildren()
    {
        $this->event('beginChildren');
    }
    public function endChildren()
    {
        $this->testEndElement();
        $this->event('endChildren');
    }
    private function testEndElement($depthOffset = 0)
    {
        $depth = $this->getDepth() + $depthOffset;      
        isset($this->elements[$depth]) || $this->elements[$depth] = 0;
        $this->elements[$depth] && $this->event('endElement');

    }
    public function nextElement()
    {
        $this->testEndElement();
        $this->event('{nextElement}');
        $this->event('beginElement');       
        $this->elements[$this->getDepth()] = 1;
    } 
    public function beginIteration()
    {
        $this->event('beginIteration');
    }
    public function endIteration()
    {
        $this->testEndElement();
        $this->event('endIteration');       
    }
}

class ListDecorator
{
    private $iterator;
    public function __construct(RecursiveListIterator $iterator)
    {
        $this->iterator = $iterator;
    }
    public function inset($add = 0)
    {
        return str_repeat('  ', $this->iterator->getDepth()*2+$add);
    }
    public function beginElement()
    {
        printf("%s<li>\n", $this->inset(1));
    }
    public function endElement()
    {
        printf("%s</li>\n", $this->inset(1));
    }
    public function beginChildren()
    {
        printf("%s<ul>\n", $this->inset());
    }
    public function endChildren()
    {
        printf("%s</ul>\n", $this->inset());
    }
    public function beginIteration()
    {
        printf("%s<ul>\n", $this->inset());
    }
    public function endIteration()
    {
        printf("%s</ul>\n", $this->inset());
    }
}


$root = new TreeNode($tree);
$it = new TreeNodesIterator(array($root));
$rit = new RecursiveListIterator($it);
$decor = new ListDecorator($rit);
$rit->addDecorator($decor);

foreach($rit as $item)
{
    $inset = $decor->inset(2);
    printf("%s%s\n", $inset, $item->getName());
}

Outpupt:

<ul>
  <li>
    D
    <ul>
      <li>
        G
        <ul>
          <li>
            H
          </li>
          <li>
            F
          </li>
        </ul>
      </li>
      <li>
        E
        <ul>
          </li>
          <li>
            A
          </li>
          <li>
            C
            <ul>
              <li>
                B
              </li>
            </ul>
          </li>
        </ul>
      </li>
    </ul>
  </li>
</ul>

ডেমো (পিএইচপি 5.2 বৈকল্পিক)

একটি সম্ভাব্য রূপটি RecursiveIteratorএকটি পুনরাবৃত্তি হবে যা যে কোনওটির উপরে পুনরাবৃত্তি করে এবং ঘটতে পারে এমন সমস্ত ইভেন্টের উপর একটি পুনরাবৃত্তি সরবরাহ করে। ফোরচ লুপের অভ্যন্তরে একটি স্যুইচ / কেস তারপরে ঘটনাগুলি মোকাবেলা করতে পারে।

সম্পর্কিত:


3
এই সমাধানটি যেমন "ভাল ইঞ্জিনিয়ারড" - ঠিক আগের উদাহরণগুলির তুলনায় এটি আরও "আরও সরলীকৃত উপায়" - এটি ঠিক একই সমস্যার ওভার ইঞ্জিনিয়ারড সমাধানের মতো বলে মনে হয়
আন্দ্রে

@ আন্ড্রে: ইনপ্যাপসুলেশন আইআইআরসি গ্রেড দ্বারা। অন্য সম্পর্কিত উত্তরে আমার একটি সম্পূর্ণ নন-এনক্যাপসুলেটেড কোড-টুকরা রয়েছে যা অনেক ছোট এবং তাই পিওভির উপর নির্ভর করে "আরও সরলিকৃত" হতে পারে।
hakre

@hakre এলআইতে 'আইডি' যুক্ত করতে আমি কীভাবে "তালিকাডেকোরেটর" শ্রেণিটি সংশোধন করতে পারি, যা গাছের অ্যারে থেকে আনা হচ্ছে?
গাঙ্গেশ

1
@ গাঙ্গেশ: নোড ভিজার দিয়ে খুব সহজেই। ^^ কিছুটা অবাক করে দেওয়া, সোজা এগিয়ে সাজসজ্জারকে প্রসারিত করা এবং বিগলিমেন্ট () সম্পাদনা করা, অভ্যন্তরীণ পুনরুক্তিকারক (একটি উদাহরণের জন্য ইনসেট () পদ্ধতিটি দেখুন) এবং আইডি বৈশিষ্ট্য সহ কাজ করা।
হ্যাক্রে

@হাক্রে ধন্যবাদ আমি চেষ্টা করব।
গঙ্গেশ

8

ঠিক আছে, প্রথমে আমি কী-মান জোড়ার সোজা অ্যারেটিকে একটি শ্রেণিবিন্যাসের অ্যারে পরিণত করব

function convertToHeiarchical(array $input) {
    $parents = array();
    $root = array();
    $children = array();
    foreach ($input as $item) {
        $parents[$item['id']] = &$item;
        if ($item['parent_id']) {
            if (!isset($children[$item['parent_id']])) {
                $children[$item['parent_id']] = array();
            }
            $children[$item['parent_id']][] = &$item;
        } else {
            $root = $item['id'];
        }
    }
    foreach ($parents as $id => &$item) {
        if (isset($children[$id])) {
            $item['children'] = $children[$id];
        } else {
            $item['children'] = array();
        }
    }
    return $parents[$root];
}

এটি প্যারেন্ট_আইডি এবং আইডি সহ একটি ফ্ল্যাট অ্যারেটিকে একটি শ্রেণিবিন্যাসে রূপান্তর করতে পারে:

$item = array(
    'id' => 'A',
    'blah' => 'blah',
    'children' => array(
        array(
            'id' => 'B',
            'blah' => 'blah',
            'children' => array(
                array(
                    'id' => 'C',
                    'blah' => 'blah',
                    'children' => array(),
                ),
             ),
            'id' => 'D',
            'blah' => 'blah',
            'children' => array(
                array(
                    'id' => 'E',
                    'blah' => 'blah',
                    'children' => array(),
                ),
            ),
        ),
    ),
);

তারপরে, কেবল একটি উপস্থাপনা ফাংশন তৈরি করুন:

function renderItem($item) {
    $out = "Your OUtput For Each Item Here";
    $out .= "<ul>";
    foreach ($item['children'] as $child) {
        $out .= "<li>".renderItem($child)."</li>";
    }
    $out .= "</ul>";
    return $out;
}

5

যখন আলেকজান্ডার-কনস্টান্টিনভ সমাধান প্রথমদিকে পড়া সহজ মনে হচ্ছে না, তবে এটি পারফরম্যান্সের দিক থেকে প্রতিভা এবং তাত্পর্যজনকভাবে উভয়ই ভাল, এটি সেরা উত্তর হিসাবে ভোট দেওয়া উচিত ছিল।

ধন্যবাদ সাথী, আমি এই পোস্টে উপস্থাপিত 2 টি সমাধানের তুলনা করার জন্য আপনার সম্মানে একটি মানদণ্ড তৈরি করেছি।

আমার একটি রূপান্তর করতে হয়েছিল এমন 6 টি স্তরের সাথে আমার একটি @ 250k ফ্ল্যাট গাছ ছিল এবং আমি এটির জন্য আরও ভালতর উপায় খুঁজছিলাম এবং পুনরাবৃত্ত পুনরাবৃত্তিগুলি এড়াতে চাই।

পুনরাবৃত্তি বনাম রেফারেন্স:

// Generate a 6 level flat tree
$root = null;
$lvl1 = 13;
$lvl2 = 11;
$lvl3 = 7;
$lvl4 = 5;
$lvl5 = 3;
$lvl6 = 1;    
$flatTree = [];
for ($i = 1; $i <= 450000; $i++) {
    if ($i % 3 == 0)  { $lvl5 = $i; $flatTree[$lvl6] = $lvl5; continue; }
    if ($i % 5 == 0)  { $lvl4 = $i; $flatTree[$lvl5] = $lvl4; continue; }
    if ($i % 7 == 0)  { $lvl3 = $i; $flatTree[$lvl3] = $lvl2; continue; }
    if ($i % 11 == 0) { $lvl2 = $i; $flatTree[$lvl2] = $lvl1; continue; }
    if ($i % 13 == 0) { $lvl1 = $i; $flatTree[$lvl1] = $root; continue; }
    $lvl6 = $i;
}

echo 'Array count: ', count($flatTree), PHP_EOL;

// Reference function
function treeByReference($flatTree)
{
    $flat = [];
    $tree = [];

    foreach ($flatTree as $child => $parent) {
        if (!isset($flat[$child])) {
            $flat[$child] = [];
        }
        if (!empty($parent)) {
            $flat[$parent][$child] =& $flat[$child];
        } else {
            $tree[$child] =& $flat[$child];
        }
    }

    return $tree;
}

// Recursion function
function treeByRecursion($flatTree, $root = null)
{
    $return = [];
    foreach($flatTree as $child => $parent) {
        if ($parent == $root) {
            unset($flatTree[$child]);
            $return[$child] = treeByRecursion($flatTree, $child);
        }
    }
    return $return ?: [];
}

// Benchmark reference
$t1 = microtime(true);
$tree = treeByReference($flatTree);
echo 'Reference: ', (microtime(true) - $t1), PHP_EOL;

// Benchmark recursion
$t2 = microtime(true);
$tree = treeByRecursion($flatTree);
echo 'Recursion: ', (microtime(true) - $t2), PHP_EOL;

আউটপুট নিজেই কথা বলে:

Array count: 255493
Reference: 0.3259289264679 (less than 0.4s)
Recursion: 6604.9865279198 (almost 2h)

2

ওয়েল, ইউএল এবং এলআইতে পার্স করার জন্য এটি এমন কিছু হবে:

$array = array (
    'H' => 'G'
    'F' => 'G'
    'G' => 'D'
    'E' => 'D'
    'A' => 'E'
    'B' => 'C'
    'C' => 'E'
    'D' => 'NULL'
);


recurse_uls ($array, 'NULL');

function recurse_uls ($array, $parent)
{
    echo '<ul>';
    foreach ($array as $c => $p)  {
        if ($p != $parent) continue;
        echo '<li>'.$c.'</li>';
        recurse_uls ($array, $c);
    }
    echo '</ul>';
}

তবে আমি এমন একটি সমাধান দেখতে চাই যা আপনাকে এ্যারে ঘন ঘন ঘন ঘন ঘন ঘন ঘন ঘন ঘন প্রয়োজন হয় না ...


2

আমি এখানে যা এলাম তা এখানে:

$arr = array(
            'H' => 'G',
            'F' => 'G',
            'G' => 'D',
            'E' => 'D',
            'A' => 'E',
            'B' => 'C',
            'C' => 'E',
            'D' => null );

    $nested = parentChild($arr);
    print_r($nested);

    function parentChild(&$arr, $parent = false) {
      if( !$parent) { //initial call
         $rootKey = array_search( null, $arr);
         return array($rootKey => parentChild($arr, $rootKey));
      }else { // recursing through
        $keys = array_keys($arr, $parent);
        $piece = array();
        if($keys) { // found children, so handle them
          if( !is_array($keys) ) { // only one child
            $piece = parentChild($arr, $keys);
           }else{ // multiple children
             foreach( $keys as $key ){
               $piece[$key] = parentChild($arr, $key);
             }
           }
        }else {
           return $parent; //return the main tag (no kids)
        }
        return $piece; // return the array built via recursion
      }
    }

আউটপুট:

Array
(
    [D] => Array
        (
            [G] => Array
                (
                    [H] => H
                    [F] => F
                )

            [E] => Array
                (
                    [A] => A
                    [C] => Array
                        (
                            [B] => B
                        )    
                )    
        )    
)

1

অভিভাবক-সন্তানের সম্পর্ক নেস্টেড অ্যারে
ডাটাবেস থেকে সমস্ত রেকর্ড আনুন এবং নেস্টেড অ্যারে তৈরি করে।

$data = SampleTable::find()->all();
$tree = buildTree($data);
print_r($tree);

public function buildTree(array $elements, $parentId = 0) {
    $branch = array();
    foreach ($elements as $element) {
        if ($element['iParentId'] == $parentId) {
            $children =buildTree($elements, $element['iCategoriesId']);
            if ($children) {
                $element['children'] = $children;
            }
            $branch[] = $element;
        }
    }
    return $branch;
}

জেসন ফর্ম্যাটে বিভাগ এবং উপ-বিভাগের ডেটা মুদ্রণ করুন

public static function buildTree(array $elements, $parentId = 0){
    $branch = array();
    foreach($elements as $element){
        if($element['iParentId']==$parentId){
            $children =buildTree($elements, $element['iCategoriesId']);
            if ($children) {
                $element['children'] = $children;

            }
                $branch[] = array(
                    'iCategoriesId' => $element->iCategoriesId,
                    'iParentId'=>$element->iParentId,
                    'vCategoriesName'=>$element->vCategoriesName,
                    'children'=>$element->children,
            );
        }
    }
    return[
        $branch
    ];
}

0
$tree = array(
    'H' => 'G',
    'F' => 'G',
    'G' => 'D',
    'E' => 'D',
    'A' => 'E',
    'B' => 'C',
    'C' => 'E',
    'D' => null,
    'Z' => null,
    'MM' =>'Z',
    'KK' =>'Z',
    'MMM' =>'MM',
    // 'MM'=>'DDD'
);

এএ = $ this-> parseTree ($ গাছ) $;

public function get_tress($tree,$key)
{

    $x=array();
    foreach ($tree as $keys => $value) {
        if($value==$key){
        $x[]=($keys);
        }
    }
    echo "<li>";
    foreach ($x as $ke => $val) {
    echo "<ul>";
        echo($val);
        $this->get_tress($tree,$val);
    echo "</ul>";
    }
    echo "</li>";


}
function parseTree($tree, $root = null) {

    foreach ($tree as $key => $value) {
        if($value==$root){

            echo "<ul>";
            echo($key);
            $this->get_tress($tree,$key);
            echo "</ul>";
        }
    }

0

পুরানো প্রশ্ন, তবে আমারও এটি করতে হয়েছিল এবং পুনরাবৃত্তি সহ উদাহরণগুলি আমাকে মাথা ব্যথা করে। আমার ডাটাবেসে আমাদের একটি locationsটেবিল রয়েছে, যা ছিল loca_idপিকে (শিশু) এবং স্ব-রেফারেন্সিংloca_parent_id (পিতামাতার)।

লক্ষ্যটি এইচটিএমএলে এই কাঠামোর প্রতিনিধিত্ব করা। কোয়ের্সের সহজ ক্যোয়ারী ডেটা ফেরত দেওয়ার জন্য কিছু স্থির ক্রম হয় তবে প্রাকৃতিক উপায়ে এ জাতীয় ডেটা প্রদর্শন করার মতো পর্যাপ্ত পরিমাণ আমি পাইনি। আমি যা চাইছিলাম তা হ'ল ওরাকল ট্রি ওয়াক হ্যান্ডলিংয়ের LEVELসাথে প্রদর্শনের জন্য সহায়তা করার জন্য।

আমি প্রতিটি প্রবেশকে স্বতন্ত্রভাবে সনাক্ত করতে একটি 'পথ' ধারণাটি ব্যবহার করার সিদ্ধান্ত নিয়েছি। উদাহরণ স্বরূপ:

পথ দ্বারা অ্যারে বাছাই করা অর্থপূর্ণ প্রদর্শনের জন্য প্রক্রিয়া করা সহজতর করা উচিত।

আমি বুঝতে পারি যে সহযোগী অ্যারে এবং প্রকারের ব্যবহার প্রতারণাপূর্ণ হওয়ায় এটি অপারেশনের পুনরাবৃত্ত জটিলতা লুকিয়ে রাখে, তবে আমার কাছে এটি সহজ চেহারা:

<table>
<?php
    
    $sql = "
    
    SELECT l.*,
           pl.loca_name parent_loca_name,
           '' loca_path
    FROM locations l
    LEFT JOIN locations pl ON l.loca_parent_id = pl.loca_id
    ORDER BY l.loca_parent_id, l.loca_id
    
    ";
    
    function print_row ( $rowdata )
    {
    ?>
                      <tr>
                          <td>
                              <?=$rowdata['loca_id']?>
                          </td>
                          <td>
                              <?=$rowdata['loca_path']?>
                          </td>
                          <td>
                              <?=$rowdata['loca_type']?>
                          </td>
                          <td>
                              <?=$rowdata['loca_status']?>
                          </td>
                      </tr>
    <?php
    
    }
    
    $stmt  = $dbh->prepare($sql);
    $stmt->execute();
    $result = $stmt->get_result();
    $data = $result->fetch_all(MYSQLI_ASSOC);
    
    $printed = array();
    
    // To get tree hierarchy usually means recursion of data.
    // Here we will try to use an associate array and set a
    // 'path' value to represent the hierarchy tree in one
    // pass. Sorting this array by the path value should give
    // a nice tree order and reference.
// The array key will be the unique id (loca_id) for each row.
// The value for each key will the complete row from the database.
// The row contains a element 'loca_path' - we will write the path
// for each row here. A child's path will be parent_path/child_name.
// For any child we encounter with a parent we look up the parents path
// using the loca_parent_id as the key.
// Caveat, although tested quickly, just make sure that all parents are
// returned first by the query.
    
    foreach ($data as $row)
    {
    
       if ( $row['loca_parent_id'] == '' ) // Root Parent
       {
          $row['loca_path'] = $row['loca_name'] . '/';
          $printed[$row['loca_id']] = $row;
       }
       else // Child/Sub-Parent
       {
          $row['loca_path'] = $printed[$row['loca_parent_id']]['loca_path'] . $row['loca_name'] . '/';
          $printed[$row['loca_id']] = $row;
       }
    }
    
    // Array with paths built, now sort then print
    
    array_multisort(array_column($printed, 'loca_path'), SORT_ASC, $printed);
    
    foreach ( $printed as $prow )
    {
       print_row ( $prow );
    }
    ?>
    </table>

-1

ডায়নামিক ট্রি ভিউ এবং মেনু কীভাবে তৈরি করবেন

পদক্ষেপ 1: প্রথমে আমরা mysql ডাটাবেসে ট্রিভিউ সারণী তৈরি করব। এই টেবিলটিতে চারটি কলাম রয়েছে id আইডিটি হল টাস্ক আইডি এবং নামটি কার্যটির নাম।

-
-- Table structure for table `treeview_items`
--

CREATE TABLE IF NOT EXISTS `treeview_items` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `name` varchar(200) NOT NULL,
  `title` varchar(200) NOT NULL,
  `parent_id` varchar(11) NOT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB  DEFAULT CHARSET=latin1 AUTO_INCREMENT=7 ;

--
-- Dumping data for table `treeview_items`
--

INSERT INTO `treeview_items` (`id`, `name`, `title`, `parent_id`) VALUES
(1, 'task1', 'task1title', '2'),
(2, 'task2', 'task2title', '0'),
(3, 'task3', 'task1title3', '0'),
(4, 'task4', 'task2title4', '3'),
(5, 'task4', 'task1title4', '3'),
(6, 'task5', 'task2title5', '5');

পদক্ষেপ 2: ট্রি ভিউ রিকার্সিভ পদ্ধতিটি আমি ট্রি ক্রিয়েটভিউ () পদ্ধতির নীচে তৈরি করেছি যা বর্তমান টাস্ক আইডি পূর্বের টাস্ক আইডি থেকে বেশি হলে পুনরাবৃত্তিকে কল করে।

function createTreeView($array, $currentParent, $currLevel = 0, $prevLevel = -1) {

foreach ($array as $categoryId => $category) {

if ($currentParent == $category['parent_id']) {                       
    if ($currLevel > $prevLevel) echo " <ol class='tree'> "; 

    if ($currLevel == $prevLevel) echo " </li> ";

    echo '<li> <label for="subfolder2">'.$category['name'].'</label> <input type="checkbox" name="subfolder2"/>';

    if ($currLevel > $prevLevel) { $prevLevel = $currLevel; }

    $currLevel++; 

    createTreeView ($array, $categoryId, $currLevel, $prevLevel);

    $currLevel--;               
    }   

}

if ($currLevel == $prevLevel) echo " </li>  </ol> ";

}

পদক্ষেপ 3: গাছের দৃশ্য দেখানোর জন্য সূচী ফাইল তৈরি করুন। এটি ট্রিউউভিউর মূল ফাইল এটি উদাহরণ হিসাবে আমরা প্রয়োজনীয় পরামিতিগুলির সাথে ক্রিয়েটরিভিউ () পদ্ধতিটি কল করব।

 <body>
<link rel="stylesheet" type="text/css" href="_styles.css" media="screen">
<?php
mysql_connect('localhost', 'root');
mysql_select_db('test');


$qry="SELECT * FROM treeview_items";
$result=mysql_query($qry);


$arrayCategories = array();

while($row = mysql_fetch_assoc($result)){ 
 $arrayCategories[$row['id']] = array("parent_id" => $row['parent_id'], "name" =>                       
 $row['name']);   
  }
?>
<div id="content" class="general-style1">
<?php
if(mysql_num_rows($result)!=0)
{
?>
<?php 

createTreeView($arrayCategories, 0); ?>
<?php
}
?>

</div>
</body>

পদক্ষেপ 4: সিএসএস ফাইল তৈরি করুন স্টাইল। CSS এখানে আমরা সমস্ত CSS সম্পর্কিত ক্লাস লিখব, বর্তমানে আমি বৃক্ষের দৃশ্য তৈরি করতে অর্ডার তালিকাটি ব্যবহার করছি। আপনি এখানে চিত্রের পথও পরিবর্তন করতে পারেন।

img { border: none; }
input, select, textarea, th, td { font-size: 1em; }

/* CSS Tree menu styles */
ol.tree
{
    padding: 0 0 0 30px;
    width: 300px;
}
    li 
    { 
        position: relative; 
        margin-left: -15px;
        list-style: none;
    }
    li.file
    {
        margin-left: -1px !important;
    }
        li.file a
        {
            background: url(document.png) 0 0 no-repeat;
            color: #fff;
            padding-left: 21px;
            text-decoration: none;
            display: block;
        }
        li.file a[href *= '.pdf']   { background: url(document.png) 0 0 no-repeat; }
        li.file a[href *= '.html']  { background: url(document.png) 0 0 no-repeat; }
        li.file a[href $= '.css']   { background: url(document.png) 0 0 no-repeat; }
        li.file a[href $= '.js']        { background: url(document.png) 0 0 no-repeat; }
    li input
    {
        position: absolute;
        left: 0;
        margin-left: 0;
        opacity: 0;
        z-index: 2;
        cursor: pointer;
        height: 1em;
        width: 1em;
        top: 0;
    }
        li input + ol
        {
            background: url(toggle-small-expand.png) 40px 0 no-repeat;
            margin: -0.938em 0 0 -44px; /* 15px */
            height: 1em;
        }
        li input + ol > li { display: none; margin-left: -14px !important; padding-left: 1px; }
    li label
    {
        background: url(folder-horizontal.png) 15px 1px no-repeat;
        cursor: pointer;
        display: block;
        padding-left: 37px;
    }

    li input:checked + ol
    {
        background: url(toggle-small.png) 40px 5px no-repeat;
        margin: -1.25em 0 0 -44px; /* 20px */
        padding: 1.563em 0 0 80px;
        height: auto;
    }
        li input:checked + ol > li { display: block; margin: 0 0 0.125em;  /* 2px */}
        li input:checked + ol > li:last-child { margin: 0 0 0.063em; /* 1px */ }

আরো বিস্তারিত

আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.