【问题标题】:Sorting a list of tuplets linked with each other对相互链接的连音列表进行排序
【发布时间】:2021-08-05 09:34:57
【问题描述】:

我想问一个关于 Java 排序的问题,确切地说,我需要对一个元组列表(定义为自定义类)进行排序,但它们像树一样相互链接。

基本上,这是一个表达父子关系的文档 ID 列表,并被组织为集合(可能是无序的)。元组已经过滤为具有唯一的左/右元素,因此树在文档之间具有唯一的链接(它们不允许有多个叶子)。

使用示例数据,我有这样的列表:[(1,2), (3,4), (0,1), (2,3)],这代表以下树:

0
|_ 1
   |_ 2
      |_ 3
         |_ 4

因此我需要按以下顺序排列列表:[(0,1), (1,2), (2,3), (3,4)]

我还补充说父文档 id 可能大于子文档 id,因此不可能根据哪个 id 更大进行简单排序。

在使自定义类具有可比性并添加以下代码后,我尝试使用 Stream 类的 .sorted() 方法:

    @Override
    public int compareTo(DocumentIdVersionsStack o) {
        if (parentDocumentId == o.getChildDocumentId()) return  1;
        if (childDocumentId == o.getParentDocumentId()) return  -1;
        return 0;
    }

如果当前一个是另一个元组的子级,则基本上告诉它反转顺序,反之亦然,但列表仍然不是我期望的。

知道如何使用流来做到这一点吗?我不想使用需要递归的复杂排序方法,只是为了保持代码更干净,但如果不能这样做,我会检查一下。

谢谢!

编辑: 我将添加一些信息:

  • 元组已经是连续的,不会有缺少 id 的“漏洞”
  • 在将元组传递给排序方法之前再次注意递归(最后一个 id = 第一个 id)
  • 将有一个元组的左值在任何右值中都找不到 -> 这将是排序后的第一个元素
  • 在任何左侧值中都没有找到右侧值的元组 -> 这将是排序后的最后一个元素
  • 所有 left 和 right 值都是唯一的,它们只是如前所述链接在一起(left1 = right2 等等)

【问题讨论】:

  • 对不起 - 忘记添加(我现在添加) - 它是一种地图,因此已经排除了可以有多个元组具有相同的左键或右键。这意味着如果传递了像您这样的列表,它将在继续排序之前引发异常。
  • 这个[(1,2), (3,4), (0,1)](缺失)和这个[(1,2), (2-4), (3,5)](划线)怎么样?
  • 类似地,这些将在排序之前被拆分,因此它们将被视为不同的列表,只有连续的部分被单独排序
  • [(0,1), (1,2), (2,3), (3,4)] 可以放置一个链表。 (node_value, next_node_value) ,从顶部开始读取(假设链已正确添加)
  • 在这种情况下,您只需要按 touple 中的“左”值排序...

标签: java sorting java-8 java-stream


【解决方案1】:

您提到元组是唯一的。因此compareTo 方法将不起作用,因为它也处理“相等”元素,这不适用于唯一列表。在当前的compareTo 代码中,元组 (1,2) 和 (3,4) 将被视为相等,这就是它不返回预期结果的原因。此外,由于父 ID 可能大于子 ID,因此您无法清楚地说 (1,2) 是大于还是小于 (3,4)。 订单可以是(1,2), (2,3), (3,4)(3,4), (4,1), (1,2)。因此,在不知道其他节点的详细信息的情况下,使用compareTo 可能无法做到这一点。

我会建议一种方法,以父 id 作为键来保留这些元组的映射,然后找到根节点并从根开始遍历:

Map<Integer, DocumentIdVersionsStack> map = list.stream()//
                .collect(Collectors.toMap(DocumentIdVersionsStack::getParentId,
                                          Function.identity()));

Set<Integer> child = list.stream()
                         .map(DocumentIdVersionsStack::getChildId)
                         .collect(Collectors.toSet());


// Get the root node
DocumentIdVersionsStack node = list.stream()
                                   .filter(u -> !child.contains(u.getParentId()))
                                   .findFirst()
                                   .orElse(null);
List<DocumentIdVersionsStack> list2 = new ArrayList<>();
list2.add(node);
// Traverse using the map
while (map.containsKey(node.getChildId())) {
    node = map.get(node.getChildId());
    list2.add(node);
}
System.out.println(list2);

【讨论】:

  • 很好,这很好用。谢谢!我终于能够通过使用递归方法来实现它,但这更简洁(而且读起来有点干净)。
猜你喜欢
  • 2021-12-27
  • 1970-01-01
  • 2020-04-24
  • 2015-06-30
  • 2012-11-07
  • 2019-07-18
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多