Java 如何在比赛后使用流查找项目?

Java 如何在比赛后使用流查找项目?,java,regex,lambda,Java,Regex,Lambda,使用Java streams,很容易找到与给定属性匹配的元素。 例如: String b = Stream.of("a1","b2","c3") .filter(s -> s.matches("b.*")) .findFirst().get(); System.out.println("b = " + b); 生产: b=b2 然而,人们通常希望在匹配后立即获得一个或多个值,而不是匹配本身。我只知道如何使用旧的循环方式来实现这一点 String args[

使用Java streams,很容易找到与给定属性匹配的元素。
例如:

 String b = Stream.of("a1","b2","c3")
     .filter(s -> s.matches("b.*"))
     .findFirst().get();
 System.out.println("b = " + b);
生产:
b=b2

然而,人们通常希望在匹配后立即获得一个或多个值,而不是匹配本身。我只知道如何使用旧的循环方式来实现这一点

    String args[] = {"-a","1","-b","2","-c","3"};
    String result = "";
    for (int i = 0; i < args.length-1; i++) {
        String arg = args[i];
        if(arg.matches("-b.*")) {
            result= args[i+1];
            break;
        }
    }
    System.out.println("result = " + result);
String args[]={“-a”、“1”、“b”、“2”、“c”、“3”};
字符串结果=”;
for(int i=0;i
将产生:
结果=2

有没有一种干净的方式来处理Java8流?例如,给定上面的数组,将result设置为“2”,并谓词
s->s.matches(“-b.*)


如果您可以获取下一个值,那么在匹配另一个谓词之前,也可以获取下一个N值或所有值的列表/数组,例如
s->s.matches(“-c.*”)

对于在使用som
Pair
Tuple
类之后直接需要值的情况

String b = Stream.of(Pair.of("-a","1"),Pair.of("-b","2"),Pair.of("-c","3"))
    .filter(p -> p.first.matches("-b.*"))
    .map(p -> p.second)
    .findFirst().get();

我不能说下面的方法是有效的,但它遵循了一种易于应用的模式。(不过,在真正的函数式语言中,在添加过滤器时,这可能是有效的。)

首先从字符串流中收集
[[-c,3],-b,2],-a,1]]

    List<List<String>> optionLists = Stream.of("-a","1","-b","2","-c","3")
            .collect(ArrayList<List<String>>::new,
                    (lists, arg) -> {
                        if (arg.startsWith("-")) {
                            List<String> list = new LinkedList<>();
                            list.add(arg);
                            lists.add(0, list);
                        } else {
                            List<String> list = lists.get(0);
                            list.add(arg);
                        }
                    },
                    List::addAll);
    System.out.println(optionLists);
List optionlist=Stream.of(“-a”、“1”、“b”、“2”、“c”、“3”)
.collect(数组列表::新建,
(列表,arg)->{
if(参数开始时带(“-”)){
列表=新建LinkedList();
列表。添加(arg);
列表。添加(0,列表);
}否则{
List=lists.get(0);
列表。添加(arg);
}
},
列表::addAll);
System.out.println(选项列表);
然后你可以把它放在所有选项的地图上

