54

I want to implement the union, intersect, difference and reverse operations in Java.

First I have 2 instances of ArrayList<Integer>

a = [0,2,4,5,6,8,10]
b = [5,6,7,8,9,10]

a union b should return c = [0,2,4,5,6,7,8,9,10]

a intersect b should return c = [5,8,10]

a difference b should return c = [0,2,4]

reverse a = [10,8,6,5,4,2,0]

Something like this.

How to implement that method in Java?


Update: I have to start with this template:

package IntSet;
import java.util.ArrayList;
import java.util.Collection;


public class IntSet {

private ArrayList<Integer> intset;

public IntSet(){
    intset = new ArrayList<Integer>();
}

public void insert(int x){
    intset.add(x);
}

public void remove(int x){
    //implement here
    intset.indexOf(x);
}

public boolean member(int x){
    //implement here
    return true;
}

public IntSet intersect(IntSet a){
    //implement here
    return a;
}

public IntSet union(IntSet a){
    //implement here
    return a;
}

public IntSet difference(IntSet a){
    //implement here
    IntSet b = new IntSet();
    return b; 
}
jsheeran
  • 2,912
  • 2
  • 17
  • 32
Giffary
  • 3,060
  • 12
  • 50
  • 71
  • 1
    Again, you're talking about set functions, but you use lists. So your insert function is already wrong: You're not testing for duplicates. – Landei Aug 30 '10 at 12:14
  • Just for the records, there is also https://stackoverflow.com/questions/5283047, which handles the same topic and also has a lot of answers. – Martin Höller May 20 '21 at 09:56

7 Answers7

81

First, the operations you describe (except reverse) are set operations, not list operations, so use HashSet or (if you need an ordering) TreeSet.

    Set<Integer> a = new TreeSet<Integer>(Arrays.asList(new Integer[]{0,2,4,5,6,8,10}));
    Set<Integer> b = new TreeSet<Integer>(Arrays.asList(new Integer[]{5,6,7,8,9,10}));

    //union
    Set<Integer> c = new TreeSet<Integer>(a);
    c.addAll(b);
    System.out.println(c);

    //intersection
    Set<Integer> d = new TreeSet<Integer>(a);
    d.retainAll(b);
    System.out.println(d);

    //difference
    Set<Integer> e = new TreeSet<Integer>(a);
    e.removeAll(b);
    System.out.println(e);

