原解决方案
让BigDecimal 的第一个列表称为decList,Integer 的第二个列表称为intList。
intList.stream().map(decList::get).collect(Collectors.toList());
这将获取第二个列表的每个值并将其用作访问第一个列表的值的索引。然后将它们收集到一个新的List<BigDecimal>。
(编辑)使用LinkedLists 检查效率
这是值得深思的,上述解决方案通常就足够了。
TLDR
LinkedLists 唯一会损害我原来的解决方案的地方是“值列表”(在这种情况下是 List 和 BigDecimals)是 LinkedList。
本次测试的原因
由于ArrayLists 上的get 是O(1),但LinkedLists 上的get 是O(N),可能会有其他更快的解决方案。
我想检查使用Iterator 的解决方案对于LinkedLists 是否会更快。我通读了各种 Javadocs,找不到运行 linkedList.stream().map(..) 是否会使用 .iterator 代替 LinkedLists 而不是调用 get。因此,我决定安排一次实际测试的时间。
测试用例
- 使用
ArrayLists 使用流和映射测试上述原始解决方案。
- 使用
LinkedLists 使用流和映射测试上述原始解决方案。
- 使用显式
.iterator 和 LinkedLists 测试解决方案。
- 使用流和映射测试上述原始解决方案,使用
ArrayList 作为索引,使用LinkedList 作为值。
- 使用流和映射测试上面的原始解决方案,使用
LinkedList 作为索引,使用LinkedList 作为值。
测试结果
ArrayList Implementation:
Duration: 70 milliseconds
Duration: 15 milliseconds
Duration: 16 milliseconds
Duration: 15 milliseconds
Duration: 15 milliseconds
Average duration: 26 milliseconds
LinkedList Implementation with Stream and Map:
Duration: 1359 milliseconds
Duration: 1387 milliseconds
Duration: 1309 milliseconds
Duration: 1302 milliseconds
Duration: 1304 milliseconds
Average duration: 1332 milliseconds
LinkedList Implementation with Iterator:
Duration: 2806 milliseconds
Duration: 2173 milliseconds
Duration: 1305 milliseconds
Duration: 1305 milliseconds
Duration: 1305 milliseconds
Average duration: 1778 milliseconds
Mix test case #4:
Duration: 1281 milliseconds
Duration: 1278 milliseconds
Duration: 1278 milliseconds
Duration: 1278 milliseconds
Duration: 1278 milliseconds
Average duration: 1278 milliseconds
Mix test case #5:
Duration: 13 milliseconds
Duration: 7 milliseconds
Duration: 7 milliseconds
Duration: 7 milliseconds
Duration: 7 milliseconds
Average duration: 8 milliseconds
结论
-
ArrayLists 的原始解决方案比 LinkedLists 快得多,因为 O(N) 与 O(N^2)。
- 似乎
streams 已经使用iterators,或类似的增强功能来解决get 效率差异。从测试用例 2 和 3 之间的相似性可以看出这一点。
-
LinkedLists 仅在它们包含此算法中的值时才会影响效率,这是由于流的迭代器优化。请注意测试用例 #5 与仅使用 ArrayLists 一样快,尽管它如何使用 LinkedList 作为索引。
效率测试来源
import java.util.List;
import java.util.ArrayList;
import java.util.LinkedList;
import java.math.BigDecimal;
import java.util.stream.Collectors;
import java.lang.Math;
import java.util.Iterator;
class Test {
public static void main(String[] args) {
testArrayListImplementation();
testLinkedListImplementation();
testCaseFourMixed();
testCaseFiveMixed();
}
static void testArrayListImplementation() {
List<BigDecimal> bigDecList = new ArrayList<BigDecimal>();
List<Integer> ndxList = new ArrayList<Integer>();
System.out.println("ArrayList Implementation:");
timeListImplementation(bigDecList, ndxList, false);
}
static void testLinkedListImplementation() {
List<BigDecimal> bigDecList = new LinkedList<BigDecimal>();
List<Integer> ndxList = new LinkedList<Integer>();
System.out.println("LinkedList Implementation with Stream and Map:");
timeListImplementation(bigDecList, ndxList, false);
System.out.println("LinkedList Implementation with Iterator:");
timeListImplementation(bigDecList, ndxList, true);
}
static void testCaseFourMixed() {
//Test case 4
List<BigDecimal> bigDecList = new LinkedList<BigDecimal>();
List<Integer> ndxList = new ArrayList<Integer>();
System.out.println("Mix test case #4:");
timeListImplementation(bigDecList, ndxList, false);
}
static void testCaseFiveMixed() {
//Test case 5
List<BigDecimal> bigDecList = new ArrayList<BigDecimal>();
List<Integer> ndxList = new LinkedList<Integer>();
System.out.println("Mix test case #5:");
timeListImplementation(bigDecList, ndxList, false);
}
static void timeListImplementation(List<BigDecimal> bigDecList, List<Integer> ndxList, boolean useIterator) {
for (int i = 0; i < 10000; i++) {
bigDecList.add(new BigDecimal(123.4));
ndxList.add((int) (Math.random() * 1000));
}
long totalDuration = 0;
for (int linkedTrial = 0; linkedTrial < 5; linkedTrial++) {
long startTime = System.nanoTime();
for (int numComputations = 0; numComputations < 100; numComputations++) {
if (useIterator) {
Iterator<Integer> ndxIter = ndxList.iterator();
List<BigDecimal> specializedList = new LinkedList<BigDecimal>();
while (ndxIter.hasNext()) {
specializedList.add(bigDecList.get(ndxIter.next()));
}
} else {
List<BigDecimal> specializedList = ndxList.stream().map(bigDecList::get).collect(Collectors.toList());
}
}
long endTime = System.nanoTime();
long duration = (endTime - startTime) / 1000000; //milliseconds
System.out.println("Duration: " + duration + " milliseconds");
totalDuration += duration;
}
System.out.println("Average duration: " + (totalDuration / 5) + " milliseconds");
}
}