Dragon Dragon - 2 months ago 5
Java Question

How to group element in ArrayList and divide into three List

I have an entity class

class Entity {
private String customer;
private String product;
private String productDetail;
}


I have an
ArrayList<Entity>
including many records, for example record in my list:

customer product productDetail
A A1 A11
A A1 A12
A A2 A21
A A2 A22
B B1 B11
B B2 B21
C C1 C11
C C1 C12


I have 3 entities below

class ProductDetail{
private String details;
}

class Product{
private String product;
private List<ProductDetail> detailList;
}

class Customer{
private String customer;
private List<Product> productList;
}


I want to loop through my
ArrayList<Entity>
and group records into
Customer
class,
Customer
class includes
productList
, and
productList
includes
detailList
.

Please suggest me a solution.

Update my code:

Customer entity:

public class CustomerEntity {
private int customer;

private List<ProductEntity> productList;

public int getCustomer() {
return customer;
}

public void setCustomer(int customer) {
this.customer = customer;
}

public List<ProductEntity> getProductList() {
return productList;
}

public void setProductList(List<ProductEntity> productList) {
this.productList = productList;
}

}


Product Entity:

public class ProductEntity {

private int product;
private List<ProductDetailEntity> detailList;

public int getProduct() {
return product;
}

public void setProduct(int product) {
this.product = product;
}

public List<ProductDetailEntity> getDetailList() {
return detailList;
}

public void setDetailList(List<ProductDetailEntity> detailList) {
this.detailList = detailList;
}

}


Product detail entity:

public class ProductDetailEntity {
private int details;

public int getDetails() {
return details;
}

public void setDetails(int details) {
this.details = details;
}

}


My dummy code test:

public class TestList {
public static void main(String[] args) {
TestEntity testEntity;
List<TestEntity> list = new ArrayList<TestEntity>();

// Create Dummy Data
testEntity = new TestEntity();
testEntity.setCustomer("A");
testEntity.setProduct("A1");
testEntity.setProductDetail("A11");
list.add(testEntity);

testEntity = new TestEntity();
testEntity.setCustomer("A");
testEntity.setProduct("A1");
testEntity.setProductDetail("A12");
list.add(testEntity);

testEntity = new TestEntity();
testEntity.setCustomer("A");
testEntity.setProduct("A2");
testEntity.setProductDetail("A21");
list.add(testEntity);

testEntity = new TestEntity();
testEntity.setCustomer("A");
testEntity.setProduct("A2");
testEntity.setProductDetail("A22");
list.add(testEntity);

testEntity = new TestEntity();
testEntity.setCustomer("B");
testEntity.setProduct("B1");
testEntity.setProductDetail("B11");
list.add(testEntity);

testEntity = new TestEntity();
testEntity.setCustomer("B");
testEntity.setProduct("B2");
testEntity.setProductDetail("B21");
list.add(testEntity);

testEntity = new TestEntity();
testEntity.setCustomer("C");
testEntity.setProduct("C1");
testEntity.setProductDetail("C11");
list.add(testEntity);

testEntity = new TestEntity();
testEntity.setCustomer("C");
testEntity.setProduct("C1");
testEntity.setProductDetail("C12");
list.add(testEntity);

Map<String, List<TestEntity>> groupByCustomerMap = new LinkedHashMap<String, List<TestEntity>>();
List<TestEntity> tempEntityList;
TestEntity tempEntity;

// Group record by customer
for (TestEntity item : list) {
String customer = item.getCustomer();

tempEntityList = new ArrayList<TestEntity>();
tempEntity = new TestEntity();

tempEntity.setCustomer(customer);
tempEntity.setProductDetail(item.getProductDetail());
tempEntity.setProduct(item.getProduct());

tempEntityList.add(tempEntity);

if (!groupByCustomerMap.containsKey(customer)) {
groupByCustomerMap.put(customer, tempEntityList);
} else {
groupByCustomerMap.get(customer).addAll(tempEntityList);
}
}

// I think from groupByCustomerMap, read ProductDetail and group by product
// Pleaes suggest me next solution
}
}

Answer

I could propose next decision:

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.ToString;
import org.junit.Test;

import java.util.ArrayList;
import java.util.List;

/**
 * Created by smv on 19/09/16.
 */
public class MainTest {

    @AllArgsConstructor
    @ToString
    @Data
    class Entity {
        private String customer;
        private String product;
        private String productDetail;
    }

    @AllArgsConstructor
    @ToString
    @Data
    class ProductDetail{
        private String details;
    }

    @AllArgsConstructor
    @ToString
    @Data
    class Product{
        private String product;
        private List<ProductDetail> detailList;
    }

    @AllArgsConstructor
    @ToString
    @Data
    class Customer{
        private String customer;
        private List<Product> productList;
    }
    @Test
    public void run() throws Exception {
        ArrayList<Entity> entities = new ArrayList<>();
        entities.add(new Entity("A", "A1", "A11"));
        entities.add(new Entity("A", "A1", "A12"));
        entities.add(new Entity("A", "A2", "A21"));
        entities.add(new Entity("A", "A2", "A22"));
        entities.add(new Entity("B", "B1", "B11"));
        entities.add(new Entity("B", "B2", "B21"));
        entities.add(new Entity("C", "C1", "C11"));
        entities.add(new Entity("C", "C1", "C12"));

        ArrayList<Customer> customers = new ArrayList<>();
        entities.forEach(entity -> {
            Customer customer = customers.stream().filter(c -> c.getCustomer().equals(entity.getCustomer())).findFirst().orElse(new Customer(entity.getCustomer(), new ArrayList<>()));
            if (!customers.contains(customer)) {
                customers.add(customer);
            }
            Product product = customer.getProductList().stream().filter(p -> p.getProduct().equals(entity.getProduct())).findFirst().orElse(new Product(entity.getProduct(), new ArrayList<>()));
            if (!customer.getProductList().contains(product)) {
                customer.getProductList().add(product);
            }
            ProductDetail productDetail = product.getDetailList().stream().filter(pd -> pd.getDetails().equals(entity.getProductDetail())).findFirst().orElse(new ProductDetail(entity.getProductDetail()));
            if (!product.getDetailList().contains(productDetail)) {
                product.getDetailList().add(productDetail);
            }
        });

        customers.forEach(s -> System.out.println(s));
    }

}

I think it is not the best variant, but it's worked. I think there must be more elegant way to replace if in code.

UPD

Annotations on data beans it is Lombok lib annotations that provide the convenient way to declare a bean. It will work in java 7 too.

@AllArgsConstructor - adds the constructor with all fields.
@Data - generate getters/setters for all fields.
@ToString - add the method that returns the string representation of the bean.

Further syntax suitable for java 8 only. This is function List.forEach with the lambda expression, obviously, it iterates the list and can be replaced with for loop. Each data bean is found or created using the Java 8 stream API (filter with predicate expression) and Optional type (orElse). So this line:

Customer customer = customers.stream().filter(c -> c.getCustomer().equals(entity.getCustomer())).findFirst().orElse(new Customer(entity.getCustomer(), new ArrayList<>()));

can be replaced in java 7 with:

Customer customer = null;
for (Customer c: customers ) {
        if(c.getCustomer().equals(entity.getCustomer())) {
            customer = c;
            break;
        }
    }
if (customer == null) {
  customer  = new Customer(entity.getCustomer(), new ArrayList<>())
}

and so on..

Comments