如何在Java中实现列表折叠
我有一个列表,想将其减少为单个值(函数式编程术语“fold”,Ruby 术语inject
),就像
Arrays.asList("a", "b", "c") ... fold ... "a,b,c"
我感染了函数式编程思想(Scala)一样,我正在寻找比它更简单/更短的编码方式
sb = new StringBuilder
for ... {
append ...
}
sb.toString
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(14)
您正在寻找的是一个字符串“join”函数,不幸的是,Java 没有这个函数。 您将必须推出自己的联接功能,这应该不会太难。
编辑: org.apache.commons.lang.StringUtils 似乎有很多有用的字符串函数(包括 join)。
What you are looking for is a string "join" function which, unfortunately, Java does not have. You will have to roll your own join function which shouldn't be too hard.
Edit: org.apache.commons.lang.StringUtils seems to have many useful string functions (including join).
Eclipse Collections 有
injectInto
(如 Ruby 和 Smalltalk),makeString
和appendString
。 以下内容将适用于您的示例:注意:我是 Eclipse Collections 的提交者。
Eclipse Collections has
injectInto
(like Ruby and Smalltalk),makeString
andappendString
. The following will work with your example:Note: I am a committer for Eclipse Collections.
不幸的是,在 Java 中你无法逃脱这个循环,但是有几个库。 您可以尝试几个库:
unfortunately in Java you can't escape that loop, there are several libraries however. E.g. you can try several libraries:
首先,您需要一个 Java 函数库,它提供通用函子和函数投影(如折叠)。 我在这里设计并实现了一个功能强大(凭借)但简单的库: http: //www.codeproject.com/KB/java/FunctionalJava.aspx(我发现提到的其他库过于复杂)。
那么你的解决方案将如下所示:
请注意,通过应用折叠,真正需要考虑的唯一部分是 Func2.call 的实现,这 3 行代码定义了一个接受累加器和一个元素并返回累加器的运算符(我的实现考虑了空字符串和空值,如果删除这种情况,那么它就会减少到 2 行代码)。
下面是 Seq.foldl 的实际实现,Seq 实现了 Iterable:
First you'll need a functional library for Java which supplies generic functors and functional projections like fold. I've designed and implemented a powerful (by virtue) yet simple such library here: http://www.codeproject.com/KB/java/FunctionalJava.aspx (I found the other libraries mentioned overly complicated).
Then your solution would look like:
Note that by applying fold, the only part that really needs to be thought out is the implementation for Func2.call, 3 lines of code which define an operator accepting the accumulator and an element and returning the accumulator (my implementation accounts for empty strings and nulls, if you remove that case then it's down to 2 lines of code).
And here's the actual implementation of Seq.foldl, Seq implements Iterable<E>:
Java 8 风格(函数式):
Java 8 style (functional):
不幸的是,Java 不是一种函数式编程语言,并且没有一个好的方法来完成您想要的事情。
我相信 Apache Commons lib 有一个 名为 join 的函数 可以完成您想要的操作。
它必须足够好才能隐藏方法中的循环。
我想你可以递归地做到这一点:
Unfortunately Java is not a functional programming language and does not have a good way to do what you want.
I believe the Apache Commons lib has a function called join that will do what you want though.
It will have to be good enough to hide the loop in a method.
I suppose you could do it recursively:
现在您可以在 Java 8 中使用
String.join()
。Now you can use
String.join()
with Java 8.在 lambda 的支持下,我们可以使用以下代码:
With the support of lambdas we could do with the following code:
下面是折叠列表的代码,通过保留后面的节点信息并在前进时折叠。
Below is the code to fold the list, by keeping back the information of the nodes let behind and folding as we move forward.
没有这样的函数,但您可以创建如下所示的函数,并在需要时调用它。
There is no such a function, but you could create something like the following, and invoke it whenever you need to.
回答你原来的问题:
F 看起来像这样:
正如 dfa 建议的那样, Functional Java 已经实现了这个,和更多。
示例 1:
示例 2:
示例 3:
To answer your original question:
Where F looks like this:
As dfa suggested, Functional Java has this implemented, and more.
Example 1:
Example 2:
Example 3:
鉴于
然后用法看起来就像
Given
Then usage just looks like
如果您想将某些功能方面应用于普通的旧式 Java,而不切换语言尽管您可以 LamdaJ,分叉连接 (166y) 和 google-collections 是帮助您添加语法糖的库。
借助 google-collections,您可以使用Joiner 类:
Joiner.on( ",")
是一个不可变的对象,因此您可以自由共享它(例如作为常量)。您还可以配置 null 处理,例如
Joiner.on(", ").useForNull("nil");
或Joiner.on(", ").skipNulls()
。为了避免在生成大字符串时分配大字符串,您可以通过 Appendable 接口或 StringBuilder 类将其附加到现有 Streams、StringBuilder 等
:编写映射时,您需要两个不同的分隔符来用于条目和键+值之间的分隔:
If you want to apply some functional aspects to plain old Java, without switching language although you could LamdaJ, fork-join (166y) and google-collections are libraries that help you to add that syntactic sugar.
With the help of google-collections you can use the Joiner class:
Joiner.on(",")
is an immutable object so you might share it freely (for example as a constant).You can also configure null handling like
Joiner.on(", ").useForNull("nil");
orJoiner.on(", ").skipNulls()
.To avoid allocating big strings while you are generating a large string, you can use it to append to existing Streams, StringBuilders, etc. through the
Appendable
interface orStringBuilder
class:When writing out maps, you need two different separators for entries and seperation between key+value:
您正在寻找的是 Java 从 8.0 开始就有的字符串
join()
方法。 尝试以下方法之一。静态方法
String#join(分隔符,元素)
:Stream 接口支持与 Scala 的
foldLeft
函数非常相似的折叠操作。 看一下下面的连接 Collector:您可能需要静态导入
Collectors.joining
以使代码更清晰。顺便说一下,这个收集器可以应用于任何特定对象的集合:
What you are looking for is a string
join()
method which Java has since 8.0. Try one of the methods below.Static method
String#join(delimiter, elements)
:Stream interface supports a fold operation very similar to Scala’s
foldLeft
function. Take a look at the following concatenating Collector:You may want to statically import
Collectors.joining
to make your code clearer.By the way this collector can be applied to collections of any particular objects: