Use same sort algorithm with different attributes

1

Scenery:

I'm developing a small application as a task for my course. As the intention of the work is precisely to show what we learned during the lessons, I can not escape much of what I already have, in other words, I can not go to "very advanced things". Although I know that it is of course complicated to do what I want, I want tips on "simple" ways of doing it.

At some point I need to sort a collection of users by their victories (from the highest pro minor), using as their tiebreak their defeats (the less defeats, higher). The Usuario class has both attributes ( vitorias and derrotas ).

What I want is to also sort the array by number of defeats from the user, however, without having to rewrite this entire method.

My current sort method is as follows (the sort algorithm used is bubble sort )

private void ordenar(Usuario[] usuarios){
    boolean troca = true;

    while(troca){            
        troca = false;
        for(int i = 0; i < usuarios.length - 1; i++) {
            if(usuarios[i].getVitorias() < usuarios[i + 1].getVitorias() || 
               (usuarios[i].getVitorias() == usuarios[i + 1].getVitorias()
                && usuarios[i].getDerrotas() > usuarios[i + 1].getDerrotas()))
            {
                Usuario u = usuarios[i + 1];
                usuarios[i + 1] = usuarios[i];
                usuarios[i] = u;
                troca = true;
            }
        }
    }
}
    
asked by anonymous 27.04.2017 / 19:57

2 answers

2

Use an interface

One of the ways you can change the sort function is through the use of an interface. Following the code you've written, without modifying the way you're doing the sort, a suggestion of interface would be as follows:

interface Comparador 
{
    boolean compare(Usuario a, Usuario b);
}

You could write two implementations for it, for example:

One to order for victories:

class Vitoriosos implements Comparador {
    public boolean compare(Usuario a, Usuario b) {
        return (a.getVitorias() < b.getVitorias() ||    
           (a.getVitorias() == b.getVitorias()
           && a.getDerrotas() > b.getDerrotas()));
    }
}   

Another to sort by defeats:

class Derrotados implements Comparador {
    public boolean compare(Usuario a, Usuario b) {
        return (a.getDerrotas() < b.getDerrotas() ||    
          (a.getDerrotas() == b.getDerrotas()
          && a.getVitorias() > b.getVitorias()));
    }
}   

The modification in your code would be for you to pass, in addition to the collection of users, the instance of the class that implements the interface. It would look something like:

private static void ordenar(Usuario[] usuarios, Comparador cmp){
    boolean troca = true;

    while(troca){            
        troca = false;
        for(int i = 0; i < usuarios.length - 1; i++) {
            if(cmp.compare(usuarios[i], usuarios[i+1]))
            {
                Usuario u = usuarios[i + 1];
                usuarios[i + 1] = usuarios[i];
                usuarios[i] = u;
                troca = true;
            }
        }
    }
}

In Java and other languages there is a similar way to create comparator classes. In Java, the corresponding interface calls Comparator . On this page has a very simple tutorial explaining Comparator e the Comparable .

    
27.04.2017 / 22:12
3

Good afternoon, depending on your code, I believe the simplest way to do attribute-based sort would look something like this:

Create an enum for fields that can be sorted

public enum ESort {
    VITORIAS, DERROTAS;
}

Create an enum for the sort side

public enum EOrder {
    ASCENDENTE, DESCENDENTE;
}

Created these two enum's you will need to change your sorting method to work with these variances.

Now you will need to create a method that validates the order exchange

public boolean isTrocaOrder(int x1, int y1, int x2, int y2, EOrder order) {
    if (order == EOrder.DESCENDENTE) {
        if (x1 < x2 || (x1 == x2 && y1 > y2)) {
            return true;
        }
    } else if (order == EOrder.ASCENDENTE) {
        if (x1 > x2 || (x1 == x2 && y1 < y2)) {
            return true;
        }
    }
    return false;
}

I have separately created the field calls

private boolean isTrocaDerrotas(Usuario prev, Usuario next, EOrder order) {
    return isTrocaOrder(prev.getDerrotas(), prev.getVitorias(), next.getDerrotas(), next.getVitorias(), order);
}

private boolean isTrocaVitorias(Usuario prev, Usuario next, EOrder order) {
    return isTrocaOrder(prev.getVitorias(), prev.getDerrotas(), next.getVitorias(), next.getDerrotas(), order);
}

Another step is to create a validator per field

private boolean isTrocaCampo(Usuario prev, Usuario next, ESort sort, EOrder order) {
    if (sort == ESort.VITORIAS) {
        return isTrocaVitorias(prev, next, order);
    } else if (sort == ESort.DERROTAS) {
        return isTrocaDerrotas(prev, next, order);
    }
    return false;
}

Now your method can be changed

private void ordenar(Usuario[] usuarios, ESort sort, EOrder order) {
    boolean troca = true;

    while (troca) {
        troca = false;
        for (int i = 0; i < usuarios.length - 1; i++) {
            Usuario prev = usuarios[i];
            Usuario next = usuarios[i + 1];
            if (isTrocaCampo(prev, next, sort, order)) {
                usuarios[i + 1] = prev;
                usuarios[i] = next;
                troca = true;
            }
        }
    }
}

I believe that this way you can reuse your method, example calls:

ordenar(usuarios, ESort.VITORIAS, EOrder.DESCENDENTE);
ordenar(usuarios, ESort.VITORIAS, EOrder.ASCENDENTE);
ordenar(usuarios, ESort.DERROTAS, EOrder.DESCENDENTE);
ordenar(usuarios, ESort.DERROTAS, EOrder.ASCENDENTE);

reminding you that this code is using the sort order bubble sort. If you need to use other sort methods too, you can create a ITipoOrdenacao interface for example with the sort method and change the methods accordingly.

I hope I have helped Hugs

    
27.04.2017 / 21:19