将文件中的键值对添加到 Hashmap
Adding key value pairs from a file to a Hashmap
我正在尝试将键值对从文件中提取到 Hashmap 中以便于对值进行操作。
文件格式如下:
Activity1:3:Activity2:5:Activity3:7:
Activity4:1:
每行最多有3个活动及其对应的编号。
String currentPath;
Path fullPath;
HashMap<String, String> hm = new HashMap<>();
try {
// Obtain current directory path
currentPath = Paths.get("").toAbsolutePath().toString();
// Obtain full path of data.txt
fullPath = Paths.get(currentPath, "data.txt");
// Check if file exists
if (Files.exists(fullPath)) {
// Read line by line in data.txt
Files.lines(fullPath)
.forEach(line -> hm.put(line.split(":")[0], line.split(":")[1]) );
}
else{
System.out.println("data.txt is not found.");
}
} catch (
IOException e) {
e.printStackTrace();
}
但是,只有第一个 key:value 对被插入到 Hashmap 中。
我尝试使用
.map(s -> s.split(":"))
.collect(Collectors.toMap(r -> r[0], r -> r[1] ))
但它不起作用,因为 split()
输出类型是 toMap
不接受的数组。
编辑:
public static void main(String[] args) {
String currentPath;
Path filePath;
HashMap<String, String> hm = new HashMap<>();
Pattern delimiter = Pattern.compile(":");
try {
// Obtain current directory path
currentPath = Paths.get("").toAbsolutePath().toString();
// Obtain full path of data.txt
filePath = Paths.get(currentPath, "data.txt");
// Check if file exists
if (Files.exists(filePath)) {
// Read line by line in data.txt
hm = Files.lines(filePath)
.map(delimiter::split) // stream of multiple Array<String>
.flatMapToInt(a -> IntStream.range(0, a.length - 1)) // combine multiple Array<String> to a
// single stream, remove last Array<String>
.filter(i -> i % 2 == 0) // obtain only even indices
.mapToObj(i -> new AbstractMap.SimpleEntry<>(a[i], a[i+1])) // a cannot be resolved. Create new Map, key is Array<String>[even], value is Array<String>[odd]
.collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue, (a,b) -> a)); //
}
else{
System.out.println("data.txt not found.");
}
} catch (
IOException e) {
e.printStackTrace();
}
for (String objectName : hm.keySet()) {
System.out.println(objectName);
System.out.println(hm.get(objectName));
}
}
Questions seeking debugging help ("why isn't this code working?") must
include the desired behavior, a specific problem or error and the
shortest code necessary to reproduce it in the question itself.
Questions without a clear problem statement are not useful to other
readers. See: How to create a Minimal, Reproducible
Example.
这个问题很好地说明了为什么需要 MRE 以及为什么它如此有用。
当把数据硬编码成 mre 时,你很快意识到问题与文件无关:
String line = "Activity1:3:Activity2:5:Activity3:7:" ;
String[] lineAsArray = line.split(":");
//lineAsArray is of the following stucture [Activity1, 3, Activity2, 5, Activity3, 7]
//by line.split(":")[0], line.split(":")[1]) you simply add Activity1, 3
//to get all pairs iterate over the array:
for(int index = 0; index < lineAsArray.length ; index+=2){
System.out.println("key = "+ lineAsArray[index]+ " value = "+ lineAsArray[index+1]);
}
分析
当前的实现不包括一行包含许多键值对的情况。
解决方案
考虑到一行可能包含许多键值对,以下草案解决方案执行行解析。
import java.util.AbstractMap;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
public final class Main {
public static void main(final String[] args) {
final List<String> lines = new ArrayList<>();
lines.add("Activity1:3:Activity2:5:Activity3:7:");
lines.add("Activity4:1:");
final Map<String, String> map = lines
.stream()
.map(Main::parseLine)
.flatMap(List::stream)
.collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));
System.out.println(map);
}
private static List<Map.Entry<String, String>> parseLine(final String line) {
final List<Map.Entry<String, String>> entries = new ArrayList<>();
final String[] components = line.split(":");
final int pairCount = components.length / 2;
for (int pairNumber = 0; pairNumber < pairCount; ++pairNumber) {
final int pairStartIndex = pairNumber * 2;
entries.add(
new AbstractMap.SimpleEntry<>(
components[pairStartIndex],
components[pairStartIndex + 1]
)
);
}
return entries;
}
}
输出:
{Activity3=7, Activity4=1, Activity1=3, Activity2=5}
首先让我们看一下为什么您的解决方案没有给出预期的结果。当您围绕分隔符 :
拆分每一行时,可能会有许多键值对。但是您只考虑第一个键值对而忽略其余部分。所以这适用于您示例中的最后一行,因为它只有一个对应的地图条目。同时它不适用于第一行,因为它有许多对应的映射条目,而您只处理第一个条目。
这是我解决这个问题的方法。获取文件中的每一行并将其拆分为分隔符 :
。这会为每个对应的行生成一个数组。由于每一行都有一个尾随 :
字符,因此您必须跳过数组中相关的最后一个元素。然后数组中的每个偶数索引成为映射中的键,紧随其后的奇数索引成为相应的值。这是它的样子。
private static final Pattern DELIMITER = Pattern.compile(":");
Map<String, String> activityMap = lines.map(DELIMITER::split)
.flatMap(a -> IntStream.range(0, a.length - 1).filter(i -> i % 2 == 0)
.mapToObj(i -> new AbstractMap.SimpleEntry<>(a[i], a[i + 1])))
.collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue, (a, b) -> a));
输出如下所示:
{Activity3=7, Activity4=1, Activity1=3, Activity2=5}
import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.util.*;
public class Demo {
public static void main(String args[])throws IOException {
/Example :- File file = new File("src/abc.txt");/
File file = new File("<absolute_file_path>");
if(file.exists()) {
BufferedReader br = new BufferedReader(new FileReader(file));
String data = null;
HashMap<String, String> hashMap = new HashMap<>();
while ((data = br.readLine()) != null) {
String[] str = data.split(":");
for (int i = 1; i < str.length; i += 2) {
hashMap.put(str[i - 1], str[i]);
}
}
System.out.println(hashMap);
br.close();
}else
System.out.println("File not exists");
}
}
输出如下所示:
{Activity3=7, Activity4=1, Activity1=3, Activity2=5}
我正在尝试将键值对从文件中提取到 Hashmap 中以便于对值进行操作。
文件格式如下:
Activity1:3:Activity2:5:Activity3:7:
Activity4:1:
每行最多有3个活动及其对应的编号。
String currentPath;
Path fullPath;
HashMap<String, String> hm = new HashMap<>();
try {
// Obtain current directory path
currentPath = Paths.get("").toAbsolutePath().toString();
// Obtain full path of data.txt
fullPath = Paths.get(currentPath, "data.txt");
// Check if file exists
if (Files.exists(fullPath)) {
// Read line by line in data.txt
Files.lines(fullPath)
.forEach(line -> hm.put(line.split(":")[0], line.split(":")[1]) );
}
else{
System.out.println("data.txt is not found.");
}
} catch (
IOException e) {
e.printStackTrace();
}
但是,只有第一个 key:value 对被插入到 Hashmap 中。 我尝试使用
.map(s -> s.split(":"))
.collect(Collectors.toMap(r -> r[0], r -> r[1] ))
但它不起作用,因为 split()
输出类型是 toMap
不接受的数组。
编辑:
public static void main(String[] args) {
String currentPath;
Path filePath;
HashMap<String, String> hm = new HashMap<>();
Pattern delimiter = Pattern.compile(":");
try {
// Obtain current directory path
currentPath = Paths.get("").toAbsolutePath().toString();
// Obtain full path of data.txt
filePath = Paths.get(currentPath, "data.txt");
// Check if file exists
if (Files.exists(filePath)) {
// Read line by line in data.txt
hm = Files.lines(filePath)
.map(delimiter::split) // stream of multiple Array<String>
.flatMapToInt(a -> IntStream.range(0, a.length - 1)) // combine multiple Array<String> to a
// single stream, remove last Array<String>
.filter(i -> i % 2 == 0) // obtain only even indices
.mapToObj(i -> new AbstractMap.SimpleEntry<>(a[i], a[i+1])) // a cannot be resolved. Create new Map, key is Array<String>[even], value is Array<String>[odd]
.collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue, (a,b) -> a)); //
}
else{
System.out.println("data.txt not found.");
}
} catch (
IOException e) {
e.printStackTrace();
}
for (String objectName : hm.keySet()) {
System.out.println(objectName);
System.out.println(hm.get(objectName));
}
}
Questions seeking debugging help ("why isn't this code working?") must include the desired behavior, a specific problem or error and the shortest code necessary to reproduce it in the question itself. Questions without a clear problem statement are not useful to other readers. See: How to create a Minimal, Reproducible Example.
这个问题很好地说明了为什么需要 MRE 以及为什么它如此有用。
当把数据硬编码成 mre 时,你很快意识到问题与文件无关:
String line = "Activity1:3:Activity2:5:Activity3:7:" ;
String[] lineAsArray = line.split(":");
//lineAsArray is of the following stucture [Activity1, 3, Activity2, 5, Activity3, 7]
//by line.split(":")[0], line.split(":")[1]) you simply add Activity1, 3
//to get all pairs iterate over the array:
for(int index = 0; index < lineAsArray.length ; index+=2){
System.out.println("key = "+ lineAsArray[index]+ " value = "+ lineAsArray[index+1]);
}
分析
当前的实现不包括一行包含许多键值对的情况。
解决方案
考虑到一行可能包含许多键值对,以下草案解决方案执行行解析。
import java.util.AbstractMap;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
public final class Main {
public static void main(final String[] args) {
final List<String> lines = new ArrayList<>();
lines.add("Activity1:3:Activity2:5:Activity3:7:");
lines.add("Activity4:1:");
final Map<String, String> map = lines
.stream()
.map(Main::parseLine)
.flatMap(List::stream)
.collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));
System.out.println(map);
}
private static List<Map.Entry<String, String>> parseLine(final String line) {
final List<Map.Entry<String, String>> entries = new ArrayList<>();
final String[] components = line.split(":");
final int pairCount = components.length / 2;
for (int pairNumber = 0; pairNumber < pairCount; ++pairNumber) {
final int pairStartIndex = pairNumber * 2;
entries.add(
new AbstractMap.SimpleEntry<>(
components[pairStartIndex],
components[pairStartIndex + 1]
)
);
}
return entries;
}
}
输出:
{Activity3=7, Activity4=1, Activity1=3, Activity2=5}
首先让我们看一下为什么您的解决方案没有给出预期的结果。当您围绕分隔符 :
拆分每一行时,可能会有许多键值对。但是您只考虑第一个键值对而忽略其余部分。所以这适用于您示例中的最后一行,因为它只有一个对应的地图条目。同时它不适用于第一行,因为它有许多对应的映射条目,而您只处理第一个条目。
这是我解决这个问题的方法。获取文件中的每一行并将其拆分为分隔符 :
。这会为每个对应的行生成一个数组。由于每一行都有一个尾随 :
字符,因此您必须跳过数组中相关的最后一个元素。然后数组中的每个偶数索引成为映射中的键,紧随其后的奇数索引成为相应的值。这是它的样子。
private static final Pattern DELIMITER = Pattern.compile(":");
Map<String, String> activityMap = lines.map(DELIMITER::split)
.flatMap(a -> IntStream.range(0, a.length - 1).filter(i -> i % 2 == 0)
.mapToObj(i -> new AbstractMap.SimpleEntry<>(a[i], a[i + 1])))
.collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue, (a, b) -> a));
输出如下所示:
{Activity3=7, Activity4=1, Activity1=3, Activity2=5}
import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.util.*;
public class Demo {
public static void main(String args[])throws IOException {
/Example :- File file = new File("src/abc.txt");/
File file = new File("<absolute_file_path>");
if(file.exists()) {
BufferedReader br = new BufferedReader(new FileReader(file));
String data = null;
HashMap<String, String> hashMap = new HashMap<>();
while ((data = br.readLine()) != null) {
String[] str = data.split(":");
for (int i = 1; i < str.length; i += 2) {
hashMap.put(str[i - 1], str[i]);
}
}
System.out.println(hashMap);
br.close();
}else
System.out.println("File not exists");
}
}
输出如下所示:
{Activity3=7, Activity4=1, Activity1=3, Activity2=5}