2

I am trying to find the union of two string arrays. I have created a new array and have copied all the data from the first set into the new array. I am having trouble adding the information from the second set into the new array.

I need to use loops to search the second array and find the duplicates. I keep getting an ArrayIndexOutOfBoundsException.

Here is my current code:

static String[] union(String[] set1, String[] set2) {
    String union[] = new String[set1.length + set2.length];

    int i = 0;
    int cnt = 0;

    for (int n = 0; n < set1.length; n++) {
        union[i] = set1[i];
        i++;
        cnt++;
    }

    for (int m = 0; m < set2.length; m++) {
        for (int p = 0; p < union.length; p++) {
            if (set2[m] != union[p]) {
                union[i] = set2[m];
                i++;
            }
        }
    }
    cnt++;

    union = downSize(union, cnt);

    return union;
}
Makoto
  • 96,408
  • 24
  • 164
  • 210
user2884866
  • 39
  • 1
  • 3

5 Answers5

7

The standard way of doing intersections or unions is using a set. You should use the Set class from collections framework.

Create two arraylist objects for your two arrays.
Define a Set object.
Add both the arraylist objects into the Set using addAll method.

As set holds unique elements, the set forms the union of both arrays.

  //push the arrays in the list.
  List<String> list1 = new ArrayList<String>(Arrays.asList(stringArray1));
  List<String> list2 = new ArrayList<String>(Arrays.asList(stringArray2));

  HashSet <String> set = new HashSet <String>();

  //add the lists in the set.
  set.addAll(list1);
  set.addAll(list2);

  //convert it back to array.
  String[] unionArray = set.toArray(new String[0]);       
Sorter
  • 8,190
  • 5
  • 52
  • 63
4

Using Set is going to be one of the easiest way:

public static String[] unionOf(String[] strArr1, String[] strArr2) {
    Set<String> result = new HashSet<String>();
    result.addAll(Arrays.asList(strArr1));
    result.addAll(Arrays.asList(strArr2));
    return result.toArray(new String[result.size()]);
}

There are also other utilities that can help in similar work, e.g. Guava:

public static String[] unionOf(String[] strArr1, String[] strArr2) {
    return Sets.union(Sets.newHashSet(strArr1), 
                      Sets.newHashSet(strArr2))
               .toArray(new String[0]);
}
Adrian Shum
  • 35,318
  • 9
  • 72
  • 119
3

You have several problems with this part of your code:

for(int m = 0; m < set2.length; m++)
        for(int p = 0; p < union.length; p++)
            if(set2[m] != union[p])
            {   
                union[i] = set2[m];
                i++;        
            }
        cnt++;

First, you should be using !equals() instead of != to compare strings. Second, despite the indenting, the statement cnt++ is not part of the outer loop. You don't need both i and cnt; their values should always match. Finally, you are adding set2[m] once for each element of union that is different from it. You only want to add it once. Here's a version that should work:

static String[] union( String[] set1, String[] set2 )
{
    String union[] = new String[set1.length + set2.length];
    System.arraycopy(set1, 0, union, 0, set1.length); // faster than a loop
    int cnt = set1.length;
    for(int m = 0; m < set2.length; m++) {
        boolean found = false;
        for(int p = 0; p < union.length && !found; p++) {
            found = set2[m].equals(union[p]);
        }
        if(!found)
        {   
            union[cnt] = set2[m];
            cnt++;        
        }
    }
    union = downSize( union, cnt );
    return union;
}

As other posters have noted, an alternative approach is to use a HashSet<String>, add the elements found in the two arrays, and turn the result back into an array.

Ted Hopp
  • 222,293
  • 47
  • 371
  • 489
  • `boolean = set2[m].equals(union[p]);` - you probably meant: `found |= set2[m].equals(union[p]);` – Nir Alfasi Oct 16 '13 at 04:13
  • Thank you for the direction. This has been very helpful. I understand my mistake and have a better idea of how to correct the error. – user2884866 Oct 16 '13 at 04:18
  • 1
    @alfasin - Oops. Thanks for pointing that out. Fixed now. One does not need `|=`, though; `=` will do since the body of the loop is not entered unless `found` is `false`. – Ted Hopp Oct 16 '13 at 05:38
  • Right, I missed the condition inside the for-loop... +1 :) – Nir Alfasi Oct 16 '13 at 06:26
0

You get ArrayIndexOutOfBoundsException on this line:

union[i] = set2[m];

because you keep increasing i somewhere around: set2.length * union.length times (nested loops).

Doing what R.J wrote will not give you the union - you'll have many duplicate items since by doing: set2[m].equals(union[p]) you compare every member of set2 to all the members of union and for each member that it's not equal to - you add it. so you end up adding the same items multiple times!

The right way to do it is like Deepak Mishra suggested by using Set which will "take care" of the duplicates.

Example:

int[] a = {1,2,3,4,5};
int[] b = {4,5,6,7};
Set union = new HashSet<Integer>();
for(int i=0; i<a.length; i++) union.add(a[i]);
for(int i=0; i<b.length; i++) union.add(b[i]);
Object[] ans = union.toArray();
for(int i=0; i<ans.length; i++)
    System.out.print(ans[i]+" ");

will output:

1 2 3 4 5 6 7 

Since it's HW I won't write the code for the answer, but I'll give you a tip:
doing it your way requires O(n^2) - if you'll think a bit I'm sure that you can find a way to do it in a better time, say,
O(n log n)...

Nir Alfasi
  • 49,889
  • 11
  • 75
  • 119
0

Though using the SETS is the best solution, here is a simple solution.

 private static String getUnion(String a, String b, boolean ignoreCase) {

    String union = "";

    if (a == null || b == null || a.length() < 1 || b.length() < 1) {
        return union;
    }

    char[] shortest;
    char[] longest;

    if (ignoreCase) {
        shortest = (a.length() <= b.length() ? a : b).toLowerCase().toCharArray();
        longest = (a.length() <= b.length() ? b : a).toLowerCase().toCharArray();
    } else {
        shortest = (a.length() <= b.length() ? a : b).toLowerCase().toCharArray();
        longest = (a.length() <= b.length() ? b : a).toLowerCase().toCharArray();
    }

    StringBuilder sb = new StringBuilder();

    for (char c : shortest) {
        for (int i = 0; i < longest.length; i++) {
            if (longest[i] == c) {
                sb.append(c);
            }
        }
    }

    union = sb.toString();

    return union;
}

and following are few tests.

public static void main(String[] args) {

    System.out.println("Union of '' and BXYZA is " + getUnion("", "BXYZA", true));
    System.out.println("Union of null and BXYZA is " + getUnion(null, "BXYZA", true));

    System.out.println("Union of ABC and BXYZA is " + getUnion("ABC", "BXYZA", true));
    System.out.println("Union of ABC and BXYZA is " + getUnion("ABC", "bXYZA", false));

}
A Gilani
  • 405
  • 1
  • 5
  • 18