- mongodb - 在 MongoDB mapreduce 中,如何展平值对象?
- javascript - 对象传播与 Object.assign
- html - 输入类型 ="submit"Vs 按钮标签它们可以互换吗?
- sql - 使用 MongoDB 而不是 MS SQL Server 的优缺点
需要一些帮助,从我的 StackOverflow 杰出人物那里思考 lambda。
从一个列表中挑选一个列表的标准案例来收集图表深处的一些 child 。 Lambdas
有哪些很棒的方法可以帮助处理这个样板文件?
public List<ContextInfo> list() {
final List<ContextInfo> list = new ArrayList<ContextInfo>();
final StandardServer server = getServer();
for (final Service service : server.findServices()) {
if (service.getContainer() instanceof Engine) {
final Engine engine = (Engine) service.getContainer();
for (final Container possibleHost : engine.findChildren()) {
if (possibleHost instanceof Host) {
final Host host = (Host) possibleHost;
for (final Container possibleContext : host.findChildren()) {
if (possibleContext instanceof Context) {
final Context context = (Context) possibleContext;
// copy to another object -- not the important part
final ContextInfo info = new ContextInfo(context.getPath());
info.setThisPart(context.getThisPart());
info.setNotImportant(context.getNotImportant());
list.add(info);
}
}
}
}
}
}
return list;
}
请注意,列表本身会以 JSON
的形式发送给客户端,因此不要关注返回的内容。一定是一些我可以减少循环的巧妙方法。
有兴趣看看我的专家同事创造了什么。鼓励采用多种方法。
编辑
findServices
和两个 findChildren
方法返回数组
编辑 - 奖励挑战
“不重要的部分”确实很重要。我实际上需要复制一个仅在 host
实例中可用的值。这似乎毁掉了所有美丽的例子。如何将国家发扬光大?
final ContextInfo info = new ContextInfo(context.getPath());
info.setHostname(host.getName()); // The Bonus Challenge
最佳答案
它的嵌套相当深,但似乎并不特别困难。
第一个观察结果是,如果 for 循环转换为流,则可以使用 flatMap
将嵌套的 for 循环“扁平化”为单个流。 .此操作采用单个元素并在流中返回任意数量的元素。我查了一下,发现StandardServer.findServices()
返回 Service
的数组所以我们用 Arrays.stream()
把它变成一个流. (我对 Engine.findChildren()
和 Host.findChildren()
做了类似的假设。
接下来,每个循环中的逻辑执行 instanceof
检查和类型转换。这可以使用流建模为 filter
操作做instanceof
后跟 map
简单地转换并返回相同引用的操作。这实际上是一个空操作,但它允许静态类型系统转换 Stream<Container>
到 Stream<Host>
例如。
将这些转换应用于嵌套循环,我们得到以下结果:
public List<ContextInfo> list() {
final List<ContextInfo> list = new ArrayList<ContextInfo>();
final StandardServer server = getServer();
Arrays.stream(server.findServices())
.filter(service -> service.getContainer() instanceof Engine)
.map(service -> (Engine)service.getContainer())
.flatMap(engine -> Arrays.stream(engine.findChildren()))
.filter(possibleHost -> possibleHost instanceof Host)
.map(possibleHost -> (Host)possibleHost)
.flatMap(host -> Arrays.stream(host.findChildren()))
.filter(possibleContext -> possibleContext instanceof Context)
.map(possibleContext -> (Context)possibleContext)
.forEach(context -> {
// copy to another object -- not the important part
final ContextInfo info = new ContextInfo(context.getPath());
info.setThisPart(context.getThisPart());
info.setNotImportant(context.getNotImportant());
list.add(info);
});
return list;
}
但是等等,还有更多。
final forEach
操作稍微复杂一些map
转换 Context
的操作变成 ContextInfo
.此外,这些只是收集到 List
因此我们可以使用收集器来执行此操作,而不是先创建和清空列表,然后再填充它。应用这些重构会产生以下结果:
public List<ContextInfo> list() {
final StandardServer server = getServer();
return Arrays.stream(server.findServices())
.filter(service -> service.getContainer() instanceof Engine)
.map(service -> (Engine)service.getContainer())
.flatMap(engine -> Arrays.stream(engine.findChildren()))
.filter(possibleHost -> possibleHost instanceof Host)
.map(possibleHost -> (Host)possibleHost)
.flatMap(host -> Arrays.stream(host.findChildren()))
.filter(possibleContext -> possibleContext instanceof Context)
.map(possibleContext -> (Context)possibleContext)
.map(context -> {
// copy to another object -- not the important part
final ContextInfo info = new ContextInfo(context.getPath());
info.setThisPart(context.getThisPart());
info.setNotImportant(context.getNotImportant());
return info;
})
.collect(Collectors.toList());
}
我通常会尽量避免使用多行 lambda(例如在最终的 map
操作中),所以我会将它重构为一个小辅助方法,该方法采用 Context
并返回 ContextInfo
.这根本不会缩短代码,但我认为它确实使它更清晰。
更新
但是等等,还有更多。
让我们提取对 service.getContainer()
的调用进入它自己的管道元素:
return Arrays.stream(server.findServices())
.map(service -> service.getContainer())
.filter(container -> container instanceof Engine)
.map(container -> (Engine)container)
.flatMap(engine -> Arrays.stream(engine.findChildren()))
// ...
这暴露了 instanceof
上的重复过滤。然后是带有类型转换的映射。总共进行了 3 次。似乎其他代码可能需要做类似的事情,所以最好将这部分逻辑提取到辅助方法中。问题是 filter
可以更改流中元素的数量(删除不匹配的元素),但不能更改它们的类型。和map
可以改变元素的类型,但不能改变它们的数量。可以改变数量和类型吗?是的,是我们的老 friend flatMap
再次!所以我们的辅助方法需要获取一个元素并返回一个不同类型的元素流。该返回流将包含单个转换元素(如果它匹配)或者它将是空的(如果它不匹配)。辅助函数如下所示:
<T,U> Stream<U> toType(T t, Class<U> clazz) {
if (clazz.isInstance(t)) {
return Stream.of(clazz.cast(t));
} else {
return Stream.empty();
}
}
(这大致基于一些评论中提到的 C# 的 OfType
构造。)
在此过程中,让我们提取一个方法来创建 ContextInfo
:
ContextInfo makeContextInfo(Context context) {
// copy to another object -- not the important part
final ContextInfo info = new ContextInfo(context.getPath());
info.setThisPart(context.getThisPart());
info.setNotImportant(context.getNotImportant());
return info;
}
在这些提取之后,管道如下所示:
return Arrays.stream(server.findServices())
.map(service -> service.getContainer())
.flatMap(container -> toType(container, Engine.class))
.flatMap(engine -> Arrays.stream(engine.findChildren()))
.flatMap(possibleHost -> toType(possibleHost, Host.class))
.flatMap(host -> Arrays.stream(host.findChildren()))
.flatMap(possibleContext -> toType(possibleContext, Context.class))
.map(this::makeContextInfo)
.collect(Collectors.toList());
更好,我认为,我们已经删除了可怕的多行语句 lambda。
更新:奖励挑战
再一次,flatMap
是你的 friend 。取流的尾部并将其迁移到最后一个 flatMap
在尾部之前。那样 host
变量仍在范围内,您可以将其传递给 makeContextInfo
已修改为采用 host
的辅助方法也是。
return Arrays.stream(server.findServices())
.map(service -> service.getContainer())
.flatMap(container -> toType(container, Engine.class))
.flatMap(engine -> Arrays.stream(engine.findChildren()))
.flatMap(possibleHost -> toType(possibleHost, Host.class))
.flatMap(host -> Arrays.stream(host.findChildren())
.flatMap(possibleContext -> toType(possibleContext, Context.class))
.map(ctx -> makeContextInfo(ctx, host)))
.collect(Collectors.toList());
关于java - Lambdas,多个 forEach 带强制转换,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/25439277/
我一直很难编辑我的 .htaccess 文件来一起做这三件事。我已经能够分别获得每个部分,但我只是不明白逻辑流程如何使它们全部工作。 这是我能够使用 bluehost support 上的演示进行整合
我制作的宏将模板工作簿保存为两个单独的文件。每个测试保存一个(位置 1、2、3 或 4),然后在另一个宏中使用每个测试的数据。第二个是保留用于备份的原始数据文件。现在的问题是每次我在每个位置运行测试并
我正在写一篇关于如何使用 OCaml 的模块系统而不是 Java 的 OO 系统(一个有趣的视角)的博客文章。我遇到了一些我不理解的关于强制的事情。下面是一个基本模块和两个包含它的模块: module
我有一段将被执行多次(5,000+)的代码,以及一个仅在第一次为真的 if 语句。我曾想过使用“FIRST”变量并每次都进行比较,但每次都检查它似乎是一种浪费,即使我知道它不需要。 bool FIRS
首先,我是 Perforce 的新手,我主要通过其文档进行学习。 因此,我们即将从 CVS 迁移到 Perforce,我最近学到了一个避免更改每个工作区的 P4CLIENT 的好方法,即在工作区根目录
我正在为一段代码编写测试,其中包含我试图涵盖的 IOException 捕获。 try/catch 看起来像这样: try { oos = new ObjectOutputStream(new
我正在尝试在新闻项目滚动之间添加延迟。我知道 $.each() 通过不等待动画完成来完成其工作,但我想知道如何制作它,以便一次向上滚动一个项目并等到最后一个动画完成后再继续在循环中。 $(functi
假设已经编写了一个方法,需要一个排序列表作为其输入之一。当然这将在代码中进行注释和记录,param 将被命名为“sortedList”,但如果有人忘记,则会出现错误。 有没有办法强制输入必须排序?我正
我正在尝试将传入请求重定向到 https://www.domain.com/和所有 https://www.domain.com/ {所有页面}并且没有什么麻烦。我试过的方法: 添加此行:Redire
我将如何实现以下内容: title_selection = raw_input("Please type in the number of your title and press Enter.\n%
我有一个登录表单,我需要强制关闭自动完成功能。我试过了 jquery: $('#login').attr("autocomplete", "off"); HTML: Javascript:docume
我想知道我应该怎么做才能强制从 dev 分支 merge 到我的 master 分支?使用“git merge dev”会导致很多冲突。但是,我不想单独处理它们。相反,我只是想使用我的 dev 分支中
当安装 Hl7.Fhir.DSTU2 和 Hl7.Fhir.R4 这两个 Nuget 包时,我们得到如下信息: DSTU2 包似乎在使用 Hl7.Fhir.Support.Poco 版本 3.4.0
我正在尝试让一个功能组件在 testFn 执行时强制重新渲染。我想使用状态来做到这一点(如果有更好的方法请说出来),这似乎成功地强制重新渲染但只有两次,然后什么都没有。 我构建了一个简单的演示来模拟这
默认情况下,g++ 似乎会省略未使用的类内定义方法的代码。示例 from my previous question : struct Foo { void bar() {} void baz(
我正在尝试使用 here 中介绍的技术使我的网站背景以比内容慢的速度滚动。我不希望背景固定,只希望更慢。 这是 HTML 的样子: .parallax { perspective: 1px;
我能找到的最相似的问题是 'how to create a row of scrollable text boxes or widgets in flutter inside a ListView?'
我有以下 eslint 配置: "object-curly-newline": ["error", { "ImportDeclaration": "never",
我正在使用 TinyMCE 插件并将 valid_elements 选项设置为: "a[href|target:_blank],strong/b,em/i,br,p,ul,ol,li" 即使没有列出数
您好,我想使用以下命令放置多行描述 p4 --field Description="MY CLN Header \\n my CLN complete description in two -thre
我是一名优秀的程序员,十分优秀!