英文:
Convert String to List of Map
问题
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";
List<Map<Integer, String>> outputList = Arrays.stream(esConnectionPropertiesStr.split("\\),\n"))
.map(e -> Arrays.stream(e.split(", "))
.map(s -> s.replace("$", "").replace("(", "").replace(")", "").trim())
.collect(Collectors.toList()))
.map(e -> {
Map<Integer, String> map = new HashMap<>();
map.put(1, e.get(0));
map.put(2, e.get(1));
map.put(3, e.get(2));
map.put(4, e.get(3));
map.put(5, e.get(4));
return map;
})
.collect(Collectors.toList());
Please note that the provided Java code is a direct translation of the given code and might not be the most efficient or idiomatic solution.
英文:
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??
答案1
得分: 1
`AtomicInteger` 在这里是多余的。它增加了更多的复杂性和更多的失败可能性。
此外,`Stream API` 的规范[不保证][1]会执行 `Stream::peek` 方法。
以下是朴素(尽管相当冗长)的解决方案:
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());
----------
虽然上面的解决方案可以工作,但在我看来它不易读。我会将 `list-to-map` 转换提取到一个静态实用方法中:
class Utils {
public static Map<Integer, String> toIndexedMap(List<String> list) {
return IntStream.range(0, list.size())
.boxed()
.collect(toMap(identity(), list::get));
}
然后按如下方式使用实用方法:
List<Map<Integer, String>> result =
Arrays.stream(esConnectionPropertiesStr.split("\\),"))
.map(row -> Arrays.stream(row.split(","))
.collect(collectingAndThen(toList(), Utils::toIndexedMap)))
.collect(toList());
[1]: https://stackoverflow.com/a/33636377/10584605
英文:
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());
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论