0

I have a following String. I want to convert it into List of Map as below,

String esConnectionPropertiesStr = "ID1, 701, REST, 0, $PROJECT_ID),\n" +
               "ID2, 702, ES_USERNAME, 0, $PROJECT_ID),\n" +
               "ID3, 703, ES_PASSWORD, 0, $PROJECT_ID),\n" +
               "ID4, 704, ES_HOST, 0, $PROJECT_ID";

Output:

[ 
    {1=ID1, 2=701, 3= ES_USERNAME, 4= 0, 5= $PROJECT_ID}, 
    {1=ID2, 2=702, 3= ES_PASSWORD, 4= 0, 5= $PROJECT_ID},
    {1=ID3, 2=703, 3=ES_HOST, 4= 0, 5= $PROJECT_ID},
    {1=ID4, 2=704, 3= ES_PORT, 4= 0, 5=$PROJECT_ID} 
]

It is spliting by ), and then by comma to get map elements. I tried following which works,

AtomicInteger index = new AtomicInteger(0);
Arrays.stream(esConnectionPropertiesStr.split("\\),"))
        .map(e -> Arrays.stream(e.split(","))
                .collect(Collectors.toMap(n1 -> index.incrementAndGet(), s -> s)))
        .peek(i -> index.set(0))
        .collect(Collectors.toList());

Is there any better way to do this??

Vikas
  • 6,868
  • 4
  • 27
  • 41
  • 1
    Does this answer your question? [Is there a concise way to iterate over a stream with indices in Java 8?](https://stackoverflow.com/questions/18552005/is-there-a-concise-way-to-iterate-over-a-stream-with-indices-in-java-8) – samabcde Apr 08 '20 at 14:32
  • Could you explain what is the difference that you are looking other than from the existing questions? – Naman Apr 09 '20 at 08:08
  • The existing question that might look duplicate has simple String which could be easily converted to Map. In my question, I have split String by `),` to get list elements and by a comma to get map elements. I have added what I tried but just thought that this could be improved. – Vikas Apr 09 '20 at 09:40
  • Can you explain the use-case for having a `List>` data structure here? If anything else, let's see if we can reduce this to something simpler. – quantum Apr 09 '20 at 14:44

1 Answers1

1

The AtomicInteger is redundant here. It adds more complexity and more room for failure. Moreover the specification of Stream API does not guarantee the execution of Stream::peek.

This is the naive (though pretty long) solution:

List<Map<Integer, String>> resultMap =
        Arrays.stream(esConnectionPropertiesStr.split("\\),"))
              .map(row -> Arrays.stream(row.split(","))
                                .collect(collectingAndThen(toList(), 
                                         list ->IntStream.range(0, list.size())
                                                         .boxed()
                                                         .collect(toMap(identity(), list::get)))))
              .collect(toList());

Although the solution above works, IMHO it isn't readable. I would extract the list-to-map conversion into a static util method:

class Utils { // 
    public static Map<Integer, String> toIndexedMap(List<String> list) {
        return IntStream.range(0, list.size())
                        .boxed()
                        .collect(toMap(identity(), list::get));
}

then use the utility methods as follow:

List<Map<Integer, String>> result =
        Arrays.stream(esConnectionPropertiesStr.split("\\),"))
              .map(row -> Arrays.stream(row.split(","))
                                .collect(collectingAndThen(toList(), Utils::toIndexedMap)))
              .collect(toList());
ETO
  • 6,970
  • 1
  • 20
  • 37