我可以使用流来检查哪两个连续字符串的长度最大?
例如,我有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);
答案 0 :(得分:2)
这是基于流的解决方案。我不确定我是否会在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类,使其更具可读性,而不是使用两个元素的列表。
答案 1 :(得分:1)
要完成这项工作,您必须将原始的List<String>
分解为List<Pair>
块,然后才能轻松完成工作。而chunk2
懒惰就像流intermediate operations一样。例如:
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);
}
答案 2 :(得分:1)
支持任意流的这种操作(即,没有允许通过索引进行流式传输的随机访问源),需要一个自定义收集器:
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’s factory method:
,则流创建本身会更直截了当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
类不会改变)
答案 3 :(得分:0)
您可以使用.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]
。