当前位置: 首页 > 知识库问答 >
问题:

是否有用于复杂列表处理的Java API?[已关闭]

李锦
2023-03-14

编辑问题以包括所需的行为、特定的问题或错误,以及重现问题所需的最短代码。这将帮助其他人回答这个问题。

我有以下项目清单(订单事项):

<A> <B> [ ] [\n] <C> [  ] [   ] [\n\r] <D> <A> [ ] [ xyz ] [ abc ] <X>

我想合并方括号表示的文本节点:

<A> <B> [ \n] <C> [     \n\r] <D> <A> [  xyz  abc ] <X>

我编写了一个带有标志和prevNode指针的for-each循环来完成这项任务,但感觉不太对劲:

  • 对于一项可以在10秒钟内口头表达的任务来说,这太费劲了
  • 如果没有注释,理解代码将需要一些脑力劳动和时间

我相信这就是Java 8流API的意义所在:编写代码的工作量越少,读取代码的工作量越小。

Java中是否有类似的机制来处理列表?

使现代化

由于没有现成的解决方案,我开发了一个非常简单的fluent API来解决这个任务。还原现在看起来就像这样:

List<Node> output = ListStream.of(input)
                .continuousRegion(node -> node instanceof TextNode)
                .reduceRegion((a, b) -> new TextNode(a.value + b.value))
                .toArrayList();

它完美地解决了许多任务,您只需对列表中的连续区域进行操作。我有很多这样的例子,为进一步的数据处理准备XML。

算法

public List<Node> reduce(List<Node> list) {
        List<Node> result = new ArrayList<>();

        TextNode prevTextNode = null;
        for (Node node : list) {
            if (node instanceof TextNode) {
                TextNode textNode = (TextNode) node;

                if (prevTextNode == null) {
                    prevTextNode = textNode;
                } else {
                    prevTextNode = new TextNode(prevTextNode.value + textNode.value);
                }
            } else {
                if (prevTextNode != null) {
                    result.add(prevTextNode);
                    prevTextNode = null;
                }

                result.add(node);
            }
        }

        if (prevTextNode != null) {
            result.add(prevTextNode);
        }

        return result;
    }

所有代码(可编译):

import com.sun.deploy.util.StringUtils;
import org.junit.Test;

import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;

import static org.junit.Assert.assertEquals;

public class ListReductionExample {
    class Node {
        final String value;

        Node(String value) {
            this.value = value;
        }

        @Override
        public String toString() {
            return "<" + value + ">";
        }

        @Override
        public boolean equals(Object o) {
            if (this == o) return true;
            if (!(o instanceof Node)) return false;

            Node node = (Node) o;

            return value != null ? value.equals(node.value) : node.value == null;
        }

        @Override
        public int hashCode() {
            return value != null ? value.hashCode() : 0;
        }
    }

    class TextNode extends Node {
        TextNode(String value) {
            super(value);
        }

        @Override
        public String toString() {
            return "[" + value + "]";
        }

    }

    public List<Node> reduce(List<Node> list) {
        List<Node> result = new ArrayList<>();

        TextNode prevTextNode = null;
        for (Node node : list) {
            if (node instanceof TextNode) {
                TextNode textNode = (TextNode) node;

                if (prevTextNode == null) {
                    prevTextNode = textNode;
                } else {
                    prevTextNode = new TextNode(prevTextNode.value + textNode.value);
                }
            } else {
                if (prevTextNode != null) {
                    result.add(prevTextNode);
                    prevTextNode = null;
                }

                result.add(node);
            }
        }

        if (prevTextNode != null) {
            result.add(prevTextNode);
        }

        return result;
    }

    public void printList(List<Node> list) {
        List<String> listOfStrings = list.stream().map(Node::toString).collect(Collectors.toList());

        System.out.println(StringUtils.join(listOfStrings, " "));
    }

    @Test
    public void test() {
        // <A> <B> [ ] [N] <C> [  ] [   ] [NR] <D> <A> [ ] [ xyz ] [ abc ] <X>
        List<Node> input = new ArrayList<>();
        input.add(new Node("A"));
        input.add(new Node("B"));
        input.add(new TextNode(" "));
        input.add(new TextNode("N"));
        input.add(new Node("C"));
        input.add(new TextNode("  "));
        input.add(new TextNode("   "));
        input.add(new TextNode("NR"));
        input.add(new Node("D"));
        input.add(new Node("A"));
        input.add(new TextNode(" "));
        input.add(new TextNode(" xyz "));
        input.add(new TextNode(" abc "));
        input.add(new Node("X"));

        printList(input);

        // <A> <B> [ N] <C> [     NR] <D> <A> [  xyz  abc ] <X>
        List<Node> expectedOutput = new ArrayList<>();
        expectedOutput.add(new Node("A"));
        expectedOutput.add(new Node("B"));
        expectedOutput.add(new TextNode(" N"));
        expectedOutput.add(new Node("C"));
        expectedOutput.add(new TextNode("     NR"));
        expectedOutput.add(new Node("D"));
        expectedOutput.add(new Node("A"));
        expectedOutput.add(new TextNode("  xyz  abc "));
        expectedOutput.add(new Node("X"));

        printList(expectedOutput);

        assertEquals(expectedOutput, reduce(input));
    }
}

共有2个答案

岑炯
2023-03-14

我有一种强烈的感觉,您不是在谈论Collection API中的列表,而是在谈论DOM节点。在这种情况下,您正在做不必要的工作。看

<代码>节点。normalize():

