Como somar items iguais em lista?

5 respostas
gtludwig

pessoal,

A entrada de dados para minha aplicação é um arquivo excel. Cada linha representa um objeto da classe Component, cuja definição é:

public class Component {

    private String id;
    private String partNumber;
    private String mcId;
    private Integer quantity;

    public Component() {
    }
    // getters e setters
    // hashcode e equals
    // toString()
}

Não tenho como controlar a geração desse arquivo excel e pode acontecer da lista de Component resultante seja algo assim:

Component [id=1, partNumber="A", quantity=5]
Component [id=2, partNumber="A", quantity=3]
Component [id=3, partNumber="B", quantity=2]
Component [id=4, partNumber=B", quantity=7]

Como que eu consigo garantir que a lista seja algo do tipo

Component [id=2, partNumber="A", quantity=8]
Component [id=3, partNumber="B", quantity=9]

O método que eu tentei usa para isso é assim:

private void eliminateDuplicateComponent() {
        // lista original
        List<Component> compList = componentList;

        // instanciação de mapa para organizar a lista de componentes
        Map<String, Component> componentMap = new HashMap<String, Component>();

        for (int i = 0; i < compList.size(); i++) {
            Component comp = compList.get(i);
            if (comp.getPartNumber().equals(
                    componentMap.containsKey(comp.getPartNumber()))) {
                Component c = componentMap.get(comp.getPartNumber());
                c.setQuantity(c.getQuantity() + comp.getQuantity());
            } else {
                componentMap.put(comp.getPartNumber(), comp);
            }
        }
        componentList = new ArrayList<Component>(componentMap.values());
    }

mas o retorno é:
Component [id=2, partNumber="A", quantity=3]
Component [id=3, partNumber="B", quantity=7]

alguma idéia de como fazer isso?

Grato,
Gustavo

5 Respostas

nel

Oi!

Algo em que eu pensei rapidamente, é fazer sua classe Component implementar o Comparator, sendo que faça a avaliação a partir do campo partNumber, já que pelo o que eu entendi, é ele que repete e é partir dele que tu deseja “agrupar”.

Feito isso, você usa Collections.sort(suaLista, new Component()) e terás sua lista organizada. A partir disso, você sabe que os itens repetidos estarão em sequencia, agora, use um objeto Iterator para percorrer sua lista.

Bom, agora você pode realizar a comparação e caso seja igual, soma o valor e remove ela, sempre a próxima, ou seja, a primeira vez em que repete o valor.
O Iterator permite você remover um objeto da lista em que ele está percorrendo.

Dá para melhor bastante essa implementação, estou dizendo meio na pressa, se eu tiver mais tempo paro e penso em algo mais apresentável.
Abraços.

gilmaslima

Você já pensou em implementar a interface Comparator na sua classe Component?

xandevieira

eu faria algo ± assim.

for (int i = 0; i < compList.size(); i++) { Component comp = compList.get(i); String chave = comp.getPartNumber(); if (componentMap.get(chave) == null) { componentMap.put(chave, comp); } else { componentMap.get(chave).setQuantity(componentMap.get(chave).getQuantity() + comp.getQuantity()); } }

gtludwig

@nel, @gilmaslima,
A idéia do Comparator parece bem interessante. Mas eu não conheço essa interface, tenho que dar uma olhada.

@avsouza,
hmm, parece interessante! vou ver se funciona!

nel

Oi!

Creio que isso seja a sua solução, a mais rápida, a melhor? É outra história, mas acredito que resolva sim seu problema:

List<Component> components = new ArrayList<Component>();
		components.add(new Component("1", "A", 5));
		components.add(new Component("2", "B", 2));
		components.add(new Component("3", "A", 3));
		components.add(new Component("4", "C", 5));
		components.add(new Component("5", "B", 4));
		
		Collections.sort(components, new Component());
		
		Map<String, Component> map = new HashMap<String, Component>();
		for(Component c : components) {
			String key = c.getPartNumber();
			if(!map.containsKey(key)) {
				map.put(c.getPartNumber(), c);
			} else {
				Component comp = map.get(key);
				Integer quantity = comp.getQuantity() + c.getQuantity();
				comp.setQuantity(quantity);
			}
		}
		
		for(String key : map.keySet()) {
			Component c = map.get(key);
			System.out.println("Id: " + c.getId());
			System.out.println("PartNumber: " + c.getPartNumber());
			System.out.println("Quantity: " + c.getQuantity());
			System.out.println("##########################################");
		}

Implementando o Comparator...

class Component implements Comparator<Component> {
	private String id;  
    private String partNumber;
    private Integer quantity;
    
    public Component() {}
    
    public Component(String id, String partNumber, Integer quantity) {
    	this.id = id;
    	this.partNumber = partNumber;
    	this.quantity = quantity;
    }
    
	public String getId() {
		return id;
	}
	
	public String getPartNumber() {
		return partNumber;
	}
	
	public Integer getQuantity() {
		return quantity;
	}
	
	public void setQuantity(Integer quantity) {
		this.quantity = quantity;
	}
	
	@Override
	public int compare(Component o1, Component o2) {
		return o1.getPartNumber().compareToIgnoreCase(o2.getPartNumber());
	} 
}

Dois detalhes:

1 - Eu criei no construtor os sets e ainda criei um método set no Quantity só para agilizar o exemplo pra você, atente-se mais a lógica e como foi feito o comparator.
2 - O resultado do comparator ignora case sensitive, veja se pode ou não, ai é questão de você analisar.

Abraços.

Criado 22 de julho de 2011
Ultima resposta 22 de jul. de 2011
Respostas 5
Participantes 4