我正在尝试使用Java 8中的Streams API从集合中检索n个唯一的随机元素以进行进一步处理,但是没有太多或任何运气.
更准确地说,我想要这样的东西:
Set<Integer> subList = new HashSet<>();
Queue<Integer> collection = new PriorityQueue<>();
collection.addAll(Arrays.asList(1,2,3,4,5,6,7,8,9));
Random random = new Random();
int n = 4;
while (subList.size() < n) {
subList.add(collection.get(random.nextInt()));
}
sublist.forEach(v -> v.doSomethingFancy());
Run Code Online (Sandbox Code Playgroud)
我想尽可能高效地做到这一点.
可以这样做吗?
编辑:我的第二次尝试 - 虽然不是我的目标:
List<Integer> sublist = new ArrayList<>(collection);
Collections.shuffle(sublist);
sublist.stream().limit(n).forEach(v -> v.doSomethingFancy());
Run Code Online (Sandbox Code Playgroud)
编辑:第三次尝试(灵感来自Holger),如果coll.size()很大且n很小,这将消除大量的shuffle开销:
int n = // unique element count
List<Integer> sublist = new ArrayList<>(collection);
Random r = new Random();
for(int i = 0; i < n; i++)
Collections.swap(sublist, i, i + …Run Code Online (Sandbox Code Playgroud) 要重构的功能......
<T> T notUsedRandomItem(List<T> allItems, List<T> usedItems) {
return allItems.stream()
.filter(item -> !usedItems.contains(item))
.sorted((o1, o2) -> new Random().nextInt(2) - 1)
.findFirst()
.orElseThrow(() -> new RuntimeException("Did not find item!"));
}
Run Code Online (Sandbox Code Playgroud)
功能可能会像这样使用......
System.out.println(
notUsedRandomItem(
Arrays.asList(1, 2, 3, 4),
Arrays.asList(1, 2)
)
); // Should print either 3 or 4
Run Code Online (Sandbox Code Playgroud)
编辑:通过针对人员列表运行它们来收集建议的实现和测试效率.
edit2:为Person类添加了缺少的equals方法.
import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.function.BiFunction;
import java.util.stream.Collectors;
import java.util.stream.IntStream;
import static java.util.stream.Collectors.toList;
class Functions {
<T> T notUsedRandomItemOriginal(List<T> allItems, List<T> usedItems) {
return allItems.stream()
.filter(item -> !usedItems.contains(item))
.sorted((o1, o2) -> …Run Code Online (Sandbox Code Playgroud)