0

親メッセージへの参照を含むメッセージの配列があります。次のようになります。

array (
  'm1' => array ('m9'),
  'm5' => array ('m3', 'm4', 'm2'),
  'm2' => array ('m1'),
  'm3' => array ('m2', 'm1', 'm8'),
  'm6' => array ('m7'),
  'm4' => array ('m3', 'm2'),
)

この配列のキーはメッセージ ID で、値は0 個以上の親 ID への参照です (順不同)。ID の順序はランダムである可能性があり、参照された親 ID が特定のメッセージ セットに含まれているとは限りません。

私がする必要があるのは、これらのメッセージを「スレッド ビュー」にグループ化することです。基本的に、この配列を次のようなものに変換する必要があります。

array(
  'm1' => array('m1', 'm2', 'm3', 'm4', 'm5'),
  'm6' => array('m6')
);

すべてのメッセージは、最上位メッセージでグループ化されたスレッドに割り当てられる必要があります。親への参照がない場合、または参照された親がセットに存在しない場合、メッセージはトップレベルであると見なされます。メッセージ 'm1' と 'm6' は、指定されたセットに 'm9' と 'm7' がないため、トップレベルです。メッセージ 'm3' は、存在しない 'm8' への参照にもかかわらず 'm1' スレッドにあります - それを 'm1' にリンクする他の既存の親があります。

私の質問は、それを行う方法と、効率的に行う方法です。どんな助けでも大歓迎です。

アップデート:

私が思いついたのは、最初にこれらの関係を逆にすることです。したがって、次のようになります。

array (
  'm9' => array ('m1'), # this would be rejected
  'm3' => array ('m5', 'm4'),
  'm4' => array ('m5'),
  'm2' => array ('m5', 'm3', 'm4'),
  'm1' => array ('m2', 'm3'),
  'm8' => array ('m3'), # this would be rejected
  'm7' => array ('m6'), # this would be rejected
)

次に、入力キーには存在するが変換された配列には存在しないため、キー 'm6' と 'm5' を子なしで追加します。

これで、入力データで見つけることができるすべての関係の親 => 子ができました。この配列のキーを入力配列と比較した後、キー「m9」、「m8」、および「m7」を存在しないとして拒否できます。

最終的に、配列は次のようになります。

array (
  'm3' => array ('m5', 'm4'),
  'm4' => array ('m5'),
  'm2' => array ('m5', 'm3', 'm4'),
  'm1' => array ('m2', 'm3'),
  'm6' => array(),
  'm5' => array()
)

私が今しなければならないことは、この構造をどうにかして平らにすることです。別の親p2の子でもあるすべての親p1を検索し、 p1の子をp2の子に追加する必要があります。これらの配列を何度も繰り返す以外の方法でそれを行う方法はわかりませんが、ここではオプションではありません。

4

1 に答える 1

0

これは私にとって興味深い挑戦のように思えました。これまでに達成したこと:

まず第一に、孤児を取り除くかもしれません:

$a = array (
  'm1' => array ('m9'),
  'm5' => array ('m3', 'm4', 'm2'),
  'm2' => array ('m1'),
  'm3' => array ('m2', 'm1', 'm8'),
  'm6' => array ('m7'),
  'm4' => array ('m3', 'm2'),
);

$f = array_map(function($v) use (&$a) {
  $k = key($a); next($a);
  $vals = array_filter($v, function($el) use ($a) {
    return isset($a[$el]);
  });
  return empty($vals) ? [$k] : $vals;
}, $a);

後者は、子の配列にマッピングする配列を提供します。

お気に入りのarray_flatten関数が手元にあると仮定します。

function array_flatten($array, $return) {
  for($x = 0; $x <= count($array); $x++) {
    if(isset($array[$x]) && is_array($array[$x])) {
      $return = array_flatten($array[$x], $return);
    } else {
      if(isset($array[$x])) {
        $return[] = $array[$x];
      }
    }
  }
  return $return;
}

これで、以下の関数を使用してツリーをたどることができます。

function resolve_parents(&$f) {
  array_walk($f, function(&$v, $k) use(&$f) {
    if(!is_array($v)) { // great! that’s what we needed
      $f[$k] = $v; 
    } else if(count($v) > 1) { // many children left
      $f[$k] = array_unique(
                 array_flatten(
                   array_map(function($v) use(&$f) { 
                     return $f[$v]; 
                   }, $v), 
                 array())
               );
    } else {  // great, one child left, store it as result
      $f[$k] = $v[0];
    };  
  }); 
}

まあ、それは私たちに一歩上の解決策を与えてくれます。必要に応じて何度でも実行してください ( arrayas 値がないことを確認してください ⇒ すべてが解決されます):

function check_result($arr) {
  return array_reduce($arr, function($memo, $v) { 
    return $memo = $memo && !is_array($v); }, true);
}
while(!check_result($f)) resolve_parents($f);

最終的に配列を生成します。

// Array
// (
//    [m1] => m1
//    [m5] => m1
//    [m2] => m1
//    [m3] => m1
//    [m6] => m6
//    [m4] => m1
// )

どうやらあなたの質問に対する答えです。

残念ながら、上記の方法は洗練されておらず、効率的であることが証明されていません。コードがヒントになる場合に備えて、ここに残しました。

ご不明な点がございましたら、お気軽にお問い合わせください。

于 2015-02-05T13:39:22.720 に答える