gpt4 book ai didi

java - 如何从一组对象生成组合?

转载 作者:行者123 更新时间:2023-12-04 15:38:23 25 4
gpt4 key购买 nike

我需要得到所有可能的 7 个对象集中 5 个对象的组合 .不重复的组合(选择的顺序无关紧要,即以不同的顺序选择的相同对象被视为相同的组合)。

我有实现,它工作正常并产生正确的结果:

String[] vegetablesSet = {"Pepper", "Cabbage", "Tomato", "Carrot", "Beans", "Cucumber", "Peas"};
final int SALAD_COMBINATION_SIZE = 5; // Example: {"Tomato", "Cabbage", "Cucumber", "Pepper", "Carrot"}

Set<Set<String>> allSaladCombinations = new HashSet<>();
for (int i = 1, max = 1 << vegetablesSet.length; i < max; i++) {
Set<String> set = new HashSet<>();
int count = 0;
for (int j = 0, k = 1; j < vegetablesSet.length; j++, k <<= 1) {
if ((k & i) != 0) {
set.add(vegetablesSet[j]);
count++;
}
}
if (count == SALAD_COMBINATION_SIZE) {
allSaladCombinations.add(set);
}
}

for (Set<String> set : allSaladCombinations) {
for (String vegatable : set) {
System.out.print(vegatable + " ");
}
System.out.println();
}

输出正确:已找到 21 个正确的组合。

但它使用按位运算符,在我的评估中,它的可读性、可维护性和可扩展性不是很好。我想将其重构或完全重写为更灵活和更易于理解的面向对象方法。我对如何做到这一点非常感兴趣 使用 OOP 和递归 .

我没有在我的项目中使用 Google Guava , Apache CommonsCombinatoricsLib .而且我不想只为一种方法包含整个第三方库。我在网站上搜索类似的问题,但只找到了很好的清晰排列实现: https://stackoverflow.com/a/14486955

这些情况有一些相似的含义,但对象的顺序对我来说并不重要,在我的情况下,它们被认为是相同的组合,不应计算。

最佳答案

你可以试试这个代码:

    public static void main(String[] args) {
String[] vegetablesSet = { "Pepper", "Cabbage", "Tomato", "Carrot", "Beans", "Cucumber", "Peas" };
Set<Set<String>> result = new HashSet<>();
combinations(vegetablesSet, new ArrayList<>(), result, 5, 0);
result.forEach(System.out::println);
}

public static void combinations(String[] values, List<String> current, Set<Set<String>> accumulator, int size, int pos) {
if (current.size() == size) {
Set<String> toAdd = current.stream().collect(Collectors.toSet());
if (accumulator.contains(toAdd)) {
throw new RuntimeException("Duplicated value " + current);
}
accumulator.add(toAdd);
return;
}
for (int i = pos; i <= values.length - size + current.size(); i++) {
current.add(values[i]);
combinations(values, current, accumulator, size, i + 1);
current.remove(current.size() - 1);
}
}

基本思想是仅从当前位置开始使用元素并使用递归来混合不同的选项。

如果你想要一个更简单的方法调用,你可以像这样创建一个包装器方法:
    public static Set<Set<String>> combinations(String[] values) {
Set<Set<String>> result = new HashSet<>();
combinations(values, new ArrayList<>(), result, SALAD_COMBINATION_SIZE, 0);
return result;
}

编辑:
另一种方法是使 1 和 0(在这种情况下为 5 个 1 和 2 个零)的不同排列来创建掩码,然后将在组合中进行转换。我觉得它比之前的解决方案更自然,因为它不使用循环,除了掩码应用程序(隐含在流操作中):
    public static void combinations2(String[] values, String current, Set<Set<String>> accumulator, int ones, int zeroes) {
if (ones + zeroes == 0) {
accumulator.add(IntStream.range(0, values.length)
.filter(position -> '1' == current.charAt(position))
.mapToObj(position -> values[position])
.collect(Collectors.toSet()));
return;
}
if (ones > 0) {
combinations2(values, current + "1", accumulator, ones - 1, zeroes);
}
if (zeroes > 0) {
combinations2(values, current + "0", accumulator, ones, zeroes - 1);
}
}

包装方法:
public static Set<Set<String>> combinations(String[] values) {
Set<Set<String>> result = new HashSet<>();
combinations2(values, "", result, SALAD_COMBINATION_SIZE, values.length - SALAD_COMBINATION_SIZE);
return result;
}

关于java - 如何从一组对象生成组合?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/59351266/

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