【问题标题】:How to get the combination of elements from the list as shown如何从列表中获取元素的组合,如图所示
【发布时间】:2015-07-29 00:28:04
【问题描述】:

我有一个List<int[]> 作为index_position:int[] values

input:

index 0:{1,2} 
index 1:{1,3,5} 
index 2:{2}

无论是否使用 Lambda,我如何在 Java 中获得以下组合。

第一步:找出所有这样的组合

[{1,1,2}, {1,3,2}, {1,5,2}, {2,1,2}, {2,3,2}, {2,5,2}]

-> 

Step2:从已获得的组合中删除重复项

[{1,2}, {1,3,2}, {1,5,2}, {2,1}, {2,3}, {2,5}]

“想要在每个步骤中执行,例如从 n 个数组生成所有 n 个元素子集 >其中第一个元素来自第一个数组,第二个来自第二个数组...,>从每个结果子集中删除重复项。”

不需要进一步减少

[{1,2}, {1,2}] 

[{1,2}] 

[{1,2},{2,1}] 

[{1,2}] / [{2,1}]

但在我的情况下也不会影响结果。

【问题讨论】:

  • 这不是 Java 语法意义上的 List 对象。您能否发布创建此列表的代码或至少描述此列表的结构?
  • 并描述你所谓的“减少”的规则。我不知道第二个列表与第一个列表有什么关系!
  • edit您的帖子并更正您的示例。有时相同的输出可能是不同操作的结果。因此,我们宁愿不假设您正在尝试做什么,所以您应该准确地在每个步骤中执行您想要执行的操作,例如 generate all n element subset from n 个数组,其中第一个元素来自第一个数组,第二个来自第二个数组...从每个结果子集中删除重复项。您是否还想删除重复的子集,例如 {1,2} {1,2},或者甚至是 {1,2} {2,1}
  • 您的每个步骤都应该成为单独的问题(可能已经在 SO 上提出过问题,所以现在尝试搜索资源)。无论如何,我们仍然不知道非常重要的信息,即:您的阵列数量总是 3 还是可以有更多?根据这些信息,我们可以选择是否可以简单地使用三个循环(或内部流)来完成,或者我们是否需要一些递归解决方案。
  • 我们可以假设每个int[] 都包含唯一的数字吗?换句话说index 0:可以是{1,1,2}吗?

标签: java arrays lambda functional-programming


【解决方案1】:

您要问的似乎是 N 组的笛卡尔积 (Set1 x Set2 x ... x SetN)。

不幸的是,Java 中没有标准方法可以让我们轻松构建一个,但在 Guava 及其Sets.cartesianProduct 方法的帮助下,这项任务似乎很容易。

唯一的条件是我们需要提供List<Set<..>>作为它的参数。
因为这个答案是基于假设 每个 int[] 都可以被视为集合,这意味着它的值必须是唯一的。实际上更准确地说,如果index 0 将是{1,2,1}{1,2,2},它将被处理为设置{1,2}

这是List<Set<Integer>> 的示例,其中包含您当前的数据
toList 是静态导入的Collections.toList() 方法,类似toSet):

//part 0: preparing data
List<Set<Integer>> sets = new ArrayList<>(
            Arrays.asList(
                new HashSet<>(Arrays.asList(1, 2)), 
                new HashSet<>(Arrays.asList(1, 3, 5)),
                new HashSet<>(Arrays.asList(2))
            )
        );
sets.forEach(System.out::println);
System.out.println("-----------------");

//part 1: calculating cartesian products
Set<List<Integer>> cartesianProducts = Sets.cartesianProduct(sets);
System.out.println(cartesianProducts);
System.out.println("-----------------");

//part 2
List<List<Integer>> noDuplicatesInProducts = cartesianProducts
        .stream()//iterate over each cartesian product
        .map(product ->  product.stream()
                          .distinct()//remove duplicate values
                          .collect(toList())//store updated product as list
        ).collect(toList());//store all products as list
System.out.println(noDuplicatesInProducts);

输出:

[1, 2]
[1, 3, 5]
[2]
-----------------
[[1, 1, 2], [1, 3, 2], [1, 5, 2], [2, 1, 2], [2, 3, 2], [2, 5, 2]]
-----------------
[[1, 2], [1, 3, 2], [1, 5, 2], [2, 1], [2, 3], [2, 5]]

