Home > OS >  Comparator alternative , if 2 attributes have same value
Comparator alternative , if 2 attributes have same value

Time:09-15

Currently I am working on a scenario in which I have to find minimum Timestamp and have to print corresponding amount and second scenario is suppose If Timestamp of 2 data is same then I have to print timestamp and sum of both the amount. I am not able to achieve the second scenario through comparator. If you people have some solution or any alternative please let me know.

Code:

import java.util.Arrays;
import java.util.Comparator;
import java.util.List;
 
class Student {
    private String timestamp;
    private int amount;
 
    public Student(String timestamp, int amount) {
        this.timestamp = timestamp;
        this.amount = amount;
    }
 
    public String getTimestamp() {
        return timestamp;
    }
 
    public int getAmount() {
        return amount;
    }
 
    @Override
    public String toString() {
        return "Student{"  
                "timestamp='"   timestamp   '\''  
                ", amount="   amount  
                '}';
    }
}
 
public class Main
{
    public static void main(String[] args)
    {
        List<Student> students = Arrays.asList(
                new Student("2022-06-06 14:19:37.000", 25),
                new Student("2022-06-06 14:19:37.000", 15),
        );
 
        
 
        Comparator<Student> timestampComparator = Comparator
      .comparing(Student::getTimestamp);
    Student earliestDate = students.stream()
      .min(timestampComparator)
      .get();
    }
}

The expected output- 2022-06-06 14:19:37.000, 40

Output that I am getting- 2022-06-06 14:19:37.000, 25

CodePudding user response:

You don't need a Comparator, what you need is to group and aggregate the result.

Since you need actual dates, you should use java.time, the modern java date time API. For simplicity i'll use LocalDateTime and assume all students are in the same(default) timezone. Changed student class:

public class Student {

  private static final DateTimeFormatter FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss.SSS");

  private final LocalDateTime timestamp;
  private final int amount;

  public Student(String timestamp, int amount) {
    this.timestamp = LocalDateTime.parse(timestamp, FORMATTER);
    this.amount = amount;
  }

  public LocalDateTime getTimestamp() {
    return timestamp;
  }

  public int getAmount() {
    return amount;
  }
}

Note how i'm parsing the strings to LocalDateTime.

The actual grouping and aggregation of data;

public class Temp {

  public static void main(String[] args) {
    List<Student> students = Arrays.asList(new Student("2022-06-06 14:19:37.000", 25),
            new Student("2022-06-06 14:19:37.000", 15),
            new Student("2022-06-06 14:19:38.000", 15));
    Map.Entry<LocalDateTime, Integer> result = students.stream()
            .collect(Collectors.toMap(Student::getTimestamp, Student::getAmount, Integer::sum, TreeMap::new))
            .firstEntry();
    System.out.println(result.getKey()   ", "   result.getValue());
  }
}

I am collecting data into Map<LocalDateTime, Integer>, keys are timestamps, values are sums of amount for each student with this timestamp.

  1. Student::getTimestamp - function generating key for the map, by extracting the timestamp of the student.
  2. Student::getAmount - function generating value for the key, by extracting amount for the student.
  3. Integer::sum - merge function, handles key collisions(key already exists), the value is replaced by the current value new amount.
  4. TreeMap::new - function, supplying the map, where the data is collected. I am using TreeMap because it is sorted by the key and it's easy to extract the key/value pair with minimum key.

Refer to the docs of Collectors.toMap() for additional info.

CodePudding user response:

You need a second cycle to build the sum.

public static void main(String[] args)
{
    List<Student> students = Arrays.asList(
            new Student("2022-06-06 14:19:37.000", 25),
            new Student("2022-06-06 14:19:37.000", 15));

    Comparator<Student> timestampComparator = Comparator
            .comparing(Student::getTimestamp);
    Student earliestDate = students.stream()
            .min(timestampComparator)
            .get();
    int sum = students.stream()
            .filter(s-> earliestDate.getTimestamp().equals(s.getTimestamp()))
            .mapToInt(Student::getAmount).sum();
    Student sumStudent = new Student(earliestDate.getTimestamp(), sum);
    System.out.println(sumStudent);
}

CodePudding user response:

You want to first group by your timestamp and calculate the sum for each timestamp (if there's only a single item for this timestamp, the sum will be this item's value only). This doesn't require a comparator. Next, find the minimum timestamp and return the sum (this is where the comparator comes into play).

int value = students.stream()
  .collect(Collectors.groupingBy(Student::getTimestamp, Collectors.summingInt()))
  .entrySet()
  .stream()
  .min(Map.Entry.compareByKey())
  .map(Map.Entry::getValue)
  .findFirst()
  .orElse(0);
  • Related