在PHP中对线程中的消息进行分组

在PHP中对线程中的消息进行分组,php,threaded-comments,Php,Threaded Comments,我有一个消息数组,其中包含对父消息的引用,如下所示: array ( 'm1' => array ('m9'), 'm5' => array ('m3', 'm4', 'm2'), 'm2' => array ('m1'), 'm3' => array ('m2', 'm1', 'm8'), 'm6' => array ('m7'), 'm4' => array ('m3', 'm2'), ) array( 'm1' =>

我有一个消息数组,其中包含对父消息的引用,如下所示:

array (
  'm1' => array ('m9'),
  'm5' => array ('m3', 'm4', 'm2'),
  'm2' => array ('m1'),
  'm3' => array ('m2', 'm1', 'm8'),
  'm6' => array ('m7'),
  'm4' => array ('m3', 'm2'),
)
array(
  'm1' => array('m1', 'm2', 'm3', 'm4', 'm5'),
  'm6' => array('m6')
);
array (
  'm3' => array ('m5', 'm4'),
  'm4' => array ('m5'),
  'm2' => array ('m5', 'm3', 'm4'),
  'm1' => array ('m2', 'm3'),
  'm6' => array(),
  'm5' => array()
)
此数组的键是消息ID,值是对零个或多个父ID的引用(以任何顺序)。ID的顺序可以是随机的,并且不能保证引用的父ID在给定的消息集中

我需要做的是在“线程视图”中将这些消息分组。因此,基本上我需要将这个数组转换为如下内容:

array (
  'm1' => array ('m9'),
  'm5' => array ('m3', 'm4', 'm2'),
  'm2' => array ('m1'),
  'm3' => array ('m2', 'm1', 'm8'),
  'm6' => array ('m7'),
  'm4' => array ('m3', 'm2'),
)
array(
  'm1' => array('m1', 'm2', 'm3', 'm4', 'm5'),
  'm6' => array('m6')
);
array (
  'm3' => array ('m5', 'm4'),
  'm4' => array ('m5'),
  'm2' => array ('m5', 'm3', 'm4'),
  'm1' => array ('m2', 'm3'),
  'm6' => array(),
  'm5' => array()
)
每个消息都应该分配给一个按顶级消息分组的线程。当消息未引用父消息或引用的父消息在集合中不存在时,该消息被视为顶级消息。 消息“m1”和“m6”是顶级的,因为“m9”和“m7”不在给定的集合中。消息“m3”位于“m1”线程中,尽管引用了不存在的“m8”-它还有其他现有的父线程将其链接到“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=>子级。将此数组的键与输入数组进行比较后,我可以拒绝键“m9”、“m8”和“m7”,因为它们不存在

最后,阵列将如下所示:

array (
  'm1' => array ('m9'),
  'm5' => array ('m3', 'm4', 'm2'),
  'm2' => array ('m1'),
  'm3' => array ('m2', 'm1', 'm8'),
  'm6' => array ('m7'),
  'm4' => array ('m3', 'm2'),
)
array(
  'm1' => array('m1', 'm2', 'm3', 'm4', 'm5'),
  'm6' => array('m6')
);
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子级。
除了一次又一次地迭代那些数组之外,我不知道如何用另一种方法来实现它,但这在这里不是一个选项。

这对我来说似乎是一个有趣的挑战。我迄今为止取得的成就:

首先,我们可以摆脱孤儿:

$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);
后者提供一个数组,将父数组映射到子数组

假设您手头有您最喜欢的
阵列展平
功能:

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;
}
好吧,它给了我们一个前进的决心。根据需要多次运行它(检查是否没有
array
as值⇒ 一切都解决了):

我们将最终生成一个数组:

// Array
// (
//    [m1] => m1
//    [m5] => m1
//    [m2] => m1
//    [m3] => m1
//    [m6] => m6
//    [m4] => m1
// )
这显然是你问题的答案

不幸的是,上述方法既不优雅,也没有被证明是有效的。我只是把它放在这里,以防代码提示你


如果您有任何问题,请随时提问。

我不确定我是否理解您的申请,但有许多单条消息的家长对我来说有点奇怪。通常它的对立面-单亲有很多子线程,不可能通过这个输入数据来检索队列中的消息顺序。好的,任何消息都可以有对给定线程中任何先前消息的父引用,这不取决于我。消息的顺序在这里并不重要,我所需要的只是创建关系top parent=>children。如果您正在构建一个评论系统(而不仅仅是问一个理论问题),为什么不添加一个名为“thread\u id”的列,使您的查询更简单呢?每当有人发布新评论时,如果是对另一条评论的回复,请使用该评论的“线程id”,如果是第一条评论,请将线程id设置为该评论自己的id。这不是评论系统,也不是理论问题。我从外部系统以描述的格式输入数据,我需要处理它。当然,最终它会存储在一些正常的结构中,但首先我需要解析这些数据。非常感谢!这正是我需要的。我提出了更不雅观的解决方案——更多的迭代,更多的代码,但结果是相同的,大约100个消息数据集的执行时间几乎相同,所以我可能会部分地切换到您的解决方案。也许以后我会找到一种方法来优化它。再次感谢。