我無法使用 Java Streams 撰寫以下條件。假設我有一個元素周期表中的元素串列。我必須撰寫一個方法,通過檢查串列是否包含硅或鐳或兩者來回傳字串。如果它只有硅,方法必須回傳Silicon。如果它只有鐳,方法必須回傳Radium。如果兩者都有,方法必須回傳Both。如果它們都不可用,則方法回傳""(默認值)。
目前,我撰寫的代碼如下。
String resolve(List<Element> elements) {
AtomicReference<String> value = new AtomicReference<>("");
elements.stream()
.map(Element::getName)
.forEach(name -> {
if (name.equalsIgnoreCase("RADIUM")) {
if (value.get().equals("")) {
value.set("RADIUM");
} else {
value.set("BOTH");
}
} else if (name.equalsIgnoreCase("SILICON")) {
if (value.get().equals("")) {
value.set("SILICON");
} else {
value.set("BOTH");
}
}
});
return value.get();
}
我知道代碼看起來更混亂,看起來比功能更重要。但我不知道如何使用流以更好的方式撰寫它。我還考慮過多次瀏覽串列以過濾元素Silicon并Radium在此基礎上最終確定的可能性。但是通過串列兩次似乎效率不高。
注意:我也明白這可以用命令的方式撰寫,而不是與流和原子變數復雜化。我只想知道如何使用流撰寫相同的邏輯。
請分享您對使用 Java Streams 實作相同目標的更好方法的建議。
uj5u.com熱心網友回復:
它可以在單個陳述句中使用Stream IPA完成,并且無需多行 lambda、嵌套條件和不純函式來更改 lambda 之外的狀態。
我的方法是引入一個列舉,其中元素對應于所有可能的結果,其常數EMPTY為 , SILICON, RADIUM, BOTH。
除了空字串之外的所有回傳值都可以通過呼叫name()從java.lang.Enum. 而且只是為了用空字串來解決這個問題,我添加了getName()方法。
請注意,由于Java 16列舉可以在方法內本地宣告。
流管道的邏輯如下:
- 流元素變成字串流;
- 被過濾并轉換成列舉常量流;
- 減少列舉成員;
- 列舉的可選項變成了字串的可選項。
實作可能如下所示:
public static String resolve(List<Element> elements) {
return elements.stream()
.map(Element::getName)
.map(String::toUpperCase)
.filter(str -> str.equals("SILICON") || str.equals("RADIUM"))
.map(Elements::valueOf)
.reduce((result, next) -> result == Elements.BOTH || result != next ? Elements.BOTH : next)
.map(Elements::getName)
.orElse("");
}
列舉
enum Elements {EMPTY, SILICON, RADIUM, BOTH;
String getName() {
return this == EMPTY ? "" : name(); // note name() declared in the java.lang.Enum as final and can't be overridden
}
}
主要的
public static void main(String[] args) {
System.out.println(resolve(List.of(new Element("Silicon"), new Element("Lithium"))));
System.out.println(resolve(List.of(new Element("Silicon"), new Element("Radium"))));
System.out.println(resolve(List.of(new Element("Ferrum"), new Element("Oxygen"), new Element("Aurum")))
.isEmpty() " - no target elements"); // output is an empty string
}
輸出
SILICON
BOTH
true - no target elements
筆記:
- 盡管使用流,您可以在O(n)時間迭代方法中生成結果,但可能更適合此任務。這樣想:如果串列中有一個
10.000元素串列,并且它以"SILICON"and開頭"RADIUM"。您可以輕松地打破回圈并回傳"BOTH"。 - 根據檔案,必須避免流中的有狀態操作,還要了解為什么javadoc對有狀態流發出警告,您可以看看這個問題。如果你想玩
AtomicReference它完全沒問題,請記住,這種方法不被認為是好的做法。
我想如果我用流實作了這樣的方法,整體邏輯將與上面相同,但不使用enum。由于只需要一個物件,它是一個歸約,所以我將應用于reduce()字串流,將所有條件的歸約邏輯提取到一個單獨的方法中。通常,lambdas必須是易讀的 one-liners。
uj5u.com熱心網友回復:
將字串收集到一個獨特的集合中。然后在恒定時間內檢查收容。
Set<String> names = elements.stream().map(Element::getName).map(String::toLowerCase).collect(toSet());
boolean hasSilicon = names.contains("silicon");
boolean hasRadium = names.contains("radium");
String result = "";
if (hasSilicon && hasRadium) {
result = "BOTH";
} else if (hasSilicon) {
result = "SILICON";
} else if (hasRadium) {
result = "RADIUM";
}
return result;
uj5u.com熱心網友回復:
我在過濾器中使用謂詞來表示鐳和硅,并使用結果集列印結果。
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;
public class Test {
public static void main(String[] args) {
List<Element> elementss = new ArrayList<>();
Set<String> stringSet = elementss.stream().map(e -> e.getName())
.filter(string -> (string.equals("Radium") || string.equals("Silicon")))
.collect(Collectors.toSet());
if(stringSet.size()==2){
System.out.println("both");
}else if(stringSet.size()==1){
System.out.println(stringSet);
}else{
System.out.println(" ");
}
}
}
uj5u.com熱心網友回復:
如果您使用正則運算式,您可以節省幾行,但我懷疑它是否比其他答案更好:
String resolve(List<Element> elements) {
String result = elements.stream()
.map(Element::getName)
.map(String::toUpperCase)
.filter(str -> str.matches("RADIUM|SILICON"))
.sorted()
.collect(Collectors.joining());
return result.matches("RADIUMSILICON") ? "BOTH" : result;
}
轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/440297.html
上一篇:我不明白代碼是如何變成56、49