如果您正在寻找一种将List&lt;int[]&gt; 转换为List&lt;Set&lt;Integer&gt;&gt; 的方法,这里有一个示例:

private static List<Set<Integer>> convert(List<int[]> list) {
    return list
            .stream()
            .map(arr -> 
                    IntStream.of(arr)
                    .mapToObj(Integer::valueOf)// same as .boxed()
                    .collect(toSet())
            ).collect(toList());
}

【讨论】:

  • 这似乎是我一直在寻找的答案,我会在几个小时内用我的数据表测试后标记答案。
【解决方案2】:

编辑:当时给出了这个答案,问题含糊不清,并提出了“删除重复项”的问题。我会保留这个答案,因为它可能包含对其他人有用的信息。

由于您没有正确描述输入和想要的输出,因此很难说出问题的确切解决方案。仅发布一个示例是不够的。

所以我们假设如下:

  • 输入:整数数组列表 (List&lt;int[]&gt;)。

  • 输出:整数数组列表 (List&lt;int[]&gt;),其中第 n 个 数组包含第 n 个值 输入列表的数组,但删除了重复项。

将输入列表的项目复制到一个新的输出列表中很简单:

List<int[]> output = new ArrayList<>(input.size());
for(int[] item : input) {
    output.add(removeDuplicates(item));
}

因此问题可以简化为从int[] 中删除重复项。这可以通过使用中间Set&lt;Integer&gt; 轻松解决,因为Set 默认情况下没有重复项。不幸的是,int[] 不能直接放入 HashSet&lt;Integer&gt; 中,反之亦然,因此我们必须手动复制元素:

public int[] removeDuplicates(int[] input) {
    Set<Integer> set = new HashSet<Integer>();
    for (int i = 0; i < input.length; i++)
        set.add(input[i]);
    int[] output = new int[set.size()];
    int i = 0;
    for (Integer e : set) {
        output[i++] = e;
    }
    return output;
}

(另见How to efficiently remove duplicates from an array without using Set

当然,如果您可以将List&lt;Collection&lt;Integer&gt;&gt; 作为输入和输出,一切都会容易得多。在这种情况下,事情可以很容易地完成如下:

List<Collection<Integer>> output = new ArrayList<>(input.size());
for(Collection<Integer> item : input) {
    output.add(new HashSet<Integer>(item));
}

使用 Java 8 流式处理 API

为了完整性:Java 8 流式 API 让生活变得更加轻松,即使使用 List&lt;int[]&gt;

List<int[]> output = input.stream()
    .map(item -> Arrays.stream(item).distinct().toArray())
    .collect(Collectors.toList());

【讨论】:

  • 我已经编辑了这个问题,希望你明白我在尝试什么
  • 我不关心从数组中删除重复项。我想要列表的所有 n 索引的所有可能的唯一组合。比如说,0 索引有一个元素 1,2 的 int 数组,1 索引有元素 1,3,5 和 2 索引元素 2。所以我想要的组合是1,1,2|1,3 ,2|1,5,2。现在在这个输出中,第一组 1,1,2 的两个元素都与 1 相同。所以,我想将其设为 1,2。现在我将拥有1,2|1,3,2|1,5,2。同样,当我取 0 索引中的第 2 个元素(即 2)并检索组合时,我将得到 2,1,2|2,3,2|2,5,2。最后,我希望通过删除 2 将其设为 2,1|2,3|2,5
【解决方案3】:

我假设您想在不触及顺序的情况下从每个数组中删除重复项。

您可以将每个数组映射到例如LinkedHashSet,保持秩序但不允许重复。然后只需映射回int[] 并使用Collectors.toList() 收集:

list = list.stream()
    .map(a -> Arrays.stream(a).boxed().collect(Collectors.toList())) // map to List<Integer>
    .map(LinkedHashSet::new) // map to LinkedHashSet<Integer>
    .map(s -> s.stream().mapToInt(i -> i).toArray()) // map to int[]
    .collect(Collectors.toList());

【讨论】:

  • 请查看我已编辑的问题。我不是在寻找删除数组中的重复项或关于排序。我正在寻找 Pshemo 描述的组合
  • @user3747396 我不知道你想要什么...为什么{1,5,2} 在你的示例中消失了?
  • 我的错,我现在已经更正了。你能帮我解决这个问题吗?
  • @user3747396 不抱歉,仍然没有任何意义。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2022-08-19
  • 1970-01-01
相关资源
最近更新 更多