Comparator - PriorityQueue

3

I'm building a comparator for later use within a PriorityQueue.

private PriorityQueue<Conta> listaOrdenada = new PriorityQueue<Conta>(new ComparadorConta());

The object I want to sort is the Account.

 Conta conta = new Conta(String designação, int numero);

 new Conta("A",2);
 new Conta("B",3);
 new Conta("B",6);
 new Conta("A",1);
 new Conta("A",5);

The supposed to sort according to the following criteria:

  • You have to come with a number less than 4
  • You must see the ones that start with the letter A
  • Insertion order
  • This would give this ouput:

    "A", 2

    "A", 1

    "B", 3

    "B", 6

    "A", 5

    Only I can sort by number.

    public class ComparadorConta implements Comparator<Conta>{
    
     @Override
     public int compare(Conta a, Conta b) {
    
        return a.getNumero() - b.getNumero();
     }
    }
    

    Can someone help me sort by these criteria? Thanks!

        
    asked by anonymous 08.11.2016 / 02:30

    2 answers

    3

    EDIT 1 - With PriorityQueue

    If you really need to use PriorityQueue to sort, I suggest creating a control variable to know the insertion order.

    Create a class variable to control the last inserted within class Conta :

    private static int ultimo = 0;
    

    Create a ordem attribute that will be used internally:

    private final int ordem;
    

    In the constructor, instantiate the order and update the variable ultimo :

    this.ordem = ultimo + 1;
    ultimo = this.ordem;
    

    Add get of field ordem :

    public int getOrdem() {
      return ordem;
    }
    

    To make the comparison, you do not need a Comparator , just that your Conta class implements interface Comparable as follows:

    public class Conta implements Comparable<Conta> {
    

    You will need to implement the compareTo method that will look like the following, respecting the 3 rules imposed in the topic:

    @Override
    public int compareTo(Conta conta) {
    
      // 1. Tem de vir os que tem um numero inferior a 4
      if (this.numero < 4 && conta.getNumero() >= 4) {
        return -1;
      } else if (this.numero >= 4 && conta.getNumero() < 4) {
        return 1;
      }
    
      // 2. Tem de vir os que começam com a letra A
      if (this.designacao.toUpperCase().startsWith("A") && !conta.getDesignacao().toUpperCase().startsWith("A")) {
        return -1;
      } else if (!this.designacao.toUpperCase().startsWith("A") && conta.getDesignacao().toUpperCase().startsWith("A")) {
        return 1;
      }
    
      // 3. Ordem de inserção
      return Integer.valueOf(this.ordem).compareTo(conta.getOrdem());
    }
    

    To test use:

    public static void main(String[] args) {
      PriorityQueue<Conta> listaOrdenada = new PriorityQueue<>();
    
      listaOrdenada.add(new Conta("A", 2));
      listaOrdenada.add(new Conta("B", 3));
      listaOrdenada.add(new Conta("B", 6));
      listaOrdenada.add(new Conta("A", 1));
      listaOrdenada.add(new Conta("A", 5));
    
      while(!listaOrdenada.isEmpty()) {
        System.out.println(listaOrdenada.poll());
      }
    }
    

    Remembering that the structure you are using ( PriorityQueue ) rearranges items after poll .

    This will result in:

    • "A", 2
    • "A", 1
    • "B", 3
    • "A", 5
    • "B", 6

    No PriorityQueue

    I believe using Collections.sort and PriorityQueue is not the best choice because there is already a structure with the 3 requirement that is the insertion order. The LinkedHashSet . I will put here two implementations and the test of the two is accomplished with the following code:

    LinkedHashSet<Conta> lista = new LinkedHashSet<>();
    LinkedHashSet<Conta> listaOrdenada;
    
    lista.add(new Conta("A", 2));
    lista.add(new Conta("B", 3));
    lista.add(new Conta("B", 6));
    lista.add(new Conta("A", 1));
    lista.add(new Conta("A", 5));
    
    listaOrdenada = this.ordenar(lista);
    
    for (Conta conta : listaOrdenada) {
      System.out.println(conta);
    }
    

    Where the account class has method toString following:

    @Override
    public String toString() {
      return "\"" + this.designacao + "\"," + String.valueOf(this.numero); 
    }
    

    The first considers only the 3 isolated rules:

    public LinkedHashSet<Conta> ordenar(LinkedHashSet<Conta> lista) {
      LinkedHashSet<Conta> prioridade1 = new LinkedHashSet<>(); // Números menores que 4
      LinkedHashSet<Conta> prioridade2 = new LinkedHashSet<>(); // Letra "A"
      LinkedHashSet<Conta> restante = new LinkedHashSet<>();
      LinkedHashSet<Conta> listaOrdenada = new LinkedHashSet<>();
    
      for (Conta conta : lista) {
        if (conta.getNumero() < 4) {
          prioridade1.add(conta);
        } else if (conta.getDesignacao().toUpperCase().startsWith("A")) {
          prioridade2.add(conta);
        } else {
          restante.add(conta);
        }
      }
    
      listaOrdenada.addAll(prioridade1);
      listaOrdenada.addAll(prioridade2);
      listaOrdenada.addAll(restante);
    
      return listaOrdenada;
    }
    

    Resulting in:

    • "A", 2
    • "B", 3
    • "A", 1
    • "A", 5
    • "B", 6

    The second considers that numbers smaller than 4 and with letter "A" has the highest priority:

    public LinkedHashSet<Conta> ordenar(LinkedHashSet<Conta> lista) {
      LinkedHashSet<Conta> prioridade1 = new LinkedHashSet<>(); // Números menores que 4 com letra "A"
      LinkedHashSet<Conta> prioridade2 = new LinkedHashSet<>(); // Números menores que 4
      LinkedHashSet<Conta> prioridade3 = new LinkedHashSet<>(); // Letra "A"
      LinkedHashSet<Conta> restante = new LinkedHashSet<>();
      LinkedHashSet<Conta> listaOrdenada = new LinkedHashSet<>();
    
      for (Conta conta : lista) {
        if (conta.getNumero() < 4
                && conta.getDesignacao().toUpperCase().startsWith("A")) {
          prioridade1.add(conta);
        } else if (conta.getNumero() < 4) {
          prioridade2.add(conta);
        } else if (conta.getDesignacao().toUpperCase().startsWith("A")) {
          prioridade3.add(conta);
        } else {
          restante.add(conta);
        }
      }
    
      listaOrdenada.addAll(prioridade1);
      listaOrdenada.addAll(prioridade2);
      listaOrdenada.addAll(prioridade3);
      listaOrdenada.addAll(restante);
    
      return listaOrdenada;
    }
    

    Resulting in:

    • "A", 2
    • "A", 1
    • "B", 3
    • "A", 5
    • "B", 6

    If you need to use PriorityQueue you can do the following conversion:

    PriorityQueue pq = new PriorityQueue();
    pq.addAll(listaOrdenada);
    
        
    08.11.2016 / 02:43
    1

    To sort with one or more fields works like this, assuming 3 fields in your case are two.

    Lesson 1: As the number of fields increases, the number increases, and when it returns zero, it does not change position, this causes the item to move forward or backward in the collection

     1
     2
     3
     0
    -1
    -2
    -3
    

    Lesson 2 : Implement the java.lang.Comparable

    Implementing as needed, only from methodo

    @Override
    public int compareTo(Object object)
    {
        Conta bean = (Conta) object;
        int result=0;
        if (this.getId() < bean.getId())
        {
            result = -1;
        }
        else if (this.getNumero() < bean.getNumero)
        {
            result = -2;
        }
        else if (this.getDescricao() < bean.getDescricao())
        {
            result = -3;
        }else if (this.getId() > bean.getId())
        {
            result = 1;
        }
        else if (this.getNumero() > bean.getNumero)
        {
            result = 2;
        }
        else if (this.getDescricao() > bean.getDescricao())
        {
            result = 3;
        }
        return result;
    }
    

    Lesson 3: Treat conditions as you need them. then just use clean code

      

    Collections.sort (accounts);

        
    09.11.2016 / 22:40