Java Stream : Group List using multiple type in class

1k views Asked by At

I have different set of data like below and Now I want to group by ClientId+EffDate+Seccode

    List<Transaction> list = new  ArrayList<Transaction>();


    for (int i=0; i <= 10 ; i++){
        Transaction txn = new Transaction();

        txn.setClientId(i);
        txn.setEffDate("11/11/201"+i);
        txn.setSecCode("PPD");
        list.add(txn);
    }
    for (int i=5; i <= 10 ; i++){
        Transaction txn = new Transaction();

        txn.setClientId(i);
        txn.setEffDate("11/11/201"+i);
        txn.setSecCode("PPD");
        list.add(txn);
    }

I want to get data using below criteria

ClientId+EffDate+Seccode get list of transactions

I am trying to do using below incomplete code

 Function<Transaction, List<Object>> keyExtractor = wr ->Arrays.<Object>asList(wr.getClientId(), wr.getEffDate(), wr.getSecCode());

 Map<List<Object>, String> aggData = list.stream().collect(Collectors.groupingBy(keyExtractor).....

Any help is greatly appreciated

2

There are 2 answers

0
user7358330 On BEST ANSWER

I have solved this issue using below code.

    Test data
    ---------

     List<Transaction> list = new  ArrayList<Transaction>();


    for (int i=0; i <= 10 ; i++){
        Transaction txn = new Transaction();

        txn.setClientId(i);
        txn.setEffDate("11/11/201"+i);
        txn.setSecCode("PPD");
        list.add(txn);
    }
    for (int i=0; i <= 5 ; i++){
        Transaction txn = new Transaction();

        txn.setClientId(i);
        txn.setEffDate("11/11/201"+i);
        txn.setSecCode("PPD");
        list.add(txn);
    }


    solution
    --------
    Map<Key, List<Transaction>> map = list.stream().collect(Collectors.groupingBy(Transaction::getKey));

    for (Key key : map.keySet()){
        System.out.println( "key effect ="+ key.getEffdate() + ", sec code =" +key.getSecCode() + " , client id ="+ key.getClientId());
        for( Transaction txn : map.get(key)){
            System.out.println( txn.getEffDate() + " "+ txn.getSecCode() + " " + txn.getClientId());
        }

    }


     Transaction.java 
     ----------------
     public class Transaction {

private int clientId;

private String secCode;

private String effDate;

public int getClientId() {
    return clientId;
}

public void setClientId(int clientId) {
    this.clientId = clientId;
}

public String getSecCode() {
    return secCode;
}

public void setSecCode(String secCode) {
    this.secCode = secCode;
}

public String getEffDate() {
    return effDate;
}

public void setEffDate(String effDate) {
    this.effDate = effDate;
}



@Override
public int hashCode() {
    final int prime = 31;
    int result = 1;
    result = prime * result + clientId;
    result = prime * result + ((effDate == null) ? 0 : effDate.hashCode());
    result = prime * result + ((secCode == null) ? 0 : secCode.hashCode());
    return result;
}

@Override
public boolean equals(Object obj) {
    if (this == obj)
        return true;
    if (obj == null)
        return false;
    if (getClass() != obj.getClass())
        return false;
    Transaction other = (Transaction) obj;
    if (clientId != other.clientId)
        return false;
    if (effDate == null) {
        if (other.effDate != null)
            return false;
    } else if (!effDate.equals(other.effDate))
        return false;
    if (secCode == null) {
        if (other.secCode != null)
            return false;
    } else if (!secCode.equals(other.secCode))
        return false;
    return true;
}


public Key getKey() {
    return new Key(clientId, secCode,effDate);
}

class Key {

    public int getClientId() {
    return clientId;
}

public void setClientId(int clientId) {
    this.clientId = clientId;
}


    private int clientId;

    private String secCode;

    private String effdate;


    public Key(int clientId, String secCode,String effdate) {
        this.clientId = clientId;
        this.secCode = secCode;
        this.effdate = effdate;

    }

    public String getSecCode() {
        return secCode;
    }

    public void setSecCode(String secCode) {
        this.secCode = secCode;
    }

    public String getEffdate() {
        return effdate;
    }

    public void setEffdate(String effdate) {
        this.effdate = effdate;
    }


    @Override
    public int hashCode() {
        final int prime = 31;
        int result = 1;
        result = prime * result + clientId;
        result = prime * result + ((effdate == null) ? 0 : effdate.hashCode());
        result = prime * result + ((secCode == null) ? 0 : secCode.hashCode());
        return result;
    }


    @Override
    public boolean equals(Object obj) {
        if (this == obj)
            return true;
        if (obj == null)
            return false;
        if (getClass() != obj.getClass())
            return false;
        Key other = (Key) obj;
        if (clientId != other.clientId)
            return false;
        if (effdate == null) {
            if (other.effdate != null)
                return false;
        } else if (!effdate.equals(other.effdate))
            return false;
        if (secCode == null) {
            if (other.secCode != null)
                return false;
        } else if (!secCode.equals(other.secCode))
            return false;
        return true;
    }





}
0
pscuderi On

As far as I can tell you are trying to accomplish one of the following:

  1. Group Transactions by a single attribute (e.g., client ID); or
  2. Group Transactions by all attributes

(1) To group by a single attribute I suggest using a classifier that maps to the key you want (e.g., Transaction::getClientId). For example:

Map<Integer, List<Transaction>> byClientId = list.stream()
    .collect(Collectors.collectingAndThen(Collectors.groupingBy(Transaction::getClientId), Collections::unmodifiableMap));

System.out.println(byClientId.entrySet().stream()
    .sorted(Map.Entry.comparingByKey())
    .map(e -> e.getKey().toString() + ": " + e.getValue().stream()
        .map(Object::toString)
        .collect(Collectors.joining(", ")))
    .collect(Collectors.joining("\n")));

(2) To group by all attributes I suggest using the identify function as your classifier and remembering to override Object::equals. For example:

Map<Transaction, List<Transaction>> byTransaction = list.stream()
    .collect(Collectors.collectingAndThen(Collectors.groupingBy(Function.identity()), Collections::unmodifiableMap));

System.out.println(byTransaction.entrySet().stream()
    .sorted(Map.Entry.comparingByKey(Comparator.comparing(Transaction::getClientId)
        .thenComparing(Transaction::getEffDate)
        .thenComparing(Transaction::getSecCode)))
    .map(e -> e.getKey().toString() + ": " + e.getValue().stream()
        .map(Object::toString)
        .collect(Collectors.joining(", ")))
    .collect(Collectors.joining("\n")));