У меня есть строка, как показано ниже:
String data = "010$$fengtai,010$$chaoyang,010$$haidain,027$$wuchang,027$$hongshan,027$$caidan,021$$changnin,021$$xuhui,020$$tianhe";
И я хочу преобразовать его в карту типа Map<String,List<String>>
(как показано ниже), выполнив следующие шаги:
,
, а затем на $$
;$$
будет служить ключом при группировке данных, а подстрока после $$
должна быть помещена внутрь списка, который будет значением карты.Пример полученной карты:
{
027=[wuchang, hongshan, caidan],
020=[tianhe],
010=[fengtai, chaoyang, haidain],
021=[changnin, xuhui]
}
Я использовал традиционный способ достижения этого:
private Map<String, List<String>> parseParametersByIterate(String sensors) {
List<String[]> dataList = Arrays.stream(sensors.split(","))
.map(s -> s.split("\\$\\$"))
.collect(Collectors.toList());
Map<String, List<String>> resultMap = new HashMap<>();
for (String[] d : dataList) {
List<String> list = resultMap.get(d[0]);
if (list == null) {
list = new ArrayList<>();
list.add(d[1]);
resultMap.put(d[0], list);
} else {
list.add(d[1]);
}
}
return resultMap;
}
Но это кажется более сложным и многословным. Таким образом, я хочу реализовать эту логику в однострочном режиме (т.е. с одним оператором потока).
То, что я пробовал до сих пор, ниже
Map<String, List<String>> result = Arrays.stream(data.split(","))
.collect(Collectors.groupingBy(s -> s.split("\\$\\$")[0]));
Но результат не соответствует тому, который я хочу иметь. Как я могу создать карту, структурированную, как описано выше?
Вам просто нужно отобразить значения отображения. Вы можете сделать это, указав второй аргумент для Collectors.groupingBy
:
Collectors.groupingBy(s -> s.split("\\$\\$")[0],
Collectors.mapping(s -> s.split("\\$\\$")[1],
Collectors.toList()
))
Вместо того, чтобы разбивать дважды, вы можете сначала разбить, а потом сгруппировать:
Arrays.stream(data.split(","))
.map(s -> s.split("\\$\\$"))
.collect(Collectors.groupingBy(s -> s[0],
Collectors.mapping(s -> s[1],Collectors.toList())
));
Что теперь выводит:
{027=[wuchang, hongshan, caidan], 020=[tianhe], 021=[changnin, xuhui], 010=[fengtai, chaoyang, haidain]}
Вы можете еще больше повысить производительность, используя .map(s -> s.split("\\$\\$", 2))
, так как это сообщит операции split
, что ей не нужно искать другой $$
после того, как он его нашел.
Кстати, split(",")
и split("\\$\\$")
можно комбинировать за один шаг, не создавая промежуточных массивов — см..
Вы можете извлечь необходимую информацию из строки, не выделяя промежуточные массивы и выполняя итерацию по строке только один раз, а также используя механизм регулярных выражений только один раз вместо того, чтобы выполнять несколько вызовов String.split()
и разбивать сначала запятую ,
, а затем $$
. Мы можем получить все необходимые данные за один раз.
Поскольку вы уже используете регулярные выражения (поскольку интерпретация "\\s\\s"
требует использования механизма регулярных выражений), было бы разумно использовать их на полную мощность.
Мы можем определить следующий шаблон, который захватывает интересующие вас части:
public static final Pattern DATA = // use the proper name to describe a piece of information (like "027$$hongshan") that the pattern captures
Pattern.compile("(\\d+)\\$\\$(\\w+)");
Используя этот шаблон, мы можем создать экземпляр Matcher
и применить метод Java 9 Matcher.result()
, который создаст поток MatchResult
s.
MatchResult
— это объект, инкапсулирующий информацию о захваченной последовательности символов. Мы можем получить доступ к группам, используя метод MatchResult.group()
.
private static Map<String, List<String>> parseParametersByIterate(String sensors) {
return DATA.matcher(sensors).results() // Stream<MatchResult>
.collect(Collectors.groupingBy(
matchResult -> matchResult.group(1), // extracting "027" from "027$$hongshan"
Collectors.mapping(
matchResult -> matchResult.group(2), // extracting "hongshan" from "027$$hongshan"
Collectors.toList())
));
}
main()
public static void main(String[] args) {
String data = "010$$fengtai,010$$chaoyang,010$$haidain,027$$wuchang,027$$hongshan,027$$caidan,021$$changnin,021$$xuhui,020$$tianhe";
parseParametersByIterate(data)
.forEach((k, v) -> System.out.println(k + " -> " + v));
}
Вывод:
027 -> [wuchang, hongshan, caidan]
020 -> [tianhe]
021 -> [changnin, xuhui]
010 -> [fengtai, chaoyang, haidain]
Ага, не хочу раздваиваться, спасибо за ответ, приму через 15 минут