编辑问题以包括所需的行为、特定的问题或错误,以及重现问题所需的最短代码。这将帮助其他人回答这个问题。
我有以下项目清单(订单事项):
<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循环来完成这项任务,但感觉不太对劲:
我相信这就是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));
}
}
我有一种强烈的感觉,您不是在谈论Collection API中的列表,而是在谈论DOM节点。在这种情况下,您正在做不必要的工作。看
<代码>节点。normalize():
将此节点下的子树的整个深度中的所有
文本节点(包括属性节点)置于“正常”形式,其中只有结构(例如元素、注释、处理指令、CDATA节和实体引用)分隔
文本节点,即既没有相邻的
文本节点,也没有空的
文本节点。
因此,没有相邻的文本节点意味着连接以前相邻的文本节点。因此,您所要做的就是在parant节点上调用
normalize()
。
没有这样的特性可以只减少流的一部分。所有试图在流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 如有任何指导,将不胜感激。在我看来,对于持续处理新文件的应用程序来说,这是一个常见的用例--因此需要寻找最佳的方法来解决这个问题