3

I am trying to extract similar strings from 2 arrays, and I have managed to do so, except they are duplicating. i.e. array 1 {"arrow", "arrow", "sycophant"} and array 2 ("arrow", "sycophant", "bulbasaur"} will give me the output of {"arrow", "arrow" ,"sycophant"}, while I am only trying to get arrow once. Any suggestions?

public static void main(String[] args) {
    String[] words1 = { "sycophant", "rattle", "zinc", "alloy", "tunnel", "arrow" };
    String[] words2 = { "sycophant", "arrow", "arrow" };

    // String prefix = "a";
    // String substring = "at";
    // char[] letters = { 'a', 'b' };

    // String[] output = wordsStartingWith(words1, prefix);
    // String[] output = wordsContainingPhrase(words1, substring);
    // String[] output = wordsContainingAll(words1, letters);
    String[] output = wordsInBoth(words1, words2);

    for (int i = 0; i < output.length; i++) {
        System.out.println("Words: " + i + " " + output[i]);
    }
}

public static String[] wordsInBoth(String[] words1, String[] words2) {
    // method that finds and returns common words in two arrays
    String[] returnWords;
    int countWords = 0;

    for (int i = 0; i < words1.length; i++) {
        for (int j = 0; j < words2.length; j++) {
            if (words1[i].equalsIgnoreCase(words2[j])) {
                countWords++;
            }
        }
    }

    returnWords = new String[countWords];
    countWords = 0;

    for (int i = 0; i < words1.length; i++) {
        for (int j = 0; j < words2.length; j++) {
            if (words1[i].equalsIgnoreCase(words2[j]) 
                    && !words1[i].equalsIgnoreCase(returnWords[countWords])) {
                returnWords[countWords] = words1[i];
                countWords++;
            }
        }
    }

    return returnWords;
}
Tom
  • 16,842
  • 17
  • 45
  • 54
Soul
  • 79
  • 2
  • 8
  • 1
    Why don't you put the resultant words in a Set? – Atri Feb 04 '16 at 00:01
  • Here: !words1[i].equalsIgnoreCase(returnWords[countWords]). You are checking the current non-assigned returnWords position, not checking against the current stored words. – Atirag Feb 04 '16 at 00:07

6 Answers6

3

One possibility is to store the words that are found in a HashSet, which won't add duplicates.

// method that finds and returns common words in two arrays
public static String[] wordsInBoth(String[] words1, String[] words2) { 

    Set<String> returnWords = new HashSet<String>();

    for (int i = 0; i < words1.length; i++) {
        for (int j = 0; j < words2.length; j++) {
            if (words1[i].equalsIgnoreCase(words2[j]))
                returnWords.add(words1[i]);
        }
    }

    return returnWords.toArray(new String[returnWords.size()]);
}
Ronaldo Felipe
  • 402
  • 2
  • 13
DBug
  • 2,502
  • 1
  • 12
  • 25
1

You want to get the intersection between two lists. The answer to Intersection and union of ArrayLists in Java should point you in the right direction:

public class Test {

    public static void main(String... args) throws Exception {

        List<String> list1 = new ArrayList<String>(Arrays.asList("A", "B", "C"));
        List<String> list2 = new ArrayList<String>(Arrays.asList("B", "C", "D", "E", "F"));

        System.out.println(new Test().intersection(list1, list2));
    }

    public <T> List<T> intersection(List<T> list1, List<T> list2) {
        List<T> list = new ArrayList<T>();

        for (T t : list1) {
            if(list2.contains(t)) {
                list.add(t);
            }
        }

        return list;
    }
}
Community
  • 1
  • 1
JVon
  • 684
  • 4
  • 10
1

In case you wonder why this

   for (int i = 0; i < words1.length; i++)
        for (int j = 0; j < words2.length; j++)
            if (words1[i].equalsIgnoreCase(words2[j]) &&
               !words1[i].equalsIgnoreCase(returnWords[countWords])
            )
                    returnWords[countWords++] = words1[i];

doesn't work: it only a) attempts to check if words1[i] isn't the b) last word in returnWords.

a)

        !words1[i].equalsIgnoreCase( returnWords[countWords] )

is always true, because returnWords[countWords] is always null. When countWords is 0 there are no words added to it yet, and when it is 1, the added word is at returnWords[0]. So you'll need something like this instead:

        countWords == 0 || !words1[i].equalsIgnoreCase( returnWords[countWords-1] )