将此节点下的子树的整个深度中的所有文本节点(包括属性节点)置于“正常”形式,其中只有结构(例如元素、注释、处理指令、CDATA节和实体引用)分隔文本节点,即既没有相邻的文本节点,也没有空的文本节点。

因此,没有相邻的文本节点意味着连接以前相邻的文本节点。因此,您所要做的就是在parant节点上调用normalize()

滕星纬
2023-03-14

没有这样的特性可以只减少流的一部分。所有试图在流API上构建此类功能的解决方案都比循环复杂得多。要改进循环变量,可以做的是去掉null值和相关的条件。一般逻辑如下:

public static <T> List<T> joinElements(
                          List<T> list, BiPredicate<T,T> p, BinaryOperator<T> join) {

    if(list.isEmpty()) return Collections.emptyList();
    T element=list.get(0);
    int num=list.size();
    if(num==1) return Collections.singletonList(element);
    List<T> result=new ArrayList<>(num);
    for(int ix=1; ix<num; ix++) {
        T next=list.get(ix);
        if(p.test(element, next)) {
            element=join.apply(element, next);
        }
        else {
            result.add(element);
            element=next;
        }
    }
    result.add(element);
    return result;
}

如果怀疑调用方提供了非随机访问列表(程序员应该避免),可以使用

public static <T> List<T> joinElements(
                          List<T> list, BiPredicate<T,T> p, BinaryOperator<T> join) {

    Iterator<T> it=list.iterator();
    if(!it.hasNext()) return Collections.emptyList();
    T element=it.next();
    if(!it.hasNext()) return Collections.singletonList(element);
    List<T> result=new ArrayList<>();
    do {
        T next=it.next();
        if(p.test(element, next)) {
            element=join.apply(element, next);
        }
        else {
            result.add(element);
            element=next;
        }
    } while(it.hasNext());
    result.add(element);
    return result;
}

这可以像这样使用

List<String> result = joinElements(list,
    (a,b) -> isTextNode(a) && isTextNode(b), (a,b) -> new TextNode(a.value+b.value));

相比之下,基于Stream的解决方案可以使用Collector。由于此类任务没有内置的收集器,我们必须定义一个,它基本上与基于循环的解决方案相同,功能仅分布在多个函数上,由执行迭代的Stream评估:

List<String> result=list.stream().collect(ArrayList::new,
    (l,n) -> l.add(!l.isEmpty() && isTextNode(l.get(l.size()-1)) && isTextNode(n)?
                new TextNode(l.remove(l.size()-1).value+n.value): n),
    (l1,l2) -> {
        if(!l2.isEmpty() && !l1.isEmpty()
           && isTextNode(l1.get(l1.size()-1)) && isTextNode(l2.get(0))) {
                l2.set(0, new TextNode(l1.remove(l1.size()-1).value+l2.get(0).value));
        }
        l1.addAll(l2);
    });

决定这是否是对循环变体的改进...

 类似资料:
  • 我刚刚介绍了GCM云连接服务器的新功能。在客户端,使用google play服务似乎相当容易,如中所述https://developer.android.com/google/gcm/ccs.html然而,对于服务器端,它说: GCM云连接服务器(CCS)是一个XMPPendpoint,运行在http://gcm.googleapis.com5235端口。 CCS需要安全传输层协议(TLS)连接。

  • 我正在使用spring-mvc和Thymeleaf开发一个内部工具。 这个工具的一部分用于创建我们保存在数据库中的实体。这个实体相当复杂;它包含许多性质和关系。其中一些关系包含列表和其他属性。 我有两个限制: null 使用Thymeleaf呈现基本页面。使用JavaScript创建html元素,而不是提交到@ModelAttribute,我将表单序列化到JSON并将此JSON提交到服务器。(客户

  • 我有一个离散事件流进入我的系统,我需要根据每个事件的内容应用规则。另外,我想对这些流事件应用复杂的事件处理。 约束1.这些规则是用户提供的,并将动态更改。2.每当应用规则时,我不想重新启动我的系统。3.HA 4.只有成熟的开源解决方案 可能的方式...1.在Storm螺栓内运行Esper CEP 2。让口水流到Storm螺栓里 > 这会处理单事件规则和复杂事件吗?规则更改是否需要我的Storm重新

  • 我的设计是为了维护一个系统,它考虑到三个变量的值,以确定它将采取的行动。 我想重构它以使用一个设计模式,但找不到一个适合它的需要。 为了解释这种情况,我将使用一个健身房系统作为例子。 每个健身房用户都有一个合同类型,可以是: null null 无限制 过_65 限制移动性 Medical_Condition 低于_18 对于这三个特征的每个组合,都应该执行一组任意的操作。例如: 如果PLATIN

  • 我有一个flink cep代码,可以从套接字读取数据并检测模式。假设模式(单词)为“警报”。如果单词alert出现五次或五次以上,则应创建一个警报。但我得到了一个输入不匹配错误。Flink版本为1.3.0。提前谢谢!!

  • 我正在寻找解决应用程序中存在的一个问题的设计方法的指导。 我们在Java应用程序中安排了作业,并且使用了Quartz调度器。我们的应用程序可以有数千个作业,这些作业执行以下操作: 扫描文件夹位置以查找任何新文件。 如果有新文件,则启动关联的工作流以处理该文件。 null 如有任何指导,将不胜感激。在我看来,对于持续处理新文件的应用程序来说,这是一个常见的用例--因此需要寻找最佳的方法来解决这个问题