Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/lua/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 如何使用一组字符串筛选映射值?_Java_Dictionary_For Loop_Lambda_Set - Fatal编程技术网

Java 如何使用一组字符串筛选映射值?

Java 如何使用一组字符串筛选映射值?,java,dictionary,for-loop,lambda,set,Java,Dictionary,For Loop,Lambda,Set,我必须使用一组字符串过滤映射值,我可以让它工作,一个合作伙伴建议使用anyMatch代替我在这里所做的,但我不知道如何,我想知道你对这个算法的看法,如果有可能改进它,可以使用另一个流函数,甚至是contains方法,此外,我不确定是否可以避免直接遍历每个循环的集合 ProductsResponse serviceResponse = (obtained from backend) ...; Set<String> productIds = (some code to collect

我必须使用一组字符串过滤映射值,我可以让它工作,一个合作伙伴建议使用anyMatch代替我在这里所做的,但我不知道如何,我想知道你对这个算法的看法,如果有可能改进它,可以使用另一个流函数,甚至是contains方法,此外,我不确定是否可以避免直接遍历每个循环的集合

ProductsResponse serviceResponse = (obtained from backend) ...;
Set<String> productIds = (some code to collect the strings from another API) ...;
//Here starts the filtering process 
serviceResponse.setProducts(serviceResponse.getProducts().entrySet().stream()
          .filter(product -> {
             for (String productId: productIds) {
                if (product.getKey().startsWith(productId)) {
                    return true;
                }
             }
             return false;
           }).collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue)));

通过在集合中流动并使用anyMatch,可以避免内部for循环:

为了简洁起见,还可以使用方法参考:

serviceResponse.setProducts(serviceResponse.getProducts()
    .entrySet().stream()
    .filter(product -> productIds.stream().anyMatch(product.getKey()::startsWith))
    .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue)));

如果productID集中没有两个值a和b,其中a.startsWithb,则可以通过将该集设置为树集来极大地提高性能

或:

这将性能从On*m更改为On*logm,其中m是ProductID的大小

更新

如果productID集合中有值a和b,其中a.startsWithb,则需要一些额外的逻辑

例如,如果集合包含g和GED,并且您正在检查它是否包含GET的前缀,那么floor将返回GED,因此您必须去掉最后一个字符,并使用GE重复查找,现在返回g,以找到有效的前缀

因此,我们需要添加一个循环来重新检查:

.filter(product -> {
   String candidate = product.getKey();
   while ((candidate = productIds.floor(candidate)) != null) {
      if (product.getKey().startsWith(candidate))
         return true;
      candidate = candidate.substring(0, candidate.length() - 1);
   }
   return false;
})

这会使查找速度减慢一点,但仍然比完整的顺序搜索要好得多。

您能发布相关代码吗?值是什么类型的?对于如此有限的信息,很难提供帮助。是的,当然,我的缺点是,我想这很清楚,我会在几分钟内上传更多的代码,谢谢。只是一个说明-这仍然是一个Om*n解决方案,但至少在没有for循环的情况下看起来更好。当然,算法没有改变,谢谢@VLAZYes,只是想澄清一下。我见过一些人出于某种原因认为遍历集合是O1。我不相信这会编译。当我这样做时,我必须使用anyMatchid->product.getKey。startsWithid@WJS是的,我没有测试,这也是我的想法。我是按照你之前的方式写的,然后编辑,但我可能会回复,谢谢!我不知道地板操作的存在,听起来不错,我会尝试一下,并做一些测试,以分析您的解决方案和@Andronicus one之间的响应时间,谢谢各位。@MarcoMarchetti发现附近的和方法被大多数人完全忽略了。他们只是认为树变量是散列变量的排序版本。但是,在对SortedSet/SortedMap和NavigableSet/NavigableMap进行排序时,允许在地图中使用第一个、下一个和最后一个命名的xxxKey和xxxEntry。但这实际上只适用于自然排序。如果按降序对一组整数排序,则这些方法的行为与其名称的含义正好相反。它们仍然可以使用,但可能会令人困惑。
serviceResponse.setProducts(serviceResponse.getProducts()
    .entrySet().stream()
    .filter(product -> productIds.stream().anyMatch(product.getKey()::startsWith))
    .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue)));
TreeSet<String> productIds = (some code to collect the strings from another API) ...;
.filter(product -> {
   String id = productIds.floor(product.getKey());
   return (id != null && product.getKey().startsWith(id));
})
.filter(product -> Optional.ofNullable(productIds.floor(product.getKey()))
                   .map(product.getKey()::startsWith).orElse(false))
.filter(product -> {
   String candidate = product.getKey();
   while ((candidate = productIds.floor(candidate)) != null) {
      if (product.getKey().startsWith(candidate))
         return true;
      candidate = candidate.substring(0, candidate.length() - 1);
   }
   return false;
})