当前位置: 首页 > 知识库问答 >
问题:

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

柳杰
2023-03-14

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

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

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和递归实现这一点非常感兴趣。

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

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

共有1个答案

崔棋
2023-03-14

你可以试试这个代码:

    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;
    }
 类似资料:
  • 我有一个对象数组,如下所示: 我想把它添加到一个退出的对象中,其中id是该对象的一个键,如下所示:

  • 问题内容: 我的arraylist包含String数组对象。我如何获得所有价值?我的代码如下 如果我尝试像上面给出的那样进行检索, 怎么做? 问题答案: 您还必须遍历字符串数组。

  • 首先,我对反应式编程有点陌生。在参加了一些关于reactor和spring 5.0的演讲后,我想自己尝试一下这个编程模型。 我有一个应用程序,它使用WebClient从不同的API构建两个Flux对象。我想将这2个对象组合成一个并将其返回给用户。 代码示例如下所示: 现在在我的handler方法中: 我应该使用反应器API中的什么方法来实现这一点?我找到了一些方法来组合像组合最新的对象,但是在这种

  • 我使用以下类型生成Web服务响应类: 它生成一个具有保护长删除的类; 但是我想生成一个数组。添加minOccurs="0"maxOccurs="unbed"会生成List。 请帮忙。

  • 问题内容: 我想从numpy中的2D数组创建“心率监视器”效果,并希望音调能够反映数组中的值。 问题答案: 您可以使用from函数来创建一个wav文件,然后您可以根据需要播放该文件。请注意,数组必须是整数,因此,如果您有浮点数,则可能需要适当地缩放它们: 如果您希望Python实际播放音频,则此页面概述了某些软件包/模块。

  • 问题内容: 这个问题是我先前的问题的后续。我需要检索复杂类的列表。 我需要找到一个特定组的学生列表,这些学生位于特定的位置,其电话号码位于其地址中。我还需要显示每个学生到特定坐标的距离。 下面的代码工作正常,唯一的问题是我无法检索对象列表,例如电子邮件列表,组列表和每个学生的电话列表。 问题答案: hibernate的默认类不会传输嵌套对象,如果您遇到性能问题,应尝试以下代码。 看看这个链接和这一