[英]Nested Loop to Java Stream Puzzle
我是Java 8中的新手。我正在努力弄清楚如何使用流在列表上實現嵌套for循環。 一個列表包含消息,消息中的一個字段是作者的id(不幸的是obj引用)。 另一個列表是作者,作者中的一個字段是作者ID。 代碼需要在消息列表中的每個消息的作者列表中找到匹配的作者。 我有的工作Java代碼(不使用stream或lambdas)如下,我的問題是如何使用流重寫它? 我嘗試了幾件事,我認為需要一個flatMap和一個過濾器,但我似乎無法做到這一點。
public void showAuthors(List<Message> messages, List<Authors> authors) {
String authorName=null;
for (Message message : messages) {
int authorId = message.getAuthorId();
for (Authors author : authors) {
if (author.getId() == authorId)
authorName = author.getFullName();
break;
}
System.out.println("Message id is " + message.getId() +
" author is " + authorName);
}
}
我在這里看了一些類似的問題,但我似乎無法做到正確。
任何幫助表示贊賞!
=============================================
更新:作者列表具有Id字段的一些空數據。 這要求我使用帶有stream操作的過濾器來創建AuthorId,Name的映射。
由於您正在進行mxn
比較,因此最好在authorId -> author
之間創建一個Map,以避免對作者進行O(n)
查找:
Map<Integer, Author> authorMaps = authors.stream().collect(toMap(Author::getId, Function.identity()));
現在您可以獲取每條消息的作者,如下所示:
messages.stream().filter(m -> authorMaps.containsKey(m.getAuthorId()))
.forEach(m ->
System.out.println("Message id is " + m.getId() +
" author is " + authorMaps.get(m.getAuthorId()). getFullName());
);
首先,對我來說,你當前的邏輯是錯誤的。 如果第一次不滿足條件,並且您獲得前一作者的所有消息或一些無效結果,它會破壞內部循環。
Message id is 1 author is AuthOne
Message id is 2 author is AuthOne
Message id is 4 author is AuthOne
這是糾正過的。
public static void showAuthors(List<Message> messages, List<Author> authors) {
String authorName = null;
for (Message message : messages) {
int authorId = message.getAuthorId();
for (Author author : authors) {
if (author.getId() == authorId) {
authorName = author.getFullName();
break;
}
}
System.out.println("Message id is " + message.getId() + " author is " + authorName);
}
}
只有在找到第一個Author
后才能打破循環。 這是具有線性時間復雜度的等效stream
對應物。
Map<Integer, String> authorsById = authors.stream()
.collect(Collectors.toMap(Author::getId, Author::getFullName));
Map<Integer, String> authorNameAgainstId = messages.stream()
.collect(Collectors.toMap(Message::getId, m -> authorsById.get(m.getAuthorId())));
在嘗試了上面的一些建議之后,我很快意識到作者的數據有一些沒有Id的對象,只是名字(顯然它們有雙重用途......這不是我的設計!)。
所以,我根據上面答案的幫助/提示寫了以下內容:
public void showAuthors(List<Message> messages, List<Reference> authors) {
Map<Integer, String> authorsById = authors.stream()
.filter(author -> !(author.getId() == null))
.filter(name -> !(name.getFullName() == null))
.collect(Collectors.toMap(Reference::getId, Reference::getFullName));
messages.forEach(
message -> System.out.println("Message id is " + message.getId() +
" Author is " + authorsById.get(message.getSenderId())));
這個解決方案有什么問題嗎?
另外,我是stackoverflow的新手(我相信你可以告訴我)...有沒有辦法可以給所有3個響應者一些幫助? 這是什么上升的意思?
梅格
你不需要用於消息處理的流,這里forEach更合適。 然而,流對於作者列表來映射轉換很有用。
您可以使用帶有3個參數的toMap來避免作者列表中可能的作者重復(原始代碼避免了這一點)。
您可以使用Optional來避免可能缺少authos,null id等。每次.map返回null,Optional變為Optional :: Empty,因此對它的進一步處理被跳過到終端操作,ifPresence只是跳過空選項。
Map<Integer, String> authorNames=authors.stream()
.collect(Collectors.toMap(
Author::getId,
Author::getFullName,
(oldValue, newValue) -> oldValue));
messages.forEach(
m -> Optional.of(m)
.map(Message::getAuthorId)
.map(authorNames::get)
.map(name -> "Message id is " + m.getId() + " author is " + name)
.ifPresent(System.out::println)
);
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.