Now it works fine for your input (removed unique words):

    String[] words1 = { "arrow", "sycophant"  };
    String[] words2 = { "arrow", "sycophant", "arrow" };

it outputs

Words: 0 arrow
Words: 1 sycophant
Words: 2 null

b)

For

    String[] words1 = { "arrow", "sycophant", "arrow" };
    String[] words2 = { "arrow", "sycophant"  };

it outputs

Words: 0 arrow
Words: 1 sycophant
Words: 2 arrow

To prevent this, you would have to check whether the word about to be added isn't any of the already-added words:

        !contains( returnWords, words1[j] )

This is a simple for-loop, which you know how to do - and there are plenty of examples on this page, so I'll leave that out.

Kenney
  • 9,003
  • 15
  • 21
0

Maybe this will help you. I have changed your algorithm a bit and now it looks like this.

import java.util.Arrays;

public class Distinct {

public static void main(String[] args) {

    String[] words1 = { "sycophant", "rattle", "zinc", "alloy", "tunnel",
            "arrow" };
    String[] words2 = { "sycophant", "arrow", "alloy", "arrow" };

    // String prefix = "a";
    // String substring = "at";
    // char[] letters = { 'a', 'b' };

    // String[] output = wordsStartingWith(words1, prefix);
    // String[] output = wordsContainingPhrase(words1, substring);
    // String[] output = wordsContainingAll(words1, letters);
    String[] output = wordsInBoth(words1, words2);

    for (int i = 0; i < output.length; i++) {
        System.out.println("Words: " + i + " " + output[i]);
    }

}

public static String[] wordsInBoth(String[] words1, String[] words2) {

    String[] returnWords;
    int countWords = 0;

    for (int i = 0; i < words1.length; i++) {
            for (int j = 0; j < words2.length; j++) {
                if (words1[i].equalsIgnoreCase(words2[j])) {
                    countWords++;
                }
            }
        }

    returnWords = new String[countWords];
    countWords = 0;

    for (int i = 0; i < words1.length; i++) {
        for (int j = 0; j < words2.length; j++) {
            if (words1[i].equalsIgnoreCase(words2[j]) && !exists(returnWords, words1[i])) {
                returnWords[countWords] = words1[i];
                countWords++;
            }
        }
    }

    return Arrays.copyOfRange(returnWords, 0, countWords);
}

public static boolean exists(String[] array, String value)
{
    if (array.length == 0)
        return false;

    for(int i = 0; i < array.length; i++){
        if (array[i]!= null && array[i].equalsIgnoreCase(value) )
            return true;
    }

    return false;
}

}
Andy
  • 129
  • 12
  • Thank you for your responses. I am still working on the assignment and will hopefully post the correct answer (after i figure it out :D) I would also like to mention that even though the Lists and HashSets are a great idea, I cannot in good faith use those, as those would be too complex for the class I am taking, and will inevitably result in my professor docking me for plagiarism. But, I still thank you for your responses. I will modify the code based on @kenney 's response and see where it takes me from there. – Soul Feb 04 '16 at 18:42
  • The snippet above incorporates @kenny's idea :D – Andy Feb 06 '16 at 15:57
0

Try this.

public static String[] wordsInBoth(String[] words1, String[] words2) {
    return Stream.of(words1)
        .filter(w -> Stream.of(words2).anyMatch(w::equalsIgnoreCase))
        .toArray(String[]::new);
}
0

After a bit of fiddling around with the (primitive, slow and downright beginner :P) code I found a (messy) solution to my problems. XD

public static String[] wordsInBoth(String[] words1, String[] words2) {

    // method that finds and returns common words in two arrays

    String[] returnWords = new String[words1.length];
    String compare = "";
    int countWords = 0;

    for (int i = 0; i < words1.length; i++) {
        for (int j = 0; j < words2.length; j++) {
            if (words1[i].equalsIgnoreCase(words2[j]) && words1[i] != compare) {
                returnWords[countWords] = words1[i];
                compare = returnWords[countWords];
                countWords++;
            }
        }
    }

    returnWords = new String[countWords];
    countWords = 0;

    for (int i = 0; i < words1.length; i++) {
        for (int j = 0; j < words2.length; j++) {
            if (words1[i].equalsIgnoreCase(words2[j]) && words1[i] != compare) {
                returnWords[countWords] = words1[i];
                compare = returnWords[countWords];
                countWords++;
            }
        }
    }

    return returnWords;
}

(also, I don't know why, but my method line is not included in the code snippet when I post to Stack)

Soul
  • 79
  • 2
  • 8