2
    class Employee{
      private Integer employeeId;
      private Integer projectId;
      private String mobileNumbers;
    }

I want to convert List of employees to Map of projectId & mobile numbers. Mobile numbers can have multiple values comma separated(eg: mobileNumbers="7364567347,5784345445")

I want to split mobile number with partition of 100. Hence the value datatype is Set<Set>

Two things which I am not able to achieve in Java 8 using stream 1.Not able to split multiple mobileNumber as individual element in Set object. 2.Not able to partition

Eg:

  Employee[employeeId=1,projectId=1,mobileNumbers="1111,2222"]
  Employee[employeeId=2,projectId=1,mobileNumbers="33333"]
  Employee[employeeId=3,projectId=2,mobileNumbers="44444,5555"]

Expected : {1=[["1111","2222","33333"]], 2=[["44444","5555"]]}

I am able to proceed till Map<ProjectId,Set>. I am not able to split mobileNumbers

Map<Integer,Set<String>> result2=employeeList.stream()
         .collect(
          Collectors.groupingBy(Employee::getProjectId,
              Collectors.mapping(Employee::getMobileNumbers, Collectors.toSet()))
      );

Two things which I am not able to achieve in Java 8 using stream 1.Not able to split multiple mobileNumber as individual element in Set object. 2.Not able to partition `

1
  • The groupBy looks pretty much correct. All you need to do now is split the phone numbers (try using String.split) and then combining the collection of arrays into one set (probably using some kind of flatMap) Commented Jun 13, 2023 at 11:31

4 Answers 4

1

As always with this type of question, the imperative approach is much easier to read and reason about:

        Map<Integer, Set<String>> result = new HashMap<>();
        for (Employee employee : employeeList) {
            Set<String> set = result.result.computeIfAbsent(employee.getProjectId(), id -> new HashSet<>());
            set.addAll(Arrays.asList(employee.getMobileNumbers().split(",")));
        }

Once you understand this approach, you may even be able to turn it into a functional pipeline. But if you want this code to be maintainable, you probably shouldn't.

Sign up to request clarification or add additional context in comments.

Comments

0

To use streams only, you need the flatMapping method, which was not added until Java 9. This answer has a starting point, and then you need code like this:

Map<Integer,Set<String>> result2 = employeeList.stream()
    .collect(Collectors.groupingBy(
        Employee::getProjectId,
        flatMapping(
            e -> Arrays.stream(e.getMobileNumbers().split(",")),
            Collectors.toSet())));

Comments

0

You need to split the grouped values and flatmap into Set in the downstream collector:

Map<Integer, Set<String>> result2 = employeeList.stream()
    .collect(Collectors.groupingBy(Employee::getProjectId,
        Collectors.mapping(Employee::getMobileNumbers,
            Collectors.flatMapping(s -> Arrays.stream(s.split(",")), 
                Collectors.toSet()))));
{1=[33333, 1111, 2222], 2=[44444, 5555]}

Comments

0

If I understand correctly, you want to have a Map<Integer, Set<Set<String>>>, and not a Map<Integer, Set<String>> as in the previous solutions. In my opinion, making the partitions using Streams makes the code illegible. Thus, I'd resort to an additional function to check the set conditions. To construct the example, I chose three as the maximum number of elements in a set, so you must adjust the answer according to your needs.

   final List<Employee> employees = Arrays.asList(
                new Employee(1, 1, "1111,2222"),
                new Employee(2, 1, "33333,4444"),
                new Employee(3, 2, "44444,5555")
        );

        final Map<Integer, Set<Set<String>>> idToNumberPartitions = employees.stream()
                .collect(Collectors.groupingBy(
                        Employee::getProjectId,
                        Collector.of(
                                HashSet::new,
                                (set, employee) -> addNumbersToPartition(set, employee.getMobileNumbers().split(",")),
                                (set1, set2) -> {
                                    set1.addAll(set2);
                                    return set1;
                                }
                        )
                ));


    }

    private static void addNumbersToPartition(final Set<Set<String>> allSets, final String[] numbers) {
        Set<String> currentSet = null;
        for (final String number : numbers) {
            if (currentSet == null || currentSet.size() >= 3) {
                currentSet = new HashSet<>();
                allSets.add(currentSet);
            }
            currentSet.add(number);
        }
    }
}

For the example above, this prints:

{1=[[1111, 2222], [33333, 4444]], 2=[[44444, 5555]]}

Consult the docs to find out more about the custom Collector:

    public static<T, R> Collector<T, R, R> of(Supplier<R> supplier,
                                              BiConsumer<R, T> accumulator,
                                              BinaryOperator<R> combiner,
                                              Characteristics... characteristics)

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.