Question: The method below does the job, but it's not very efficient.

Does anyone know a more elegant solution to do this?

I have fumbled with something like this but no luck so far: /^(foo|bar|[[:space:][:punct:]])+$/

```
static public boolean matchTitle(String title, String title2) {

    Scanner scanner1 = new Scanner(title);
    Scanner scanner2 = new Scanner(title2);
    String searchTitle = title2;
    boolean match = false;
    int i = 0;
    while(i < 2){
        if(i == 1){
            scanner1 = new Scanner(title2);
            scanner2 = new Scanner(title);
            searchTitle = title;
        }

        // breaks into words
        while (scanner1.hasNext()){
            match = false;

            String token = scanner1.next();
            scanner2 = new Scanner(searchTitle);
            while (scanner2.hasNext() && !match){
                String token2 = scanner2.next();
                if(token.equals(token2)){
                    // if the words match
                    match = true;
                }
            }
            if(!match){ // we have a word that didn't match any words in the second title
                return false;
            }
        }
        i++;
    }
    return true;
}

```

**Example**

("similar words here", "similar words here") // true

("similar words here", "words here similar here") // true

("similar words here", "similar words here different") // false

Answer: 
I would go for a simpler version:

```
List<String> words1 = Arrays.asList(title.split(" "));
List<String> words2 = Arrays.asList(title2.split(" "));

return words1.containsAll(words2) &&
       words2.containsAll(words1);

```

Assumptions:

* title and title2 are non null
* space is the only delimiter
* if a string contains the same word n times, the other must contain that word n times too

**EDIT**

Your edit shows that duplicates are fine. In which case you can use a set instead of a list:

```
Set<String> words1 = new HashSet<String> (Arrays.asList(title.split(" ")));
Set<String> words2 = new HashSet<String> (Arrays.asList(title2.split(" ")));

return words1.size() == words2.size() && words1.containsAll(words2);

```

Note: as indicated by [chm052 in his answer](https://stackoverflow.com/a/15074082/829571), in the case of Sets, you can simply check for equality, which ignores the order (but not in the List example):

```
return words1.equals(words2);

```
What you are asking is wether the *set of words in the first string* is equal to the *set of words in the second string*. After all, the things you want to ignore about the string (word order and repeated words) don't exist in sets by definition.

So, you need

```
Set<String> words1 = new HashSet<String> (Arrays.asList(title.split(" ")));
Set<String> words2 = new HashSet<String> (Arrays.asList(title2.split(" ")));

return words1.equals(words2);

```

EDIT:

As assylias pointed out, there's no big change in functionality if you switch use the equals method rather than the size and containsAll methods, but it's easier to understand when reading the code. It's also probably better OO practice to decouple this method with the set class in this way; then, for example, if a better algorithm for finding deep set equality is implemented in the Java set class, you'll get to use that improvement.

BONUS SECOND EDIT:

If anyone is confused by the comment thread on this, it's about this previous answer by assylias (and wether or not it will work in every case):

```
List<String> words1 = Arrays.asList(title.split(" "));
List<String> words2 = Arrays.asList(title2.split(" "));
return words1.size() == words2.size() && words1.containsAll(words2);

```