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,值是对零个或多个父 ID 的引用(以任何顺序)。ID 的顺序可以是随机的,并且不能保证引用的父 ID 在给定的消息集中。

我需要做的是将这些消息分组在“线程视图”中。所以基本上我需要把这个数组转换成这样的东西:

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

每条消息都应分配给按顶级消息分组的线程。当消息没有对父级的引用或被引用的父级在集合中不存在时,它被认为是顶级的。消息“m1”和“m6”是顶级的,因为“m9”和“m7”不在给定集中。尽管引用了不存在的“m8”,但消息“m3”位于“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”,因为它们存在于输入键中,但不存在于转换后的数组中。

现在我有了可以在输入数据中找到的每个关系 parent => children。在将此数组的键与输入数组进行比较后,我可以将键“m9”、“m8”和“m7”拒绝为不存在。

最后数组看起来像这样:

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

我现在需要做的是以某种方式扁平化这个结构。我需要找到每个父母p1也是另一个父母p2的孩子,并将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);

后者给出了一个数组,将parents映射到children 数组

假设您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 回答