List bargs=optionList.stream()
.collect(收集器.toMap(lst->lst.get)(0),
lst->lst.subList(1,lst.size()).get(“-b”);
System.out.println(“For-b:+bargs”);

我通过这篇博文找到了它:

名为jOOL的库有一个Github链接

和Maven central信息:

该示例的代码为:

import org.jooq.lambda.Seq;


据我所知,似乎没有一种简单的方法可以做到这一点,其中的很多原因都源于Java的Stream API缺乏获取流元素索引的功能以及将流压缩在一起的能力

如果我们能够获得流中某个元素的索引,然后简单地使用.skip()函数和.limit(n)函数组合使用来丢弃包含所需匹配点的元素,然后将结果限制到接下来的n个元素,那么我们可以想象一个简单的问题解决方案

您可能想查看Protonpack,它是一个“针对Java 8的Streams实用程序库,提供takeWhile、skipWhile、zip和unfold”。使用此库,解决此问题的简单方法可能如下所示:

Stream<String> stringStream = Stream.of("-a","1","-b","2","-c","3");
Stream<String> nAfterMatch = 
    StreamUtils.skipWhile(stringStream, s -> !(s.matches("-b.*")))
    .limit(n);
Stream-stringStream=Stream.of(“-a”、“1”、“b”、“2”、“c”、“3”);
流nAfterMatch=
StreamUtils.skipWhile(stringStream,s->!(s.matches(“-b.*)))
.限制(n);

这是一种使用流解决此问题所需的拆分器:

import java.util.ArrayList;
import java.util.List;
import java.util.Spliterator;
import java.util.Spliterators.AbstractSpliterator;
import java.util.function.Consumer;
import java.util.stream.Stream;
import java.util.stream.StreamSupport;

public class PartitioningSpliterator<E> extends AbstractSpliterator<List<E>>
{
  private final Spliterator<E> spliterator;
  private final int partitionSize;

  public PartitioningSpliterator(Spliterator<E> toWrap, int partitionSize) {
    super(toWrap.estimateSize(), toWrap.characteristics());
    if (partitionSize <= 0) throw new IllegalArgumentException(
        "Partition size must be positive, but was " + partitionSize);
    this.spliterator = toWrap;
    this.partitionSize = partitionSize;
  }

  public static <E> Stream<List<E>> partition(Stream<E> in, int size) {
    return StreamSupport.stream(new PartitioningSpliterator(in.spliterator(), size), false);
  }

  @Override public boolean tryAdvance(Consumer<? super List<E>> action) {
    final HoldingConsumer<E> holder = new HoldingConsumer<>();
    if (!spliterator.tryAdvance(holder)) return false;
    final ArrayList<E> partition = new ArrayList<>(partitionSize);
    int j = 0;
    do partition.add(holder.value); while (++j < partitionSize && spliterator.tryAdvance(holder));
    action.accept(partition);
    return true;
  }

  @Override public long estimateSize() {
    final long est = spliterator.estimateSize();
    return est == Long.MAX_VALUE? est
         : est / partitionSize + (est % partitionSize > 0? 1 : 0);
  }

  static final class HoldingConsumer<T> implements Consumer<T> {
    T value;
    @Override public void accept(T value) { this.value = value; }
  }
}
作为补充,本文介绍的拆分器通过依赖
AbstractSpliterator

中的
trySplit
的默认实现来支持并行性这可能是一种变通解决方案:

String[] args = {"-a","1","-b","2","-c","3"};

String b = IntStream.range(1, args.length)
   .mapToObj(i -> new Pair<>(args[i-1], args[i]))
   .filter(pp -> pp.getFirst().startsWith("-b"))
   .findFirst().get().getSecond();

System.out.println("b = " + b);
//=> Output: b = 2
String[]args={“-a”、“1”、“b”、“2”、“c”、“3”};
字符串b=IntStream.range(1,args.length)
.mapToObj(i->新对(args[i-1],args[i]))
.filter(pp->pp.getFirst().startsWith(“-b”))
.findFirst().get().getSecond();
System.out.println(“b=“+b”);
//=>输出:b=2

.mapToObj
用于使用输入数组
args
中的连续索引从
args
数组中生成字符串值对

多亏了Java Streams
takeWhile
才有可能:

Stream<String> strings = Stream.of("a1","b2","c3");
final AtomicBoolean matchFound = new AtomicBoolean(false);
final AtomicReference<String> stringAfterMatch = new AtomicReference<>();
strings.takeWhile(string -> stringAfterMatch.get() == null).forEach(string -> {
  if (matchFound.get()) {
      stringAfterMatch.set(string);
  }
  if (string.matches("b.*")) {
    matchFound.set(true);
  }
});
String b = stringAfterMatch.get();
Stream strings=Stream.of(“a1”、“b2”、“c3”);
final AtomicBoolean matchFound=新的AtomicBoolean(false);
final AtomicReference stringAfterMatch=新的AtomicReference();
string.takeWhile(string->stringAfterMatch.get()==null).forEach(string->{
if(matchfind.get()){
stringAfterMatch.set(字符串);
}
if(string.matches(“b.*)){
matchFound.set(true);
}
});
字符串b=stringAfterMatch.get();
私有静态布尔值(字符串输入,字符串[]字){
Arrays.stream(words).allMatch(新谓词(){
@凌驾
公共布尔测试(字符串t){
if(输入包含(t))
计数器+=1;//添加全局计数器
//ExtensionUtils.keyWordHash.put(t,input);//或者您可以将字符串放入hashmap并稍后检索
返回输入。包含(t);
}
});
返回Arrays.stream(words).allMatch(input::contains);
}

我认为答案是否定的。我有理由相信,任何使用流的解决方案都会非常复杂,可读性也会受到影响。流是一个非常通用的工具,但你知道这样一句话:“当你有锤子时,一切看起来都像钉子”。但事实上,并不是所有的东西都是钉子。如果streams支持
分区
操作(我使用Clojure的命名),这将很容易做到。这将允许您将其重新组织为一个成对的流。在拆分器级别有一种方法可以做到这一点(我有代码),但对于您的情况来说可能不值得。您正在寻找的是一个“转换”双工流,它会发出自己的输出
partition(Stream.of("-a","1","-b","2","-c","3"), 2)
      .filter(pair -> pair.get(0).equals("-b"))
      .findFirst()
      .map(pair -> pair.get(1))
      .orElse("");
String[] args = {"-a","1","-b","2","-c","3"};

String b = IntStream.range(1, args.length)
   .mapToObj(i -> new Pair<>(args[i-1], args[i]))
   .filter(pp -> pp.getFirst().startsWith("-b"))
   .findFirst().get().getSecond();

System.out.println("b = " + b);
//=> Output: b = 2
Stream<String> strings = Stream.of("a1","b2","c3");
final AtomicBoolean matchFound = new AtomicBoolean(false);
final AtomicReference<String> stringAfterMatch = new AtomicReference<>();
strings.takeWhile(string -> stringAfterMatch.get() == null).forEach(string -> {
  if (matchFound.get()) {
      stringAfterMatch.set(string);
  }
  if (string.matches("b.*")) {
    matchFound.set(true);
  }
});
String b = stringAfterMatch.get();
private static boolean containsWords(String input, String[] words) {
        
        Arrays.stream(words).allMatch(new Predicate<String>() {

            @Override
            public boolean test(String t) {
                if(input.contains(t))
                    counter+=1; //add  a global counter
                //ExtensionUtils.keyWordHash.put(t, input); // or you can put the strings to a hashmap and retrieve later
                return input.contains(t);
            }
        });
        return Arrays.stream(words).allMatch(input::contains);
    }