如何从列表中获取元素组合

时间:2015-05-17 13:23:28

标签: java arrays lambda functional-programming

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

input:

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

如何使用或不使用Lambdas在Java中获得以下组合。

第1步:找到所有这些组合

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

-> 

步骤2:从被删除的组合中删除重复项

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

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

不需要进一步减少

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

[{1,2}] 

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

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

但如果完成,也不会影响我的结果。

3 个答案:

答案 0 :(得分:3)

你所问的似乎是N套(#import <NotificationCenter/NotificationCenter.h> @interface ViewController () <NCWidgetProviding> {...} )的笛卡尔积。

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

只有条件是我们需要提供Set1 x Set2 x ... x SetN作为参数 因此,这个答案是基于每个int []被视为集合的假设,这意味着它的值必须是唯一的。实际上,如果List<Set<..>>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<int[]>的方法,请参阅以下示例:

List<Set<Integer>>

答案 1 :(得分:2)

编辑:当时,给出了这个答案,问题含糊不清,并建议删除重复内容&#39;问题。我会保留这个答案,因为它可能包含其他人的有用信息。

由于您没有正确描述输入和想要的输出,很难说出问题的准确解决方案。只发布一个例子就不够了。

所以让我们假设以下内容:

  • 输入:整数数组列表(List<int[]>)。

  • 输出:整数数组列表(List<int[]>),其中第n 数组包含 n的值-th 输入列表的数组,但删除了重复项。

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

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

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

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<Collection<Integer>>作为输入和输出,那么一切都要容易得多。在这种情况下,事情可以很容易地完成如下:

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<int[]>

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

答案 2 :(得分:-1)

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

您可以将每个数组映射到例如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());