[英]Java 8 Streams filter Strings by length
我可以使用流來檢查,哪兩個連續的字符串具有最大的長度總和?
例如,我有5個有效的用戶名,我應該只打印Johnny
和Frank
:
String line = "James Jack Johnny Frank Bob";
String regexForValidUserName = "[a-zA-Z][a-zA-Z0-9_]{2,24}";
Pattern patternForUserName = Pattern.compile(regexForValidUserName);
Matcher matcherForUserName = patternForUserName.matcher(line);
List<String> listOfUsers = new LinkedList<>();
if (matcherForUserName.find()) {
listOfUsers.add(matcherForUserName.group());
}
listOfUsers.stream().map((a,b,c,d) -> a.length + b.length > c.length + d.length).foreach(System.out::println);
這是一個基於流的解決方案。 我不確定我是否會在for循環中使用它,但它可以用流做你想要的,並且相對容易理解。
正如我在評論中所說,訣竅是擁有一對名稱流,而不是名稱流。
List<String> userNames = Arrays.asList("James", "Jack", "Johnny", "Frank", "Bob");
List<String> longestPair =
IntStream.range(0, userNames.size() - 1)
.mapToObj(i -> Arrays.asList(userNames.get(i), userNames.get(i + 1)))
.max(Comparator.comparing(pair -> pair.get(0).length() + pair.get(1).length()))
.orElseThrow(() -> new IllegalStateException("the list should have at least 2 elements"));
System.out.println("longestPair = " + longestPair);
請不要使用LinkedList,因為對鏈表的隨機訪問效率非常低。 但是你幾乎不應該使用鏈表。 首選ArrayList。 對於基本上所有真實的用例,它更有效。
您還可以創建一個Pair類,使其更具可讀性,而不是使用兩個元素的列表。
要完成這項工作,您必須將原始List<String>
分解為List<Pair>
塊,然后工作非常簡單。 和chunk2
一樣懶惰 ,就像流中間操作一樣 。 例如:
Comparator<List<String>> length = comparing(pair -> {
return pair.get(0).length() + pair.get(1).length();
});
List<String> longest = chunk2(asList(line.split(" "))).max(length).get();
// ^--- ["Johnny", "Frank"]
import java.util.Spliterators.AbstractSpliterator;
import static java.util.stream.StreamSupport.stream;
import static java.util.Spliterator.*;
<T> Stream<List<T>> chunk2(List<T> list) {
int characteristics = ORDERED & SIZED & IMMUTABLE ;
int size = list.size() - 1;
return stream(new AbstractSpliterator<List<T>>(size, characteristics) {
private int pos;
@Override
public boolean tryAdvance(Consumer<? super List<T>> action) {
if (pos >= size) return false;
action.accept(list.subList(pos, ++pos + 1));
return true;
}
}, false);
}
支持任意流的這種操作(即,沒有允許通過索引進行流式傳輸的隨機訪問源),需要一個自定義收集器:
String line = "James Jack Johnny Frank Bob";
String regexForValidUserName = "[a-zA-Z][a-zA-Z0-9_]{2,24}";
Pattern patternForUserName = Pattern.compile(regexForValidUserName);
Matcher matcherForUserName = patternForUserName.matcher(line);
Stream.Builder<String> builder = Stream.builder();
while(matcherForUserName.find()) builder.add(matcherForUserName.group());
class State {
String first, last, pair1, pair2;
int currLength=-1;
void add(String next) {
if(first==null) first=next;
else {
int nextLength=last.length()+next.length();
if(nextLength>currLength) {
pair1=last;
pair2=next;
currLength=nextLength;
}
}
last=next;
}
void merge(State next) {
add(next.first);
if(currLength<next.currLength) {
pair1=next.pair1;
pair2=next.pair2;
currLength=next.currLength;
}
last=next.last;
}
String[] pair() {
return currLength>=0? new String[]{ pair1, pair2 }: null;
}
}
String[] str = builder.build()
.collect(State::new, State::add, State::merge).pair();
System.out.println(Arrays.toString(str));
收集器可以具有可變數據結構,該結構允許保持狀態,如前一個元素。 為了支持合並兩個這樣的狀態對象,它還需要跟蹤第一個元素,因為一個State
對象的最后一個元素可以與下一個State
對象的第一個元素形成一對(如果有的話)。
因此,當收集器支持並行處理時,循環將更容易編程,只有當您擁有非常多的元素時才會得到回報。
如果我們已經擁有Java 9的工廠方法,那么流創建本身會更直接:
String line = "James Jack Johnny Frank Bob";
String regexForValidUserName = "[a-zA-Z][a-zA-Z0-9_]{2,24}";
Pattern patternForUserName = Pattern.compile(regexForValidUserName);
String[] str = patternForUserName.matcher(line).results()
.map(MatchResult::group)
.collect(State::new, State::add, State::merge).pair();
System.out.println(Arrays.toString(str));
( State
級不會改變)
您可以使用.forEach
迭代流,使用自定義可變數據結構來跟蹤最長的對,例如:
class Tracker {
List<String> pairs = Collections.emptyList();
String prev = "";
int longest = 0;
public void check(String name) {
int length = prev.length() + name.length();
if (length > longest) {
longest = length;
pairs = Arrays.asList(prev, name);
}
prev = name;
}
public List<String> pairs() {
return pairs;
}
}
String line = "James Jack Johnny Frank Bob";
Tracker tracker = new Tracker();
Stream.of(line.split(" ")).forEach(tracker::check);
System.out.println(tracker.pairs());
這將打印[Johnny, Frank]
。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.