Comparator - Priorityqueue

Asked

Viewed 223 times

3

I’m building a comparator to then use inside a Priorityqueue.

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

The object I want to sort is 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 order is supposed to be according to the following criteria:

  1. Those who have a number less than 4 must come
  2. Come those who start with the letter A
  3. Insertion order

This would give this ouput:

"A",2

"A",1

"B",3

"B",6

"A",5

Only I can only order by number.

public class ComparadorConta implements Comparator<Conta>{

 @Override
 public int compare(Conta a, Conta b) {

    return a.getNumero() - b.getNumero();
 }
}

Can anyone help me sort by these criteria? Thank you!

  • Just something expensive. To access the attribute numero you use a same method? numero()?

  • by chance until it was get number, already changed

  • In your example the final correct order would not be: "A",2 "B",3 "A",1 "A",5 "B",6?

2 answers

3


EDIT 1 - Com Priorityqueue

In case 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 the class Conta:

private static int ultimo = 0;

Create an attribute ordem which will be used internally:

private final int ordem;

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

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

Add the get country ordem:

public int getOrdem() {
  return ordem;
}

To make the comparison, you don’t need a Comparator, only that its class Conta implement the interface Comparable as follows:

public class Conta implements Comparable<Conta> {

You will need to implement the method compareTo which will look like the following, respecting the 3 rules imposed on 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 the items after the poll.

This will result in:

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

Sem Priorityqueue

I believe that using the Collections.sort and PriorityQueue is not the best choice because there already exists a structure with the requirement 3 which is the insertion order. The LinkedHashSet. I will put here two implementations and the test of both is carried out 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 the method toString next:

@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" have top 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 necessary to use PriorityQueue you can do the conversion below:

PriorityQueue pq = new PriorityQueue();
pq.addAll(listaOrdenada);
  • But what about criteria 1 and 3? The comparison between letters really works, but the one of numbers doesn’t seem to fit

  • Start with the number right? I did it backwards. But there’s the compareTo the number too

  • because that’s it, I need the 3 criteria. And this only gives the letters.

  • @Sorack It turns out that your code does not compare if it is less than 4, and also does not compare objects in the insertion order, as it should.

  • I changed it to match exactly what was asked

  • Thank you! But I really have to settle this with pride

  • You can give a Priorityqueue pq = new Priorityqueue(); pq.addAll(listOrdernada); to transform later

  • yes, but without using linkedhash it is supposed.

  • Check the Edit 1 with the implementation necessary for your problem to be solved with PriorityQueue

Show 4 more comments

1

To sort with one or more fields works like this, assuming 3 fields in your case is 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 back to the position in the collection

 1
 2
 3
 0
-1
-2
-3

Lesson 2: Implement the interface java.lang.Comparable

Making the implementation as necessary, only of the method

@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 the conditions as you need. then just use, clean code

Collections.Sort(accounts);

Browser other questions tagged

You are not signed in. Login or sign up in order to post.