【问题标题】:Java: check CSV file on duplicate lines using ArrayListJava:使用 ArrayList 检查重复行上的 CSV 文件
【发布时间】:2017-11-10 15:57:25
【问题描述】:

我有一个包含以下内容的 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

你能帮我看看我做错了什么吗?我的比较器我觉得还可以。我怎么了 数组列表?

【问题讨论】:

  • 你实际上不需要两个循环。在第一种情况下循环本身,添加到集合而不是列表。如果 add 为一行返回 false,也添加到重复行列表...然后打印重复列表..
  • 谢谢 可选,我将 while 循环中的代码调整为 boolean add = validationFile.add(line); if(!add){ System.out.println(line); },它工作正常

标签: java csv arraylist


【解决方案1】:

其他答案正确表明您应该使用 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&lt;String&gt; 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 &lt;= 0)。如果搜索成功,它将返回一个非负数(comp &gt;= 0)。但另一个问题是,您正在为每个元素搜索整个列表,而且搜索显然总是会成功(也就是说,如果您的列表已排序)。

省去你所有的麻烦,改用一套。而且,使用 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);
}

【讨论】:

  • 感谢 DodgyCodeException 抽出时间指出我的缺陷。我现在对它进行了调整,就像我在上面对“可选”的评论中所说的那样。我会在你的 cmets 上工作更长时间。最好的问候,彼得
【解决方案2】:

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

如果您想要所有重复行的列表,则创建一个List,其中包含在尝试add()Set 时返回false 的行。

注意:

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

import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;

public class ReadValidationFile {
    static List<String> validationFile = new ArrayList<>();
    static {
        validationFile.add("2017-10-29 00:00:00.0,\"1005\",-10227,0,0,0,332894,0,0,222,332894,222,332894");
        validationFile.add("2017-10-29 00:00:00.0,\"1010\",-125529,0,0,0,420743,0,0,256,420743,256,420743");
        validationFile.add("2017-10-29 00:00:00.0,\"1005\",-10227,0,0,0,332894,0,0,222,332894,222,332894");
        validationFile.add("2017-10-29 00:00:00.0,\"1013\",-10625,0,0,-687,599098,0,0,379,599098,379,599098");
        validationFile.add("2017-10-29 00:00:00.0,\"1604\",-1794.9,0,0,-3.99,4081.07,0,0,361,4081.07,361,4081.07");
    }

    public static void main(String[] args) {
        // Option 1 : unique lines only 
        Set<String> uniqueLinesOnly = new HashSet<>(validationFile);

        // Option 2 : unique lines and duplicate lines 
        Set<String> uniqueLines = new HashSet<>();
        Set<String> duplicateLines = new HashSet<>();
        for (String line : validationFile) {
            if (!uniqueLines.add(line.toLowerCase())) {
                duplicateLines.add(line.toLowerCase());
            }
        }

        // Option 3 : unique lines and duplicate lines by Java Streams
        Set<String> uniquesJava8 = new HashSet<>();
        List<String> duplicatesJava8 = validationFile
                                    .stream()
                                    .filter(element -> !uniquesJava8.add(element.toLowerCase()))
                                    .map(element -> element.toLowerCase())
                                    .collect(Collectors.toList());
    }
}

【讨论】:

    【解决方案3】:
    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);
        }
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-12-26
      • 2016-04-14
      • 1970-01-01
      • 2023-03-04
      相关资源
      最近更新 更多