gpt4 book ai didi

java - 是否有更优雅的方法使用 Java 8 从列表中获取随机未使用的项目?

转载 作者:塔克拉玛干 更新时间:2023-11-03 03:46:11 26 4
gpt4 key购买 nike

要重构的函数...

<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!"));
}

函数可以这样使用...

System.out.println(
notUsedRandomItem(
Arrays.asList(1, 2, 3, 4),
Arrays.asList(1, 2)
)
); // Should print either 3 or 4

编辑:收集建议的实现并通过针对人员列表运行它们来测试效率。

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) -> new Random().nextInt(2) - 1)
.findFirst()
.orElseThrow(() -> new RuntimeException("Did not find item!"));
}

<T> T notUsedRandomItemByAominè(List<T> allItems, List<T> usedItems) {
List<T> distinctItems = allItems.stream()
.filter(item -> !usedItems.contains(item))
.collect(toList());

if (distinctItems.size() == 0) throw new RuntimeException("Did not find item!");

return distinctItems.get(new Random().nextInt(distinctItems.size()));
}

<T> T notUsedRandomItemByEugene(List<T> allItems, List<T> usedItems) {

// this is only needed because your input List might not support removeAll
List<T> left = new ArrayList<>(allItems);
List<T> right = new ArrayList<>(usedItems);

left.removeAll(right);

return left.get(new Random().nextInt(left.size()));
}

<T> T notUsedRandomItemBySchaffner(List<T> allItems, List<T> usedItems) {

Set<T> used = new HashSet<>(usedItems);
List<T> all = new ArrayList<>(allItems);

Collections.shuffle(all);

for (T item : all) if (!used.contains(item)) return item;

throw new RuntimeException("Did not find item!");
}
}

public class ComparingSpeedOfNotUsedRandomItemFunctions {

public static void main(String[] plaa) {
runFunctionsWith(100);
runFunctionsWith(1000);
runFunctionsWith(10000);
runFunctionsWith(100000);
runFunctionsWith(200000);
}

static void runFunctionsWith(int itemCount) {

TestConfiguration testConfiguration = new TestConfiguration();
Functions functions = new Functions();

System.out.println("Function execution time with " + itemCount + " items...");

System.out.println("Schaffner: " +
testConfiguration.timeSpentForFindingNotUsedPeople(
itemCount, (allPeople, usedPeople) ->
functions.notUsedRandomItemBySchaffner(allPeople, usedPeople)
));

System.out.println("Eugene: " +
testConfiguration.timeSpentForFindingNotUsedPeople(
itemCount, (allPeople, usedPeople) ->
functions.notUsedRandomItemByEugene(allPeople, usedPeople)
));

System.out.println("Aominè: " +
testConfiguration.timeSpentForFindingNotUsedPeople(
itemCount, (allPeople, usedPeople) ->
functions.notUsedRandomItemByAominè(allPeople, usedPeople)
));

System.out.println("Original: " +
testConfiguration.timeSpentForFindingNotUsedPeople(
itemCount, (allPeople, usedPeople) ->
functions.notUsedRandomItemOriginal(allPeople, usedPeople)
));
}

}

class TestConfiguration {

Long timeSpentForFindingNotUsedPeople(int numberOfPeople, BiFunction<List<Person>, List<Person>, Person> function) {

ArrayList<Person> people = new ArrayList<>();
IntStream.range(1, numberOfPeople).forEach(i -> people.add(new Person()));
Collections.shuffle(people);

List<Person> halfOfPeople =
people.stream()
.limit(numberOfPeople / 2)
.collect(Collectors.toList());

Collections.shuffle(halfOfPeople);

long before = System.nanoTime();
Person foundItem = function.apply(people, halfOfPeople);
long after = System.nanoTime();

// Return -1 if function do not return valid answer
if (halfOfPeople.contains(foundItem))
return (long) -1;

return TimeUnit.MILLISECONDS.convert(after - before, TimeUnit.NANOSECONDS);
}

class Person {
public final String name = UUID.randomUUID().toString();

@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;

Person person = (Person) o;

return name != null ? name.equals(person.name) : person.name == null;
}

@Override
public int hashCode() {
return name != null ? name.hashCode() : 0;
}
}
}

结果:

Function execution time with 100 items...
Schaffner: 0
Eugene: 1
Aominè: 2
Original: 5
Function execution time with 1000 items...
Schaffner: 0
Eugene: 14
Aominè: 13
Original: 5
Function execution time with 10000 items...
Schaffner: 2
Eugene: 564
Aominè: 325
Original: 348
Function execution time with 20000 items...
Schaffner: 3
Eugene: 1461
Aominè: 1418
Original: 1433
Function execution time with 30000 items...
Schaffner: 3
Eugene: 4616
Aominè: 2832
Original: 4567
Function execution time with 40000 items...
Schaffner: 4
Eugene: 10889
Aominè: 4903
Original: 10394

结论

当列表大小达到 10000 个项目时,到目前为止只有 Schaffner 的实现可用。

而且因为它相当简单易读,所以我会选择它作为最优雅的解决方案。

最佳答案

我能想到这个,但不知道与您现有的解决方案相比它将如何扩展:

<T> T notUsedRandomItem(List<T> allItems, List<T> usedItems) {

// this is only needed because your input List might not support removeAll
List<T> left = new ArrayList<>(allItems);
List<T> right = new ArrayList<>(usedItems);

left.removeAll(right);

return left.get(new Random().nextInt(left.size()));

}

要记住的一件事是 sorted 是一个有状态 操作,因此它将对整个“diff”进行排序,但您只能从中检索一个元素。另外你的 Comparator 是错误的,对于 same 两个值 o1o2 你可能会说它们是不同的 - 这可以以神秘的方式打破。

关于java - 是否有更优雅的方法使用 Java 8 从列表中获取随机未使用的项目?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/47913583/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com