Sorting an array using two different criteria

别等时光非礼了梦想. 提交于 2020-01-24 19:47:31

问题


I am trying to sort an array using the insertion sort algorithm. The array is filled with WordNode elements that include a word field (inputted from a text file) and a frequency field (to measure the number of times the particular word appears in the text file). I have implemented the sort so that words are sorted by frequency (from lowest to highest), but I also want to sort alphabetically if frequencies are equal. How can I sort using two different criteria at the same time? Below is my sort code.

public static void sort(ArrayUnorderedList<WordNode> array) {
    //create stacks for insertion sort
    LinkedStack<WordNode> sorted = new LinkedStack<WordNode>();
    LinkedStack<WordNode> temp = new LinkedStack<WordNode>();

    //while the array has elements to be sorted
    while(!array.isEmpty()) {
        //remove current element from array
        WordNode currentNode = array.removeFirst();

        //while the sorted stack meets sorting criteria
        while((!sorted.isEmpty()) && (sorted.peek().getFrequency() < currentNode.getFrequency())) {
            //push elements to temp stack
            temp.push(sorted.pop());
        }

        //push current element to sorted stack
        sorted.push(currentNode);

        //while the temp stack has elements to be replaced
        while(!temp.isEmpty()) {
            //push elements to sorted stack
            sorted.push(temp.pop());
        }
    }

    //replace sorted elements in array
    while(!sorted.isEmpty()) {
        array.addToRear(sorted.pop());
    }
}

回答1:


AppClay's answer is absolutely correct, but if you are interested in "tidying it up", create a helper that implements Comparator.

class WordNodeComparator implements Comparator<WordNode> {
    @Override
    public int compare(WordNode lhs, WordNode rhs) {
        int result = lhs.getFrequency() - rhs.getFrequency();
        if (result == 0) {
            return lhs.getWord().compareTo(rhs.getWord());
        }
        else {
            return result;
        }
    }
}

Then you simply create an instance of it, and use it in your loop:

while((!sorted.isEmpty()) && (nodeComparator.compare(sorted.peek(), currentNode) < 0)

Not only does this make the code easier to read and test, it's now trivial to swap out different Comparator implementations as needed.




回答2:


Update this line:

while((!sorted.isEmpty()) && (sorted.peek().getFrequency() < currentNode.getFrequency())) {

to:

while((!sorted.isEmpty()) && (sorted.peek().getFrequency() < currentNode.getFrequency() || (sorted.peek().getFrequency() == currentNode.getFrequency() &&  sorted.peek().getWord().compareTo(currentNode.getWord()) < 0))) {



回答3:


Add this to your code:

int cmp = sorted.peek().getFrequency() - currentNode.getFrequency();
if (cmp == 0)
    cmp = sorted.peek().getWord().compareTo(currentNode.getWord());

while((!sorted.isEmpty()) && cmp < 0) {
    //push elements to temp stack
    temp.push(sorted.pop());
    cmp = sorted.peek().getFrequency() - currentNode.getFrequency();
    if (cmp == 0)
        cmp = sorted.peek().getWord().compareTo(currentNode.getWord());
}

I'm assuming that getFrequency() returns an integer and that the actual word in a WordNode is accessed by the getWord() method. Using the above we compare first by frequency, and if both frequencies are equal then we compare alphabetically

EDIT :

A nicer solution, define this helper method:

private static boolean compare(LinkedStack<WordNode> sorted, WordNode current) {
    int cmp = sorted.peek().getFrequency() - current.getFrequency();
    if (cmp == 0)
        cmp = sorted.peek().getWord().compareTo(current.getWord());
    return cmp;
}

And then change the first inner loop in your code to this:

while (!sorted.isEmpty() && compare(sorted, currentNode) < 0) {
    //push elements to temp stack
    temp.push(sorted.pop());
}



回答4:


Use Guava lib:

    public static List<WordNode> sort(List<WordNode> src){
       List<WordNode> result = Lists.newArrayList(src);
       Collections.sort(result, new Comparator<WordNode>(){
           @Override public int compare(WordNode w1, WordNode w2) {
             return ComparisonChain.start()  
                     .compare(w1.frequency, w2.frequency)  
                     .compare(w1.word     , w2.word) 
                     .result(); 
        }});
       return result;
     }


来源:https://stackoverflow.com/questions/10134303/sorting-an-array-using-two-different-criteria

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!