简体   繁体   中英

Recieving Comparator Class type

I have two Comparators. One for sorting words by first letter (in sort used only for vowel words)

public class FirstLetterComparator extends ComparatorType {
@Override
public int compare(String o1, String o2) {
    String upperObject1 = o1.toUpperCase();
    String upperObject2 = o2.toUpperCase();

    return upperObject1.charAt(0) - upperObject2.charAt(0);
  }
 }

Another for sorting by length/vowelsCount coef(used for all words in sort class)

public class VowelColComparator extends ComparatorType {
String vowelGroup = "AEIOUaeiou";

@Override
public int compare(String o1, String o2) {
    int vCount1 = getVowelCount(o1);
    int vCount2 = getVowelCount(o2);

    float compareCoef1 = o1.length()/vCount1;
    float compareCoef2 = o2.length()/vCount2;

    return (int)(compareCoef1 - compareCoef2);
}

public int getVowelCount(String word){
    int vowelCount = 0;
    for (int i = 0; i < word.length(); i++){
        char ch = word.charAt(i);
        for (int j = 0; j < vowelGroup.length(); j++){
            char v = vowelGroup.charAt(j);
            if(ch == v)
                vowelCount++;
        }
    }
    return vowelCount;
}

And their superclass

public class ComparatorType implements Comparator<String> {
@Override
public int compare(String o1, String o2) {
    return 0;
  }
} 

In sort class i have two similar methods for sorting my list

public class SortWords {

public static void sortVowelCol(String text, String regex){
    Scanner scanner = new Scanner(text);

    List<String> words = new ArrayList<>();

    System.out.println();
    System.out.println("Task1:");
    while (scanner.hasNext()){
        String word = scanner.next();
        if(word.matches(regex)){
            words.add(word);
        }
    }

    Collections.sort(words, new VowelColComparator());

    int lineCounter = 1;

    System.out.println();
    System.out.println();
    System.out.println("Sorted Words:");
    lineCounter = 1;
    for(String w : words){
        if(lineCounter == 12) {
            System.out.print(w + "\n");
            lineCounter = 0;
        }
        else
            System.out.print(w + " ");
        lineCounter++;
    }

}
public static void sortVowelWords(String text, String regex) {
    Scanner scanner = new Scanner(text);

    List<String> vowelWords = new ArrayList<>();

    System.out.println();
    System.out.println("Task2: ");
    while(scanner.hasNext()){
        String word = scanner.next();
        if(word.matches(regex)){
            vowelWords.add(word);
        }
    }

    Collections.sort(vowelWords, new FirstLetterComparator());

    System.out.println();
    System.out.println();
    System.out.println("Sorted List:");
    int lineCounter = 1;
    for(String w : vowelWords){
        if(lineCounter == 12) {
            System.out.print(w + "\n");
            lineCounter = 0;
        }
        else
            System.out.print(w + " ");
        lineCounter++;
    }
  }
 }

Main class

public class Main {

public static void main(String[] args) {
    // write your code here
    SingletonText.getInstance().parse();
    SingletonText.getInstance().print();
      SortWords.sortVowelWords(SingletonText.getInstance().getText().toString(), "^[AEIOUaeiou].*");
    SortWords.sortVowelCol(SingletonText.getInstance().getText().toString(), "^[A-Za-z].*");
  }
 }

The quesuion is how can i make only one method instead of two similar methods in SortWords class? Or how to get comparator type in for Collections.sort argument?

You may use a third parameter to define the comparator to use.

public static void sort(String text, String regex, ComparatorType comp) {
    // Code
    Collections.sort(words, comp);
    // Code
}

you need refactor two function like that:

public static void sortVowel(String text, String regex,Comparator comparator) {
    Scanner scanner = new Scanner(text);
    List<String> vowelWords = new ArrayList<>();

    System.out.println();
    System.out.println("Task2: ");
    while(scanner.hasNext()){
        String word = scanner.next();
        if(word.matches(regex)){
            vowelWords.add(word);
        }
    }

    Collections.sort(vowelWords, comparator);

    System.out.println();
    System.out.println();
    System.out.println("Sorted List:");
    int lineCounter = 1;
    for(String w : vowelWords){
        if(lineCounter == 12) {
            System.out.print(w + "\n");
            lineCounter = 0;
        }
        else
            System.out.print(w + " ");
        lineCounter++;
    }
  }
 }
public static void sort(String text, String regex, String sortType) {

  Collections.sort(words, sorttype.equals("Vowel") ? new VowelColComparator() : new FirstLetterComparator());

    // Your code

}

Then we can call like this

SortWords.sort(SingletonText.getInstance().getText().toString(), "^[AEIOUaeiou].*", "Vowel");
SortWords.sort(SingletonText.getInstance().getText().toString(), "^[A-Za-z].*", "firstletter");

First of all your VowelColComparator.getVowelCount may fail due to division by zero when there is no vowel in given string. As you are comparing ratios of length and vowel count, you can do the following:

float compareCoef1 = o1.length()/(vCount1+1);
float compareCoef2 = o2.length()/(vCount2+1);

You can use factory pattern in ComparatorType class. ie ComparatorType class will decide which instance (comparator) to use depending upon regex. You can add as many comparators as you like.

public abstract class ComparatorType implements Comparator<String> {

    final public String vowelFirstLetterRegex = "^[A-Za-z].*";

    final public String vowelColRegex = "^[AEIOUaeiou].*]";


    public static ComparatorType getInstance(String regex) {
        if (regex.equals(vowelColRegex))
            return new VowelColComparator();
        else if(regex.equals(vowelFirstLetterRegex ))
            return new FirstLetterComparator();
        return null;
    }
}

And your SortWords class will have following method:

public static void sort(String text, String regex){
    Scanner scanner = new Scanner(text);

    List<String> words = new ArrayList<>();

    System.out.println();
    System.out.println("Task1:");
    while (scanner.hasNext()){
        String word = scanner.next();
        if(word.matches(regex)){
            words.add(word);
        }
    }

    Collections.sort(words, ComparatorType.getInstance(regex));

    int lineCounter = 1;

    System.out.println();
    System.out.println();
    System.out.println("Sorted Words:");
    lineCounter = 1;
    for(String w : words){
        if(lineCounter == 12) {
            System.out.print(w + "\n");
            lineCounter = 0;
        }
        else
            System.out.print(w + " ");
        lineCounter++;
    }

}

Well, as everyone said, you need to pass Comparator<String> as the third argument to your method:

sortVowelWords(String text, String regex, Comparator<String> cmp) {
    //...
}

I'd like to suggest some improvements to comparators themselves. Using lambda syntax, they may be written far more easily:

static final Comparator<String> CMP_BY_FIRST_CHAR =
    Comparator.comparing(s -> Character.toUpperCase(s.charAt(0)));

static final Comparator<String> CMP_BY_VOWEL_COEF =
    Comparator.comparing(s -> 1f * s.length() / s.replaceAll("[^AEIOUaeiou]+", "").length());

In second comparator, I added explicit cast to float to handle possible infinity values properly.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM