Remove duplicate objects from List<Minhaclasse>

Asked

Viewed 7,797 times

3

Guys is the following, I have a model class with attributes that store data returned from the database. For example:

public class RelacaoTransformacao {
    /** ID do registro no banco de dados. */
    private long id;
    /** Indica se o teste já foi concluído. */
    private boolean concluido;
    /** O valor do teste. */
    private double valor;
    // ...O restante do código.
}

Taking the code below as an example:

// Percorre o cursor obtendo todos os dados e criando um objeto com os dados retornados.
            while ( result.moveToNext() ) {
                long id = result.getLong( result.getColumnIndex( br.com.bhdnet.softencal.app.database.enums.RelacaoTransformacao.COLUNA_ID.texto ) );
                boolean concluido = result.getInt( result.getColumnIndex( br.com.bhdnet.softencal.app.database.enums.RelacaoTransformacao.COLUNA_CONCLUIDO.texto ) ) > 0 ;
                double valor = result.getDouble( result.getColumnIndex( br.com.bhdnet.softencal.app.database.enums.RelacaoTransformacao.COLUNA_VALOR.texto ) );
                int polaridade = result.getInt( result.getColumnIndex( br.com.bhdnet.softencal.app.database.enums.RelacaoTransformacao.COLUNA_POLARIDADE.texto ) );
                String observacao = result.getString( result.getColumnIndex( br.com.bhdnet.softencal.app.database.enums.RelacaoTransformacao.COLUNA_OBSERVACAO.texto ) );
                long idPrimario = result.getLong( result.getColumnIndex( br.com.bhdnet.softencal.app.database.enums.RelacaoTransformacao.COLUNA_FK_ENROLAMENTO_TCTP_ID1.texto ) );
                long idSecundario = result.getLong( result.getColumnIndex( br.com.bhdnet.softencal.app.database.enums.RelacaoTransformacao.COLUNA_FK_ENROLAMENTO_TCTP_ID2.texto ) );
                String primario = result.getString( result.getColumnIndex( br.com.bhdnet.softencal.app.database.enums.EnrolamentoTcTp.COLUNA_ENROLAMENTO.texto ) );
                primario += String.valueOf( result.getInt( result.getColumnIndex( br.com.bhdnet.softencal.app.database.enums.EnrolamentoTcTp.COLUNA_NUMERO_ENROLAMENTO.texto ) ) );

                RelacaoTransformacao relacaoTransformacao = new RelacaoTransformacao( id, concluido, valor, polaridade, observacao, idPrimario, idSecundario, primario, null );
                // Adiciona o objeto enrolamento a lista de enrolamentos
                listRelacaoTransformacao.add( relacaoTransformacao );
            }

I will always have two repeated objects on my list by the ID attribute, this due to my database search (I don’t need to explain this search, just understand that I really need to return two repeated records, because in a repeat record column the value will be different and I need to get this value). How do I get one of these objects repeated by ID and then remove it from the list?

  • Which criteria you use to know which of the objects you will remove?

  • Reframing the @Math question (which can be interpreted as asking about the duplication criterion, which is two objects having the same ID): assuming there are two objects with the same ID, which of the two should be removed? Anyone?

  • It cannot be anyone. What must be removed must be the second object. Only before I remove I’ll take a certain attribute from it, and set on the first object, then after that I can remove it.

2 answers

7

Use a class that implements a set (Set), as Treeset. Provide a Comparator in the constructor that uses the ID.

The classes that implement Set only allow distinct elements, using as a parameter the fields used in the Comparator.

  • 1

    If the order of the elements in the list doesn’t matter, this is the simplest solution. Insert elements into a Set (set), in which elements are not repeated.

  • @utluiz, based on my comment on my question that says the object to be removed will always be the second and I need to take an attribute of it before removing it, what is the best implementation for my problem? Your or the user’s Math. From your point of view.

  • 2

    @Lucassantos If you want to get data from the repeated elements, then you will have to implement a solution like @Math. However, his algorithm is complex O(n²), that is, he compares all with all. This could be optimized for O(log(n)) using two variables i and j in for’s and always starting j with i + 1.

  • @Piovezan, does a set set not leave the ordered elements? Not even if I insert them within the set in the order?

  • @Lucassantos If it’s a Linkedhashset, can be iterated by the elements in the order in which they were inserted.

  • Thanks Piovezan. @utluiz thanks for the tip and reply, I understood what you said but ask. Will it make a lot of difference in performance? I say this because the list will probably have only 6 elements on rare occasions. If there are 6 elements then we have 6x2 because it has the repetitions. Advise me to use it anyway i and j instead of for each?

  • 2

    @For 6 elements it is not worth optimizing the algorithm.

  • Thank you very much for the reply @utluiz and @ Piovezan. As the answer I will use will be the @Math , then I will mark it as accepted. But if I could I would mark them both because they both added knowledge to me.

  • @Lucassantos No problem, the important thing is you have understood.

  • @utluiz really had to do as you said here in comment, regarding optimization... You said: Isso poderia ser otimizado para O(log(n)) usando duas variáveis i e j nos for's e sempre iniciando j com i + 1. I really had to do it like this and add a little bit more to improve the optimization even more. And not only was it a matter of optimization, but @Math’s way got a logic error that didn’t work in my case. His reply was edited with the correct code.

