读取和匹配两个大文件的内容

时间:2016-02-12 00:29:06

标签: java

我有两个文件,每个文件具有大约100,000行的相同格式。对于文件一中的每一行,我正在提取第二个组件或列,如果我在第二个文件的第二列中找到匹配,我提取它们的第三个组件并将它们组合,存储或输出它。

虽然我的实现工作但程序运行速度非常慢,但是迭代文件需要一个多小时,比较并输出所有结果。

我正在读取并将这两个文件的数据存储在ArrayList中,然后迭代这些列表并进行比较。下面是我的代码,是否存在任何与性能相关的故障或其正常情况。

注意:我正在使用String.split(),但我理解其他帖子,StringTokenizer更快。

public ArrayList<String> match(String file1, String file2) throws IOException{
        ArrayList<String> finalOut = new ArrayList<>();
        try {
            ArrayList<String> data = readGenreDataIntoMemory(file1);
            ArrayList<String> data1 = readGenreDataIntoMemory(file2);
            StringTokenizer st = null;

            for(String line : data){
                HashSet<String> genres = new HashSet<>();
                boolean sameMovie = false;
                String movie2 = "";
                st = new StringTokenizer(line, "|");
                //String line[] = fline.split("\\|");
                String ratingInfo = st.nextToken();
                String movie1 = st.nextToken();
                String genreInfo = st.nextToken();
                if(!genreInfo.equals("null")){
                    for(String s : genreInfo.split(",")){
                        genres.add(s);
                    }
                }


                StringTokenizer st1 = null;
                for(String line1 : data1){
                    st1 = new StringTokenizer(line1, "|");
                    st1.nextToken();
                    movie2 = st1.nextToken();
                    String genreInfo2= st1.nextToken();
                    //If the movie name are similar then they should have the same genre
                    //Update their genres to be the same
                    if(!genreInfo2.equals("null") && movie1.equals(movie2)){
                        for(String s : genreInfo2.split(",")){
                            genres.add(s);
                        }
                        sameMovie = true;
                        break;
                    }
                }
                if(sameMovie){
                    finalOut.add(ratingInfo+""+movieName+""+genres.toString()+"\n");
                }else if(sameMovie ==  false){
                    finalOut.add(line);
                }
            }
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        }
        return finalOut;
    }

2 个答案:

答案 0 :(得分:1)

我会使用Streams API

String file1 = "files1.txt";
String file2 = "files2.txt";
// get all the lines by movie name for each file.
Map<String, List<String[]>> map = Stream.of(Files.lines(Paths.get(file1)),
                                            Files.lines(Paths.get(file2)))
        .flatMap(p -> p)
        .parallel()
        .map(s -> s.split("[|]", 3))
        .collect(Collectors.groupingByConcurrent(sa -> sa[1], Collectors.toList()));

// merge all the genres for each movie.
map.forEach((movie, lines) -> {
    Set<String> genres = lines.stream()
            .flatMap(l -> Stream.of(l[2].split(",")))
            .collect(Collectors.toSet());
    System.out.println("movie: " + movie + " genres: " + genres);
});

这样做的好处是O(n)而不是O(n^2),而且它是多线程的。

答案 1 :(得分:0)

进行哈希联接。

截至目前,您正在进行外部循环连接,即O(n ^ 2),散列连接将分摊O(n)

将每个文件的内容放在哈希映射中,键入您想要的字段(第二个字段)。

Map<String,String> map1 = new HashMap<>();
// build the map from file1

然后进行散列连接

   for(String key1 : map1.keySet()){
        if(map2.containsKey(key1)){
        // do your thing you found the match
        }
    }