-2

I have a List<int[]> as index_position:int[] values

input:

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

How do I get the following combination in Java with or without using Lambdas.

Step1: Find all such combinations

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

-> 

Step2: Remove duplicates from the obtanied combination

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

"want to do in each step like generate all n element subsets from n arrays >where first element comes from first array, second from second array..., >remove duplicates from each of resulting subsets."

It is not required to further reduce

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

to

[{1,2}] 

or

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

to

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

but will not affect the result in my case if done as well.

user3747396
  • 141
  • 12
  • 3
    This is no `List` objects in the sense of Java syntax. Can you please post the code that creates this list or at least describe how this list is structured? – isnot2bad May 17 '15 at 13:27
  • 6
    And describe the rules of what you call 'reduction'. I have no clue how the second list is related to the first list! – isnot2bad May 17 '15 at 13:29
  • I assume he wants to remove duplicates from each array. – Bubletan May 17 '15 at 13:34
  • The word reduction was wrong as well as `{2,1,1}`. Please excuse me on that. I have a java list as `List indexList = new ArrayList<>();` and `int[] indices = IntStream.range().filter().toArray();` `indexList.add(indices);`. I would like to get a combination as unique elements from all indexes of the list.Thanks. – user3747396 May 17 '15 at 13:48
  • 3
    Please [edit] your post and correct your example. Also sometimes same output can be result of different operations. Because of that we would rather not assume what you are trying to do so you should be precise what you want to do in each step like *generate all n element subsets from n arrays where first element comes from first array, second from second array...*, *remove duplicates from each of resulting subsets*. Also do you perhaps want to remove duplicate subsets like if you would have `{1,2} {1,2}`, or maybe even `{1,2} {2,1}`? – Pshemo May 17 '15 at 14:04
  • @Pshemo I have edited the question as per the comments. Could you please look into the problem as the answers posted are not the solution I am expecting and request to upvote the question if the edited question is understandable. – user3747396 May 17 '15 at 15:11
  • 2
    Each of your steps deserves to be separate question (which was probably already asked on SO so try searching for resources for now). Anyway we still don't know quite important information which is: is number of your arrays always 3 or can there be more? Depending on this information we can chose if we can do it simply with three loops (or inner streams) or if we will need some recursive solution. – Pshemo May 17 '15 at 17:46
  • 2
    Can we assume that each `int[]` contains unique numbers? In other words can `index 0:` be `{1,1,2}`? – Pshemo May 17 '15 at 18:32
  • @Pshemo The number of arrays is dynamically obtained and is therefore not 3 always. I think a case of `index: 0 | {1,1,2}` may not occur but since I do not have the data with me now so am unable to acknowledge it. In any case your answer is satisfying all cases i guess which is really what is excellent. – user3747396 May 17 '15 at 19:18
  • 1
    Anyway my [answer](http://stackoverflow.com/a/30290726/1393766) (below) is based on assumption that `int` is set, which means it can't contain duplicate elements, or to be more precise, it can contain them, but duplicates will be ignored (removed while processing). – Pshemo May 17 '15 at 19:21

3 Answers3

3

What you are asking seems to be cartesian product of N sets (Set1 x Set2 x ... x SetN).

Unfortunately there is no standard method in Java which would allow us to build one easily, but with little help of Guava and its Sets.cartesianProduct method this task seems quite easy.

Only condition is that we need to provide as its argument List<Set<..>>.
Because of that this answer is based on assumption that each int[] is can be treated as set, which means that its values must be unique. Actually to be more precise if index 0 will be {1,2,1} or {1,2,2} it will be processed as set {1,2}.

Here is example with List<Set<Integer>> with your current data
(toList is statically imported Collections.toList() method, similarly 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);

Output:

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

If you are looking for a way to convert List<int[]> to List<Set<Integer>> here is one example:

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());
}
Pshemo
  • 122,468
  • 25
  • 185
  • 269
  • This certainly seems to be the answer I was loooking for and I shall mark the answer once I tested with my datasheet in few hours. – user3747396 May 17 '15 at 19:04
2

Edit: At the time, this answer was given, the question was vague and suggested a 'remove duplicates' problem. I'll keept this answer though as it might contain helpful information to others.

Its hard to tell an exact solution to your problem as you don't properly describe the input and the wanted output. Just posting one example isn't enough.

So let's assume the following:

  • Input: A list of integer arrays (List<int[]>).

  • Output: A list of integer arrays (List<int[]>), where the n-th array contains the values of the n-th array of the input list, but with duplicates removed.

Copying the items of the input list into a new output list is simple:

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

So the problem can be reduced to removing duplicates from an int[]. This is solved easily by using a intermediate Set<Integer>, as a Set does not have duplicates by default. Unfortunately, a int[] cannot be put directly into a HashSet<Integer> and vice-versa, so we have to manually copy element-wise:

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;
}

(See also How to efficiently remove duplicates from an array without using Set)

Everything is much easier of course, if you could have an List<Collection<Integer>> as input and output. In that case, the thing could be done easily as follows:

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

Using Java 8 streaming API

For completeness: Java 8 streaming API makes life much easier, even with List<int[]>:

List<int[]> output = input.stream()
    .map(item -> Arrays.stream(item).distinct().toArray())
    .collect(Collectors.toList());
Community
  • 1
  • 1
isnot2bad
  • 24,105
  • 2
  • 29
  • 50
  • I have edited the question, hope you understand what I was trying – user3747396 May 17 '15 at 14:54
  • I am not concerned with removing duplicates from the array. I want all possible unique combinations of all n index of the List. Say, 0 index has an int array of elements 1,2 and 1 index has elements 1,3,5 and 2 index with elements 2. So a combination I want here is `1,1,2|1,3 ,2|1,5,2`. Now in this output, the first set 1,1,2 has both the elements same as 1. So, I want to make it 1,2. Now I will have `1,2|1,3,2|1,5,2`. Similarly when I take the 2nd element in the 0 index which is 2 and retrieve the combination I shall get `2,1,2|2,3,2|2,5,2`. Finally I want it as `2,1|2,3|2,5` by removing `2` – user3747396 May 17 '15 at 14:55
-1

I assume you want to remove duplicates from each array without touching the order.

You can map each array to e.g. LinkedHashSet, which keeps te order but doesn't allow duplicates. Then just map back to int[] and collect using 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());
Bubletan
  • 3,833
  • 6
  • 25
  • 33