3
CircuitID   Department  Hours

--------------------------------

Circuit A   Electricity      60

Circuit A   Hydel            70

Circuit B   Hydel            30

Circuit C   Electricity      40

Circuit B   Electricity      80

Circuit C   Hydel            50

Circuit A   Electricity      70

Now i have to create one list which will have records on following criteria:

  1. In each circuit id i need to get the record with highest hours but if duplicate hours are present than i need to take the one with Electricity department.

Result for the above result should be like below:

Circuit A  Electricity   70

Circuit B  Electricity   80

Circuit C  Hydel          50

Let me know how can i iterate effectively and in most efficient way to get the final list using java 8/ java.

The code i wrote is not at all working perfectly and my approch was shown below:

for (int i = 0; i < circuitList.size(); i++) {

  for (int j = 0; j < circuitList.size(); {
    if (circuitList.get(i).getCircuitId().equals(circuitList.get(j).getCircuitId()) && i != j) {



     if (circuitList().get(i).getHours() == circuitList().get(j).getHours()) {



      if (circuitList().get(i).getDepartment().equals(“Electricity”) {



        newList.add(circuitList().get(i));

        }

        // some more conditions on getHours

Circuit class is having pojo objects with getter setters of this three objects.

 public class Circuit {

        String circuitID;
        int hours;
        String department;
}
ash das
  • 887
  • 7
  • 11
  • Please, show what the `Circuit` class looks like. Also, it'd be nice if you corrected typos like `getCircuitId`, `getCircuitId()`, `“Electricity”`, `circuitList()` along with indents and closing braces – Andrew Tobilko May 26 '19 at 09:48
  • 3
    Use a `groupingBy` to `collect` by circuit. Use a downstream of `maxBy` with a collector sorting first on hours then on type. – Boris the Spider May 26 '19 at 12:12

4 Answers4

3

You can do it by toMap() collectors with merge function.

Map<String, Circuit> map = circuitList
             .stream()
             .collect(Collectors.toMap(Circuit::getCircuitID, Function.identity(),merge));

and merge function is:

BinaryOperator<Circuit> merge = (left, right) -> {
        if (left.hours > right.hours) return left;
        else if (left.hours < right.hours) return right;
        //if (left.department.equals("Electricity")) return left;
        if (right.department.equals("Electricity")) return right;
        return left;
};

and get final result:

List<Circuit> result = new ArrayList<>(map.values());
Hadi J
  • 16,989
  • 4
  • 36
  • 62
  • 2
    You can remove the `if (left.department.equals("Electricity")) return left;` check altogether. – daniu May 26 '19 at 13:11
  • Why not just `maxBy`? – Boris the Spider May 27 '19 at 08:48
  • @BoristheSpider, Yeah I thought about it too. `Comparator comparator = Comparator.comparing(Circuit::getHours) .thenComparingInt(circuit -> circuit.circuitID.equals("Electricity")?1:-1);` and then `Map> map = circuitList .stream() .collect(Collectors.groupingBy(Circuit::getCircuitID,Collectors.maxBy(comparator)));` – Hadi J May 27 '19 at 09:51
  • Your comparator is wrong as it never returns `0` - but yeah, something like that. – Boris the Spider May 27 '19 at 10:40
  • When i tried your solution i get List as `[CircuitProblem.Circuit@1a71e93, CircuitProblem.Circuit@6cbb7a, CircuitProblem.Circuit@3df479]` , i can get them in correct format when i override toString() in my Circuit class, but is there a way i can do it without overriding .toString() ?? – Joka Lee May 27 '19 at 12:24
  • 1
    @Joka Lee `result.forEach(circuit->System.out.printLn("[CircuitID: "+circuit.circuitID+ " Department :" + circuit.department + " Hours : "+ circuit.hours +"]"));` – Hadi J May 27 '19 at 12:32
  • In previous many answers you have used function.identity() , what is the advantage of it over s->s ?? Any resource ?? – Joka Lee May 27 '19 at 12:47
  • @JokaLee, I think it is more readable than `s->s`, see [this](https://stackoverflow.com/questions/28032827/java-8-lambdas-function-identity-or-t-t) – Hadi J May 27 '19 at 12:50
3

First write a custom comparator to check for highest hours and evaluate duplicate hours situation to take the one with Electricity department:

Comparator<Circuit> cmp = new Comparator<Circuit>() {
    @Override
    public int compare(Circuit o1, Circuit o2) {
        
        int compare = Integer.compare(o1.getHours(), o2.getHours());
        
        if(compare==0) {  // equal hours so check for department

            // the element with 'Electricity' value must seem to be have max value
            if(o1.getDepartment().equals("Electricity")) {
                compare = 1;
            }
            if(o2.getDepartment().equals("Electricity")) {
                compare = -1;
            }
        }
        
        return compare;
    }
};

Then group by circuitId attribute with Collectors.groupingBy(Circuit::getCircuitId, and find max hours with the help of custom comparator above Collectors.maxBy(cmp):

Map<String, Optional<Circuit>> resultMap = circuitList.stream().collect(
                Collectors.groupingBy(Circuit::getCircuitId, Collectors.maxBy(cmp)));
Collection<Optional<Circuit>> result = resultMap.values();
result.forEach(x -> System.out.println(x.get().getCircuitId() + "  " + x.get().getDepartment() + "\t" + x.get().getHours()));
Hülya
  • 3,353
  • 2
  • 12
  • 19
2
public static Map<String, Circuit> getMaxHours(final List<Circuit> circuitsList) {
    final Map<String, Circuit> mappedCircuitsById = new HashMap<String, Circuit>();

    for (final Circuit circuit : circuitsList) {
        if (!mappedCircuitsById.containsKey(circuit.getCircuitID())) {
            mappedCircuitsById.put(circuit.getCircuitID(), circuit);
        } else {
            final Circuit existingMax = mappedCircuitsById.get(circuit.getCircuitID());
            if (circuit.getHours() > existingMax.getHours()) mappedCircuitsById.put(circuit.getCircuitID(), circuit);
            else if (circuit.getHours() == existingMax.getHours()) {
                if (circuit.getDepartment().equals("Electricity")) mappedCircuitsById.put(circuit.getCircuitID(), circuit);
                else if (existingMax.getDepartment().equals("Electricity")) mappedCircuitsById.put(circuit.getCircuitID(), existingMax);
            }
        }
    }

    return mappedCircuitsById;
}

Create a map where the key of the map is the circuitID and the value is the Circuit object which meets the "max hours" requirements. Iterate over the elements of the list and and update the map accordingly to store the new "max hours" Circuit object

1

We have to group by CircuitID first and write custom comparator to filter based on our requirement. It can be done as shown below:

List<Circuits> filteredList = new ArrayList<>();
list.stream().collect(Collectors.groupingBy(Circuits::getCircuitID)).forEach((key, value) -> filteredList.add(compare(value)));


private static Circuits compare (List<Circuits> list) {
    Circuits circuits = null;
    for (Circuits c : list) {
        if (null == circuits) {
            circuits = c;
        }
        if (c.getHours() > circuits.getHours()) {
            circuits = c;
        } else if (c.getHours() == circuits.getHours()) {
            circuits = c.getDepartment().equalsIgnoreCase("Electricity") ? c : circuits;
        }
    }
    return circuits;
}