是否可以使用Java 8 Streams构建Tree数据模型

时间:2016-10-27 21:52:37

标签: tree java-8 java-stream

我正在调查Java 8流。

我目前无法尝试通过流式传输每个记录描述父子关系的文件来构建经典树结构。

我希望我的解决方案能够从输入数据记录构建一个类似于以下示例的树: -

Parent A - Child B
Parent A - Child C
Parent A - Child D
Parent A - Child E
Parent B - Child F
Parent B - Child G
Parent C - Child H
Parent D - Child I
Parent G - Child J

我想构建一个LinkedHashMap<String, List<String>>

e.g。最终

A - B, C, D, E
B - F, G
C - H
D - I
G - J

我最接近的是重复密钥

Map<String, List<String>> map = stream.sorted().map(line -> line.split("-")).flatMap(line -> Arrays.stream(line)).collect(Collectors.toMap(Function.identity(), Arrays::asList));

或使用以下Node值对象

public class Node {

    private final String name;
    private Node parent;
    private List<Node> children = new LinkedList<>();

}

构造所有树节点,并使用完全填充的子节点列表直接从流输入文件。

3 个答案:

答案 0 :(得分:3)

添加合并lambda以聚合子项:

Map<String, List<String>> map = list.stream().sorted()
        .map(line -> line.split("\\s*-\\s*"))
        .collect(toMap(a -> a[0], 
                       a -> new ArrayList<>(Arrays.asList(a[1])),
                      (a, b) -> {a.addAll(b); return a;}));

如果您的节点没有parent字段,则可以更直接地获取节点:

List<Node> nodes = ist.stream().sorted()
    .map(line -> line.split("\\s*-\\s*"))
    .collect(groupingBy(a -> a[0]))
    .entrySet()
    .stream()
    .map(e -> new Node(e.getKey()[0], e.getValue().stream()
        .map(a -> new Node(a[1], null))
        .collect(toList())))
    .collect(toList());

初始分组要简单得多,因为没有与List的对话 - 分割中的原始数组保持原样。

免责声明:代码可能无法编译或工作,因为它在我的手机上被翻阅(但它有合理的可能性)

答案 1 :(得分:3)

这是groupingBy收藏家的工作:

import static java.util.stream.Collectors.*;

Pattern ptrn = Pattern.compile("Parent (.*) - Child (.*)");

Map<String, List<String>> map = data.stream()
        .sorted()
        .map(ptrn::matcher)
        .filter(Matcher::find)
        .collect(groupingBy(
                m -> m.group(1), 
                LinkedHashMap::new ,
                mapping(m -> m.group(2), toList())
        ));

答案 2 :(得分:2)

如果您的目标是多地图,可以使用以下内容:

Map<String, Collection<String>> result = stream //stream of lines
    .sorted()
    .map(line -> line.split("\\s*-\\s*"))
    .collect(
        Collectors.toMap(
            (String[] arr) -> arr[0],
            (String[] arr) -> Collections.singleton(arr[1]),
            (u, v) -> {
                Collection<String> merged = new LinkedHashSet<>(u);
                merged.addAll(v);
                return merged;
            },
            LinkedHashMap::new
        )
    );

这里的关键是自定义地图收集器,它使用集合作为值和合并函数来处理重复键的情况,即具有多个值的键。您可以在HashMapHashSet上使用简单的LinkedHashMapLinkedHashSet,以防您不关心元素的顺序,在这种情况下,您可以删除sorted()操作也是如此。