2015-01-12 1 views
-1

У меня есть таблица в базе данных MySQL, которая представляет дерево генетического языка. Каждая строка - это язык с идентификатором и родительским идентификатором; например:(PHP) Совокупный подсчет дочерних элементов в многомерном массиве, заполняемый рекурсивной функцией

id | language   | parent 
-----+---------------------+-------- 
1 | Proto-Indo-European | NULL 
6 | Celtic    | 1 
8 | Insular Celtic  | 6 
9 | Goidelic   | 8 
14 | Irish    | 9 
16 | Manx    | 9 
21 | British    | 8 
22 | Welsh    | 21 
109 | Germanic   | 1 
115 | West Germanic  | 109 
117 | Anglo-Saxon   | 115 
118 | Anglic    | 117 
119 | Old English   | 118 

Моя цель состоит в том, чтобы превратить эти строки в довольно вложенный список HTML с совокупными счетчиками после каждого языка, который имеет дочерние языки, используя простую рекурсивную функцию PHP, в результате чего-то вроде этого (на основе языки в примере выше строк):

  • прото-индо-европейские (11)
    • Кельтский (6)
      • Островные Кельтский (5)
        • Goidelic (2)
          • Ирландский
          • Манкс
        • Британский (1)
          • Welsh
    • германское (4)
      • западногерманской (3)
        • англосаксонская (2)
          • англик (1)
            • Старый Английский

У меня есть следующие PHP функции (упрощенный здесь), который создает многомерный массив с правильной структурой:

function select_languages_hierarchical($parent = NULL) { 
    global $db; 
    $branch = array(); 
    $query = "SELECT * FROM languages WHERE parent = $parent"; 

    if ($q = $db->query($query)) { 
     while ($row = $q->fetch_assoc()) { 
      $element['id'] = $row['id']; 
      $element['name'] = $row['language']; 
      $children = select_languages_hierarchical($row['id']); 

      if ($children) { 
       $element['children'] = $children; 
      } 

      $branch[] = $element; 
     } 
    } 
    return $branch; 
} 

Это производит массив, соответствующий вложенный список выше, с вложенными массивы, находящиеся в элементе children каждого массива.

Тем не менее, я просто не могу для жизни, несмотря на то, что у меня много проблем, Googling, и просматривая куча рекурсии, подсчета агрегатов и подсчета массива здесь, на SO, выясните способ создания счетчики, которые описывают количество языков-потомков для каждого языка.

Независимо от того, что я делаю, где бы я ни создавал, изменял и использовал свои счетные переменные, и что бы я ни делал, подсчитывая (независимо от того, выполняете ли счетчик $ count ++ каждый раз, когда я перебираю язык, сделайте «count» ($ children) и т.д.), Я всегда в конечном итоге с результатами, когда счетчик не сбрасывается, когда функция достигает «высокий» уровень, так что я получаю списки, как это вместо:

  • прото-индо-европейский (12)
    • Кельтский (6)
      • Островные Кельтский (5)
        • Goidelic (2)
          • Ирландский
          • Манкс
        • Британский (4)
          • Вельш
    • германском (9)
      • западногерманской (12)
        • англосаксонская (14)
          • англик (15)
            • Старый Английский

- Или что-то подобное, что-чисел и как они складываются различаются в разных которые я предпринял; но у всех их есть общее, что счетчик постоянно увеличивается, без перезагрузки.Или же, если я пытаюсь сбросить его в какой-то момент, естественно, он получает сброс на каждой итерации, оставляя меня:

  • прото-индо-европейского (2)
    • кельтской (2)
      • Островные Селтик (1)
        • Goidelic (2)
          • Ирландский
          • Манкс
        • British (1)
          • Welsh
    • германское (1)
      • западногерманской (1)
        • Ang ло-саксонской (1)
          • англик (1)
            • Старый Английский

Очевидно, что логика не моя сильная костюм здесь.

Может кто-нибудь помочь моему мозгу от спонтанного сжигания и/или взрыва, предложив мне способ достичь такого «умного подсчета», который я ищу здесь?

+0

Вы близко.В основном обновите свой массив, чтобы вы сохраняли счетчик child и дочернюю информацию на каждом узле. например '$ node ['count'] = 3, $ node ['name'] = 'West Germanic', $ node ['children'] = массив дочерних языков'. –

+0

@MarcB Это именно то, что я пытаюсь сделать. Проблема заключается в получении правильного числа - i.e., '3' в вашем примере - для хранения в' $ element ['countchildren'] '(как я его называл в своем коде). –

+0

, когда вы выполняете свой рекурсивный вызов. в основном обновить текущий счетчик текущего узла с помощью счетчика, хранящегося в узле, который вы получили от рекурсивного вызова, например. '$ curnode ['count'] + = $ children ['count']'. Проблема в том, что вы просто делаете '$ element ['children'] = $ children', что заменит ваши предыдущие рекурсивные вызовы. вам нужно будет объединить результаты. –

ответ

1

Думая об этом, вместо того, чтобы запускать zillion-рекурсивные запросы в PHP, вы можете просто сделать базовый select * и построить свое дерево в PHP и сделать подсчет там. Из cousre это было бы полезно только в том случае, если вы хотите, чтобы все дерево языков.

$lang = array(); 
$sql = "SELECT * FROM languages"; 
... run query ... 
while($row = fetch results) { 
    // store this lang's node 
    $lang[$row['id']]['name'] = $row['name']; 

    // add this language to its parent's child array 
    $lang[$row['parent']]['children'][$row['id']] = $row['id']; 

    // increment its parent's counter 
    $lang[$row['parent']]['count']++; 
} 

Теперь, это, вероятно, выбрасывает кучу предупреждений о неопределенных массивах и этажерках, так как я не испытывая для существования родителей, прежде чем пытаться обновляет это рассчитывает. Но это всего лишь базовые вещи if (!isset()) { initialize node }.

Выход в вашу вложенную <ul> будет рекурсивной функцией, но так как вы теперь получили отсчеты ребенка узел в уже дереве, это будет намного проще:

function output($id = 1) { // assuming "1" is your tree root node 
    echo '<li>' . $lang[$id]['name'] . '(' . $lang[$id]['count'] . ')'; 
    if ($lang[$id]['count'] > 0) { 
     echo '<ul>'; 
     foreach($lang[$id]['children'] as $childID) { 
      output($childID); 
     } 
     echo '</ul>'; 
    } 
    echo '</li>'; 
} 
+0

Это очень аккуратное и хорошее боковое мышление! Я поиграл с идеей просто построить дерево в PHP полностью (экономия на gazillion MySQL-запросах - всегда хорошая идея), но не мог понять хороший, чистый способ сделать это. Попробуй это и примите, если я смогу заставить его работать так, как ожидалось. :-) –