从文件中将键值对添加到Hashmap中

3

我正在尝试从文件中提取一个键值对到哈希映射表中,以便更轻松地操作值。

该文件格式如下:

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();
}

然而,只有第一组键值对被插入了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));
        }
    }
4个回答

2
首先让我们看一下为什么您的解决方案无法给出预期结果。当您在分隔符:周围拆分每行时,可能有许多键值对。但是您仅考虑第一个键值对,而省略其余部分。因此,这适用于您示例中的最后一行,因为它只有一个对应的映射条目。同时,它不适用于第一行,因为它有许多对应的映射条目,而您仅处理第一个条目。
以下是我的解决方法。将文件中的每行拆分为分隔符:周围。这将为每个相应的行生成一个数组。由于每行都有一个结尾的:字符,因此您必须跳过数组中相关的最后一个元素。然后数组中的每个偶数索引成为地图中的键,紧随其后的奇数索引成为相应的价值。这是它的样子。
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}

注:Original Answer翻译成“最初的回答”。

我能问一下,如何整合正则表达式代码?我对Streams感到困惑。我在编辑的代码中评论了我的理解,请看一下。 - TheKraven
1
你的 flatMapToInt 在这里没有用处。请查看给出的答案并相应地更改您的代码。请注意,filtermapToObj 操作符位于 flatMap 操作符内部。您无法在 flatMap 操作符外部访问数组引用 a,这就是为什么编译器会报错的原因。请查看编译器错误,尝试解释并修复它们。此外,在声明映射时,请使用接口类型而不是实现类型,如下所示:Map<String, String> hm = new HashMap<>(); - Ravindra Ranwala
哦,我的错,我没有注意到filterMapToObjfilter的一部分。也注意到了Map声明,这是一个好习惯吗? - TheKraven

1

寻求调试帮助的问题(“为什么这段代码不起作用?”)必须包括所需行为、具体问题或错误以及在问题本身中重现它所需的最短代码。没有明确的问题陈述的问题对其他读者没有用。参见:如何创建最小可重现示例

这个问题是为什么需要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]);
    }

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}

-1
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}


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接