Java:使用ArrayList检查重复行上的CSV文件

时间:2017-11-10 15:57:26

标签: java csv arraylist

我有一个包含以下内容的CSV文件:

2017-10-29 00:00:00.0,"1005",-10227,0,0,0,332894,0,0,222,332894,222,332894 2017-10-29 00:00:00.0,"1010",-125529,0,0,0,420743,0,0,256,420743,256,420743 2017-10-29 00:00:00.0,"1005",-10227,0,0,0,332894,0,0,222,332894,222,332894 2017-10-29 00:00:00.0,"1013",-10625,0,0,-687,599098,0,0,379,599098,379,599098 2017-10-29 00:00:00.0,"1604",-1794.9,0,0,-3.99,4081.07,0,0,361,4081.07,361,4081.07

因此第1行和第3行是重复的。 现在我想读入文件并在控制台中打印出重复的行。

我设置了这个Java代码,读取文件并将其逐行放入ArrayList中。然后我创建一个不可变的 复制,循环遍历ArrayList,在binarySearch中我使用ArrayList的不可变副本:

import java.io.BufferedReader;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

public class ReadValidationFile {

public static void main(String[] args) {

    List<String> validationFile = new ArrayList<>();

    try(BufferedReader br = new BufferedReader(new FileReader("validation_small.csv"));){

        String line;
        while((line = br.readLine())!= null){
            validationFile.add(line);
        }

    } catch (FileNotFoundException e) {
        //e.printStackTrace();
        System.out.println("file not found " + e.getMessage());
    } catch (IOException e) {
        e.printStackTrace();
    }

    List<String> validationFileCopy = Collections.unmodifiableList(validationFile);

    for(String line : validationFile){
        int comp = Collections.binarySearch(validationFileCopy,line,new ComparatorLine());
        if (comp <= 0){
            System.out.println(line);
        }

    }
}
}

比较类:

import java.util.Comparator;

public class ComparatorLine implements Comparator<String> {
@Override
public int compare(String s1, String s2) {
    return s1.compareToIgnoreCase(s2);
}
}

我希望打印这一行:

2017-10-29 00:00:00.0,"1005",-10227,0,0,0,332894,0,0,222,332894,222,332894

但我得到的输出是:

2017-10-29 00:00:00.0,"1010",-125529,0,0,0,420743,0,0,256,420743,256,420743

你能帮我看看我做错了什么吗?我认为我的比较器没问题。我有什么问题 的ArrayLists?

谢谢你, 彼得

3 个答案:

答案 0 :(得分:3)

在从输入csv文件中读取行时创建Set,随时设置add()元素返回false打印该行,因为它是重复行。

如果您需要所有重复行的列表,请创建一个List,其中包含在审核falseadd()时返回Set的行。

注意:

  • 我使用静态数据模拟了您的文件读取。
  • 小注意,如果您的数据只包含数字而没有字母,那么您不需要不区分大小写的比较。
  • 如果您的数据包含字母表,那么您也不需要特殊的比较器,因为您可以使用Set将数据插入add(line.toLowerCase()),这将确保将所有行与小写进行比较,然后添加到{ {1}}。
Set

答案 1 :(得分:3)

其他答案正确地说明您应该使用Set而不是List。但是为了学习,让我们看看你的代码,看看你哪里出错了。

public class ReadValidationFile {

public static void main(String[] args) {

    List<String> validationFile = new ArrayList<>();

    try(BufferedReader br = new BufferedReader(new FileReader("validation_small.csv"));){

分号是不必要的。

        String line;
        while((line = br.readLine())!= null){
            validationFile.add(line);
        }

这一切都可以在一行中实现:
List<String> validationFile = Files.readAllLines(Paths.get("validation_small.csv"), "utf-8");

    } catch (FileNotFoundException e) {
        //e.printStackTrace();
        System.out.println("file not found " + e.getMessage());
    } catch (IOException e) {
        e.printStackTrace();
    }

    List<String> validationFileCopy = Collections.unmodifiableList(validationFile);

实际上,这不是副本。这只是同一列表的不可修改的视图。

    for(String line : validationFile){
        int comp = Collections.binarySearch(validationFileCopy,line,new ComparatorLine());

您也可以只搜索validationFile本身。但是,您调用的binarySearch仅适用于已排序的列表,但您的列表未排序。请参阅documentation

        if (comp <= 0){
            System.out.println(line);
        }

如果找不到 comp <= 0),则表示正在打印。如果搜索成功,则会返回非负数(comp >= 0)。但另一个问题是,您正在搜索每个元素的整个列表,搜索显然总是成功(即,如果您的列表已排序)。

省去所有麻烦并使用Set代替。并且,使用Java 8流,整个程序可以简化为以下内容:

public static void main(String[] args) throws Exception {
    Set<String> uniqueLines = new HashSet<>();
    Files.lines(Paths.get("", "utf-8"))
            .filter(line -> !uniqueLines.add(line))
            .forEach(System.out::println);
}

如果你真的需要在比较字符串时忽略大小写(从你给定的数据看起来它看起来没有任何区别,因为它只是数字),然后通过第一个大写字母存储每个唯一的行和然后降低它。这种显然繁琐的技术是必要的,因为如果处理非英语文本只是小写是不够的。 equalsIgnoreCase方法也可以这样做。

public static void main(String[] args) throws Exception {
    Set<String> uniqueLines = new HashSet<>();
    Files.lines(Paths.get("", "utf-8"))
            .filter(line -> !uniqueLines.add(line.toUpperCase().toLowerCase()))
            .forEach(System.out::println);
}

答案 2 :(得分:1)

import java.io.BufferedReader;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;

public class ReadValidationFile {
    public static void main(String[] args){       
        List<String> validationFile = new ArrayList<>();
        try(BufferedReader br = new BufferedReader(new FileReader("validation_small.csv"));){
            String line;
            while((line = br.readLine())!= null){
                validationFile.add(line);
            }
        } catch (FileNotFoundException e) {
            //e.printStackTrace();
            System.out.println("file not found " + e.getMessage());
        } catch (IOException e) {
            e.printStackTrace();
        }
        Set<String> uniques = new HashSet<>();        
        List<String> duplicates = validationFile.stream().filter(i->!uniques.add(i)).collect(Collectors.toList());
        System.out.println(duplicates);
    }
}