簡體   English   中英

根據平面陣列和結構化ID構建陣列樹

[英]Build an array tree from flat array and structured ID

如果您對問題感到困惑,請稍等一下,因為我不確定這是否完全正確。

SELECT * FROM `rules` ORDER BY `Rank_1` , `Rank_2` , `Rank_3` , `Rank_4` ASC

產量:

http://img814.imageshack.us/img814/8396/climsyclipboardeh.png

復制面食:

0   0   0   0   0
1   0   0   0   1
1   1   0   0   1.1
1   1   1   0   1.1.1 
2   0   0   0   2
4   0   0   0   4
4   1   0   0   4.1
4   1   1   0   4.1.1 
4   1   1   9   4.1.1.9
4   1   1   10  4.1.1.10 
4   1   1   11  4.1.1.11

但是,此數據並不是我需要的形式,以便對其進行有用的處理。

我想遍歷所有規則,並根據自己的“深度”做不同的事情。 例如,我想使用RuleID = 0並執行<h1> ,1.1具有<h2>但是當涉及到4.1.x時,打開一個<ul>並給每個規則一個<li>

為此,我認為最好的方法是像選擇數組那樣選擇數據,最終得到的結果是:

array( 4 =>
    array( 4.1 =>
        array( 4.1.1 => 'rule content')
    )
);

然后,我可以意識到我的深度並打開<ul>標簽,循環遍歷該深度的規則,以此類推。

真正解決這個問題的最佳方法是什么? 我已經有很長一段時間了,老實說,不知道從這里去哪里。 我真的希望數據在同一張表中。 我想如果它們都在不同的表中,我可能可以解決此問題,但我不知道這肯定會更容易。

我從這條路線開始:

foreach($m as $rule) {
    $depth = count(explode('.', $rule['ruleid']));
    switch($depth) {
        case 1:
            echo '<h1>'.$rule['content'].'</h1>';
            break;
        case 2:
            echo '<h2>'.$rule['content'].'</h2>';
            break;
        case 3:
            echo '<strong>'.$rule['content'].'</strong>';
            break;
    }
    echo '<br />\n';
}

然后我意識到這只是要單獨處理每個規則條目,而我的解決方案需要某種“意識”到規則中的位置,因此它可以知道何時打開標簽(例如<ul> )然后在回顯規則中可能存在的列表項后再次關閉它(例如"Don't do: <ul><li>this</li><li>or this</li></ul>"

這是上面數據表中所需輸出的示例:

0.簡介

...

4.聊天

4.1。 做和不做

4.1.1。 做:

  • 4.1.1.9要有禮貌
  • 4.1.1.10要有耐心
  • 4.1.1.11要聰明

希望一些火花能幫助到您!

假設從您的輸入數據中,您可以產生一個像這樣的數組:

$data = array(
  '0'        => 'content 0',
  '1'        => 'content 1',
  '1.1'      => 'content 1.1',
  '1.1.1'    => 'content 1.1.1',
  '2'        => 'content 2',
  '4'        => 'content 4',
  '4.1'      => 'content 4.1',
  '4.1.1'    => 'content 4.1.1',
  '4.1.1.9'  => 'content 4.1.1.9',
  '4.1.1.10' => 'content 4.1.1.10',
  '4.1.1.11' => 'content 4.1.1.11',
);

然后您可以將其轉換為樹狀結構:

// this will be our root node
// it has no content, but a place for children
$struct = array(
  'children' => array()
);

foreach ($data as $ruleID => $content) {
  //                 /\
  //                 ||
  //     for every rule id in the input data we start at
  //     the root
  //          ||
  //          \/
  $parent =& $struct;

  // we split $ruleID at the dot to get a path, which we traverse
  //            ||
  //            \/
  foreach (explode('.', $ruleID) as $val) {

    // for every entry in the path we
    // check if it's available in the current parent
    //    ||
    //    \/
    if (!isset($parent['children'][$val])) {
      // if not, we create an empty entry
      $parent['children'][$val] = array(
        'content' => '',       // no content
        'children' => array()  // no children
      );
    }

    //                         /\
    //                         ||
    // and then use either the new, or allready existent parent
    // as the new parent
    //      ||
    //      ||  mind the assignment by reference! this
    //      \/  is the most important part
    $parent =& $parent['children'][$val];
  }

  // after the whole path is traversed, we can
  // finally add our content
  //                    ||
  //                    \/
  $parent['content'] = $content;
}

print_r($struct);

演示: http//codepad.org/vtMPjGoa

如果想以某種可能破壞各種樣式規則的方式將HTML與SQL混合,則可以添加“ ruledepth”列,然后在其上使用“ CASE”,例如:


SELECT othercols, 
CASE 
WHEN ruledepth=0 THEN CONCAT('<h1>', ruleid, '</h1>') 
WHEN ruledepth=1 THEN CONCAT('<h2>', ruleid, '</h2>') 
WHEN ruledepth=2 THEN CONCAT('<li>', rileid, '</li>')
etc
END FROM XXX WHERE .... ORDER BY ruleid........

對OPs代碼稍作修改。

您可以將$rule['ruleid']到echo語句中,使其與所需的輸出完全相同。

$hasList=false;
foreach($m as $rule) {
    $depth = count(explode('.', $rule['ruleid']));
    // end previous list before starting with new rules
    if ($hasList && $depth<4) {
        echo '</ul>';
        $hasList=false;
    }
    switch($depth) {
        case 1:
            echo '<h1>'.$rule['content'].'</h1>';
            break;
        case 2:
            echo '<h2>'.$rule['content'].'</h2>';
            break;
        case 3:
            echo '<strong>'.$rule['content'].'</strong>';
            break;
        case 4:
            // start list if not already started
            if (!$hasList) {
                echo '<ul>';
                $hasList=true;
            }
            echo '<li>'.$rule['content'].'</li>';
            break;
    }
    //echo "<br />\n";
}
// end last list
if ($hasList) {
    echo '</ul>';
    $hasList=false;
}

我不確定這是否正是您所需要的,但是也許它將給您一些想法。

首先,您可以通過執行以下操作來確定規則的“深度”:

$depth = count(explode('.',$rule_id));

這將在上拆分您的規則ID . 並制作一個數組。 然后,它計算數組中的項目以確定深度。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM