StuartDTO
StuartDTO

Reputation: 1031

How can I group a List<Object> into another List<Object> by some attributes

I'm trying to group a List<Object> which contains

Exercice, type, User, passed, ..

There are more but those are the most important, the thing is that I'm getting a long list, so I want to group it by :

Type, User, NumberOfPassed, NumberOfFaileds

For instance I have :

Exercice1, hand, [email protected], true
Exercice2, hand, [email protected], false
Exercice3, hand, [email protected], false
Exercice4, hand, [email protected], false
Exercice2, hand, [email protected], true
Exercice1, hand, [email protected], true

And the output should be

Hand, [email protected], 1/4
Hand, [email protected], 2/2

Upvotes: 0

Views: 948

Answers (3)

Willi Mentzel
Willi Mentzel

Reputation: 29844

Given your data class looks like this:

data class UserData(
        val exercise: String,
        val type: String,
        val emailAddress: String,
        val passed: Boolean
)

You could first group by type and emailAddress using a Pair as key for the resulting map:

val groupingMap = l.groupBy{ it.type to it.emailAddress }

groupingMap will be of type: Map<Pair<String, String>, List<UserData>>

After that you can iterate over that map using forEach like this:

resultMap.forEach { (groupKey, list) ->
    val numElements = list.count()
    val numTrueElements = list.count { it.passed }
    val (type, emailAddress) = groupKey
    println("$type, $emailAddress, $numTrueElements/$numElements")
}

Result:

hand, [email protected], 1/4
hand, [email protected], 2/2

There might be better suited types for type and maybe even exercise (it depends on the use-case) but for the sake of the example I chose String.

Upvotes: 2

Bastida
Bastida

Reputation: 105

I think you could create this object to help you to solve this:

public class Result {
  private String type;
  private String email;
  private int numPassed;
  private Double total;

  public Result(String type, String email, boolean approved) {
      total = 1.0;
      this.type = type;
      this.email = email;
      this.numPassed = approved ? 1 : 0;
  }

  public void increase(boolean examResult){
      total++;
      if(examResult){
          numPassed++;
      }
  }

  public boolean isApproved(){
      return numPassed >= total / 2d;
  }

  public String getFraction(){
    return numPassed + "/" + total.intValue();
  }
}

And the algorithm to aggroup your list should be like this:

private static List<Result> group(List<Input> yourList) {
    List<Result> result = new ArrayList<>();

    for (Input i : yourList) {
        String type = i.getType();
        String email = i.getEmail();
        boolean approved = i.isApproved();
        Result r = getIfExists(result, type, email);

        if(r != null){
            result.remove(r);
            r.increase(approved);
        } else{
            r = new Result(type, email, approved);
        }

        result.add(r);
    }

    return result;
}

private static Result getIfExists(List<Result> results, String type, String email) {
    Result result = null;
    boolean exit = false;
    for (int i = 0; i < results.size() && !exit; i++) {
        Result r = results.get(i);
        if (r.getType().equals(type) && r.getEmail().equals(email)) {
            result = r;
            exit = true;
        }
    }
    return result;
}

This code won't compile since is not implemeting setter-getter but implemeting it will work.

Upvotes: 1

TheFnafException
TheFnafException

Reputation: 25

I think that You can use list> for grouping list of Objects to another list of Objects.

Upvotes: -1

Related Questions