    //reverse
    List<Integer> list = new ArrayList<Integer>(a);
    java.util.Collections.reverse(list);
    System.out.println(list);
Landei
  • 54,104
  • 13
  • 100
  • 195
  • 5
    If you declared `a` and `b` as `NavigableSet`, then you could reverse their order using the `descendingSet()` method. For a general `Set`, there is no notion of order. – Natix Oct 10 '14 at 14:27
  • Nice answer, though the reverse part is nonsense. It originated in head of OP, but you didn't have to follow this. Or, you could provide a set with opposite comparator. – Vlasec Nov 07 '17 at 17:18
45
//Union 
List<Integer> c = new ArrayList<Integer>(a.size() + b.size());
addNoDups(c,a);
addNoDups(c,b);

private void addNoDups(List<Integer> toAddTo,List<Integer> iterateOver) {
    for(Integer num:iterateOver){
        if(toAddTo.indexOf(num) == -1) {
            toAddTo.add(num);
        }
    }
}

//intersection
List<Integer> c = new ArrayList<Integer> (a.size() > b.size() ?a.size():b.size());
c.addAll(a);
c.retainAll(b);

//difference a-b
List<Integer> c = new ArrayList<Integer> (a.size());
c.addAll(a);
c.removeAll(b);
anand
  • 482
  • 4
  • 2
  • 2
    +1 for a concise answer. Although I think you could have used Hashset instead of ArrayList to drive home the point. – Hari Apr 02 '14 at 23:37
  • +1 But... This approach can reserve more space, then it is required for the resulted `List c`. Maybe, it would be better not to reserve that space during `new ArrayList` creation time at all? – Dmytro Dzyubak May 25 '14 at 14:52
  • @DmytroDzyubak The complexity of all methods is quadratic, which is usually much worse than using some extraneous space. It may be acceptable sometimes, but the solution at the very least clearly mention it. – maaartinus Dec 10 '16 at 11:56
30

If you are using Sets (as you should, for all of those except reverse are Set operations), Guava provides these operations in it's Sets class.

Set<Integer> union = Sets.union(set1, set2);
Set<Integer> intersection = Sets.intersection(set1, set2);
Set<Integer> difference = Sets.difference(set1, set2);

All of these return unmodifiable views, backed by the original Sets.

See Guava Explained -> Collection Utilities -> Sets

If Lists are what you have, you can convert them to a Set by using the copy constructor present in all standard collections:

List<X> list = new ArrayList<>();
// fill up list here
Set<X> set = new HashSet<>(list);
Sean Patrick Floyd
  • 292,901
  • 67
  • 465
  • 588
9

A lot of the answers tell you to use libraries that will do the work for you. While this is the right solution for the real world, keep in mind hat you're doing homework, and your teacher probably wants you to understand how the functions are written, not just how to find libraries to do the work for you.

That said, you've got a good start with the code you've shown. Let's take the problem one step at a time.

First, do you know where the Java documentation is located? http://download.oracle.com/javase/1.4.2/docs/api/ this is critical, as this is how you find out what functions do what. Here's the link to Java 1.4. I didn't notice what version you're using, but Java is backward compatible, so this should be sufficient.

In the docs, find the ArrayList entry.

Now that we've got the API docs, we need to break down your question. you've posted code, so I'll address it function by function.

insert() : do you have to have an ordered list, or does order not matter? Or are you guaranteed that values will be provided to you in order? Have you learned sorting algorithms yet?

remove() : this function doesn't work. take a look at the ArrayList API and see how to remove an item from the list. Use that method.

member() : your member method doesn't work. You need to check every entry of the list and determine if the current member matches the function argument. Have you learned about for loops?

intersect() : ok, tell me in English what intersect is supposed to do. Don't use the teacher's description if you can help it - use your own words (note to others, this is an exercise for the OP to learn to program, so please don't go answering it for him)

difference() : again, tell me in English what it's supposed to do.

reverse() : again, give me the English description of what this is supposed to do.

Once you have english descriptions, describe an algorithm that can do the work. don't write it in Java yet. just write an algorithm, in english, describing how you would do the work manaully, with pen and paper.

at this point, try and convert the algorithm to Java code.

vikas_hada
  • 89
  • 2
  • 9
atk
  • 9,244
  • 3
  • 32
  • 32
4

I just will leave it here. There is a new way with java-8 and streams

List<Integer> listA = Arrays.asList(0, 2, 4, 5, 6, 8, 10);
List<Integer> listB = Arrays.asList(5, 6, 7, 8, 9, 10);

List<Integer> intersection = listA.stream()
        .filter(listB::contains)
        .collect(Collectors.toList());

List<Integer> union = Stream.concat(listA.stream(), listB.stream())
        .distinct().sorted()
        .collect(Collectors.toList());

List<Integer> aDiffB = listA.stream()
        .filter(i -> !listB.contains(i))
        .collect(Collectors.toList());

System.out.println(intersection); // [5, 6, 8, 10]
System.out.println(union); // [0, 2, 4, 5, 6, 7, 8, 9, 10]
System.out.println(aDiffB); // [0, 2, 4]
Anton Balaniuc
  • 10,889
  • 1
  • 35
  • 53
3

This snippet will find the union of two collections using apache commons CollectionUtils.union method

Collection<String> totalFriends = CollectionUtils.union(yourFriends, myFriends);
An Nguyen
  • 770
  • 2
  • 12
  • 25
1

The methods addAll, retainAll and removeAll are the methods most commonly used to implement union, intersect and difference in Java. With Streams in Java 8+, you do have some more options for intersect and difference using filter as pointed out in a previous answer.

If you're open to using a third-party library, the following code will work with primitive collections using Eclipse Collections when version 11.0 of the library is released.

@Test
public void unionIntersectDifferenceReverse()
{
    IntList list1 = IntLists.immutable.with(0, 2, 4, 5, 6, 8, 10);
    IntList list2 = IntLists.immutable.with(5, 6, 7, 8, 9, 10);

    MutableIntSet set1 = list1.toSet();
    MutableIntSet set2 = list2.toSet();

    IntSet union = set1.union(set2);
    IntSet intersection = set1.intersect(set2);
    IntSet difference = set1.difference(set2);

    IntList reversed = list1.toReversed();

    Assert.assertEquals(IntSets.mutable.with(0, 2, 4, 5, 6, 7, 8, 9, 10), union);
    Assert.assertEquals(IntSets.mutable.with(5, 6, 8, 10), intersection);
    Assert.assertEquals(IntSets.mutable.with(0, 2, 4), difference);
    Assert.assertEquals(IntLists.mutable.with(10, 8, 6, 5, 4, 2, 0), reversed);
}

This functionality was recently contributed to primitive Sets in Eclipse Collections. The linked blog describes how these methods are implemented on primitive sets.

The following code uses object collections with boxed Integers. This code will work with Eclipse Collections releases available today.

@Test
public void unionIntersectDifferenceReverseWithBoxedIntegers()
{
    ImmutableList<Integer> list1 = Lists.immutable.with(0, 2, 4, 5, 6, 8, 10);
    ImmutableList<Integer> list2 = Lists.immutable.with(5, 6, 7, 8, 9, 10);

    MutableSet<Integer> set1 = list1.toSet();
    MutableSet<Integer> set2 = list2.toSet();

    MutableSet<Integer> union = set1.union(set2);
    MutableSet<Integer> intersection = set1.intersect(set2);
    MutableSet<Integer> difference = set1.difference(set2);

    ImmutableList reversed = list1.toReversed();

    Assert.assertEquals(Sets.mutable.with(0, 2, 4, 5, 6, 7, 8, 9, 10), union);
    Assert.assertEquals(Sets.mutable.with(5, 6, 8, 10), intersection);
    Assert.assertEquals(Sets.mutable.with(0, 2, 4), difference);
    Assert.assertEquals(Lists.mutable.with(10, 8, 6, 5, 4, 2, 0), reversed);
}

Note: I am a committer for Eclipse Collections.

Donald Raab
  • 6,458
  • 2
  • 36
  • 44