假设我有一个流
天真的做法是只做以下几件事:
Stream.of(...)
.sorted()
.distinct()
或者,也许反过来:
Stream.of(...)
.distinct()
.sorted()
由于JDK的源代码并不能真正访问这两种方法的实现,我只是想知道可能的内存消耗和性能影响。
或者将我自己的过滤器编写为以下内容会更有效吗?
Stream.of(...)
.sorted()
.filter(noAdjacentDuplicatesFilter())
public static Predicate<Object> noAdjacentDuplicatesFilter() {
final Object[] previousValue = {new Object()};
return value -> {
final boolean takeValue = !Objects.equals(previousValue[0], value);
previousValue[0] = value;
return takeValue;
};
}
免责声明:我知道性能测试很难,尤其是在需要热身的JVM和没有其他进程运行的受控环境中。
如果我测试它,我会得到这些结果,因此您的实现似乎有利于并行执行。(在i7上运行4核超线程)。
所以“.distinct().sorted()
”似乎要慢一些。正如霍尔格所预测/解释的那样
Round 1 (Warm up?)
3938
2449
5747
Round 2
2834
2620
3984
Round 3 Parallel
831
4343
6346
Round 4 Parallel
825
3309
6339
使用代码:
package test.test;
import java.util.Collections;
import java.util.List;
import java.util.Objects;
import java.util.function.Predicate;
import java.util.stream.Collectors;
import java.util.stream.IntStream;
public class SortDistinctTest {
public static void main(String[] args) {
IntStream range = IntStream.range(0, 6_000_000);
List<Integer> collect = range.boxed().collect(Collectors.toList());
Collections.shuffle(collect);
long start = System.currentTimeMillis();
System.out.println("Round 1 (Warm up?)");
collect.stream().sorted().filter(noAdjacentDuplicatesFilter()).collect(Collectors.counting());
long fst = System.currentTimeMillis();
System.out.println(fst - start);
collect.stream().sorted().distinct().collect(Collectors.counting());
long snd = System.currentTimeMillis();
System.out.println(snd - fst);
collect.stream().distinct().sorted().collect(Collectors.counting());
long end = System.currentTimeMillis();
System.out.println(end - snd);
System.out.println("Round 2");
collect.stream().sorted().filter(noAdjacentDuplicatesFilter()).collect(Collectors.counting());
fst = System.currentTimeMillis();
System.out.println(fst - end);
collect.stream().sorted().distinct().collect(Collectors.counting());
snd = System.currentTimeMillis();
System.out.println(snd - fst);
collect.stream().distinct().sorted().collect(Collectors.counting());
end = System.currentTimeMillis();
System.out.println(end - snd);
System.out.println("Round 3 Parallel");
collect.stream().parallel().sorted().filter(noAdjacentDuplicatesFilter()).collect(Collectors.counting());
fst = System.currentTimeMillis();
System.out.println(fst - end);
collect.stream().parallel().sorted().distinct().collect(Collectors.counting());
snd = System.currentTimeMillis();
System.out.println(snd - fst);
collect.stream().parallel().distinct().sorted().collect(Collectors.counting());
end = System.currentTimeMillis();
System.out.println(end - snd);
System.out.println("Round 4 Parallel");
collect.stream().parallel().sorted().filter(noAdjacentDuplicatesFilter()).collect(Collectors.counting());
fst = System.currentTimeMillis();
System.out.println(fst - end);
collect.stream().parallel().sorted().distinct().collect(Collectors.counting());
snd = System.currentTimeMillis();
System.out.println(snd - fst);
collect.stream().parallel().distinct().sorted().collect(Collectors.counting());
end = System.currentTimeMillis();
System.out.println(end - snd);
}
public static Predicate<Object> noAdjacentDuplicatesFilter() {
final Object[] previousValue = { new Object() };
return value -> {
final boolean takeValue = !Objects.equals(previousValue[0], value);
previousValue[0] = value;
return takeValue;
};
}
}
当您在sorted()
之后链接一个明显()
操作时,实现将利用数据的排序性质并避免构建内部HashSet
,这可以由以下程序演示
public class DistinctAndSort {
static int COMPARE, EQUALS, HASHCODE;
static class Tracker implements Comparable<Tracker> {
static int SERIAL;
int id;
Tracker() {
id=SERIAL++/2;
}
public int compareTo(Tracker o) {
COMPARE++;
return Integer.compare(id, o.id);
}
public int hashCode() {
HASHCODE++;
return id;
}
public boolean equals(Object obj) {
EQUALS++;
return super.equals(obj);
}
}
public static void main(String[] args) {
System.out.println("adjacent sorted() and distinct()");
Stream.generate(Tracker::new).limit(100)
.sorted().distinct()
.forEachOrdered(o -> {});
System.out.printf("compareTo: %d, EQUALS: %d, HASHCODE: %d%n",
COMPARE, EQUALS, HASHCODE);
COMPARE=EQUALS=HASHCODE=0;
System.out.println("now with intermediate operation");
Stream.generate(Tracker::new).limit(100)
.sorted().map(x -> x).distinct()
.forEachOrdered(o -> {});
System.out.printf("compareTo: %d, EQUALS: %d, HASHCODE: %d%n",
COMPARE, EQUALS, HASHCODE);
}
}
哪个会打印
adjacent sorted() and distinct()
compareTo: 99, EQUALS: 99, HASHCODE: 0
now with intermediate operation
compareTo: 99, EQUALS: 100, HASHCODE: 200
中间操作,就像map(x-
不能保证会发生这种优化,但是,可以合理地假设Stream实现的开发人员不会删除该优化,甚至不会尝试添加更多优化,因此滚动您自己的实现将阻止您的代码受益从未来的优化。
此外,您所创建的是一个“有状态谓词”,强烈反对使用它,当然,当与并行流一起使用时,它会中断。
如果您不相信流API能够足够有效地执行此操作,那么最好在没有流API的情况下实现此特定操作。
我最近开始学习PySpark的大数据分析。我有以下问题,并试图找到一个更好的方法来实现这一点。我会带你解决下面的问题。 给定下面的pyspark数据框: 我想按列进行分组——Col1、Col2、Col3,并在每个组中按日期时间降序排序 然后,从每个排序的组中选出最上面的一行(即DateTime中最新的一行) 最后,透视Col3值并使用“值” 我该如何以一种有效的方式,以较小的步骤实现这一目标?提前
我试图查询具有分区键和排序键的表(但是分区键和排序键是1:1,我只想使用分区键[仅返回一项]进行查询)。 这是我尝试过的代码,但没有成功(testId是分区键名,1234567890是字符串形式的分区键值);你们都知道我可以只使用分区键进行查询的方法吗?记住,由于分区键和排序键是1:1,所以只会返回一个项?提前非常感谢您。[这是我的第一篇堆栈溢出帖子-很抱歉,如果我用词不当,我很乐意回答关于我的措
问题内容: 考虑数据框 使用按列定义的组,我想按预期进行排序。但是,我想将这些行保留在原处。 问题答案: 您可以用来取回新的所需索引顺序,然后用于重新排列DataFrame: 如果需要,可以将上面的两行合并为一条长行。 结果输出: 请注意,如果您不关心维护旧索引,则可以直接从中重新分配: 产生:
我想在RESTful API中支持分页。 我的API方法应该通过返回产品的JSON列表http://localhost/products/v1/getproductsbycategory,可能有数千种产品,我想翻阅它们,因此我的请求应该如下所示:
问题内容: 假设我们在集合中有一些项目,并且我们想使用某些比较器对它们进行排序,并期望结果在列表中: 一种方法是对列表中的项目进行排序,例如: Anothe方法正在使用排序流: 我想知道哪种方法更有效?排序流是否有任何优势(例如在多核上进行Faste排序)? 在运行时复杂性方面/最快方面是高效的。 我不相信自己要实现一个完美的基准,学习并不能真正启发我。 问题答案: 可以肯定地说,两种形式的排序都
我正在使用Elasticsearch ch6.8,我在响应中得到了一个文档列表。一些文档具有相同的分数,但它们在响应列表中以相同的顺序出现。我想知道算法ES使用什么来对具有相同分数的文档进行排序?