Show 5 more comments

6


You can do one inside the other by going through the list and storing in different variables each object in the list, then you compare the id, if the id is the same and it is not the same object you enter into your logic of choosing which of the two should be removed.

Add these elements that should be removed in a separate list to remove them after checking inside the Fors.

Example:

public class LucasSantos {
    public static void main(String[] args) {
        List<RelacaoTransformacao> listRelacaoTransformacao = new ArrayList<>(); 
        List<RelacaoTransformacao> listEliminar = new ArrayList<>(); 
        listRelacaoTransformacao.add(new RelacaoTransformacao(1, true, 2));
        listRelacaoTransformacao.add(new RelacaoTransformacao(1, true, 5));
        listRelacaoTransformacao.add(new RelacaoTransformacao(2, true, 5));
        listRelacaoTransformacao.add(new RelacaoTransformacao(2, true, 1));
        System.out.println("Antes");
        for(RelacaoTransformacao r: listRelacaoTransformacao) {
            System.out.println(r);
        }

        // Faz um for percorrendo os itens da lista. Para cada item da lista percorrido, faz um outro for para percorrer todos os itens da lista novamente (Pulando o primeiro item do for externo)
        // para verificar qual objeto tem id igual ao objeto do for mais externo e se são objetos diferentes.
        for ( int i = 0; i < listRelacaoTransformacao.size(); i++ ) {
            for ( int j = i + 1; j < listRelacaoTransformacao.size(); j++ ) {
                // Se os objetos tiverem o mesmo id mas forem objetos diferentes, entao pegamos o campo primario do segundo objeto e o colocamos no campo secundario da primeiro objeto.
                // Adicionamos o segundo objeto na lista para eliminação de objetos repetidos.
                if ( listRelacaoTransformacao.get( i ).getId() == listRelacaoTransformacao.get( j ).getId() &&
                    !( ( (Object) listRelacaoTransformacao.get( i ) ).equals( listRelacaoTransformacao.get( j ) ) )  ) {

                    // Aqui você faz o que quiser.
                    i++; // Incrementa i em 1 para evitar verificações desnecessárias.
                    break;
                }
            }
        }
        //elimina todos os elementos que foram marcados para remoção
        listRelacaoTransformacao.removeAll(listEliminar);
        System.out.println("Depois");
        for(RelacaoTransformacao r: listRelacaoTransformacao) {
            System.out.println(r);
        }
    }
}

Exit:

Before
Relacaotransformacao [id=1, concluido=true, valor=2.0]
Relacaotransformacao [id=1, concluido=true, valor=5.0]
Relacaotransformacao [id=2, concluido=true, valor=5.0]
Relacaotransformacao [id=2, concluido=true, valor=1.0]
Relacaotransformacao [id=3, concluido=true, valor=2.0]
Afterward
Relacaotransformacao [id=1, concluido=true, valor=2.0]
Relacaotransformacao [id=2, concluido=true, valor=1.0]

Observing: whenever comparing objects overwrites the equals() method, and if you are working with Set overwrites also the hashcode(). The List interface does not use the hashcode() method however the documentation itself recommends you always overwrite it when overwriting the equals. The Object class documentation says:

equals(): Note that it is generally necessary to override the hashcode method Whenever this method is overridden, so as to maintain the general Contract for the hashcode method, which States that Equal Objects must have Equal hash codes.

In free translation:

equals(): Note that it is generally necessary to overwrite the hashcode method whenever this method is overwritten, as this keeps the hashcode method contract, which says that equal objects must have equal hash codes.

More information than the hashcode method() :

How important it is to implement the hashcode method in Java?

Documentation: equals(), Class Object - Java SE 7

Browser other questions tagged

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