【问题标题】:Arrays.sort() removes many items from my arrayArrays.sort() 从我的数组中删除许多项目
【发布时间】:2018-09-04 03:47:13
【问题描述】:

在我的 Java 程序中,我有以下代码:

String[] states = readFile("States.txt");

System.out.println(String.join(" ", states));
System.out.println(states.length);

Arrays.sort(states);

System.out.println(String.join(" ", states));
System.out.println(states.length);

奇怪的是,从java.util.Arrays 调用Arrays.sort() 会导致从列表中删除许多项目。当我运行上面的代码时,这是输出:

FL GA SC NC VA MD NY NJ DE PA CT RI MA VT NH ME AL TN KY WV OH MI MS AR MO KS NE IN IL WI MN LA TX OK IA SD ND NM CO WY ID AZ UT NV MT CA OR WA AL HI
50
AL AL AR AZ CA CO CT DE FL GA HI
50

我对这里发生的事情非常非常困惑。为什么只打印出 11 个项目? Arrays.sort() 是否正在删除项目?为什么Arrays.sort() 会这样做?为什么数组的大小还是50?项目是空白还是什么?

我假设我的 readFile() 方法工作正常,因为未排序的数组打印得很好......

public static String[] readFile(String FileName) {
    char[] cbuf = new char[200];
    String[] array;
    FileReader fr;
    try {
        fr = new FileReader(FileName);
        try {
            fr.read(cbuf);
        } catch (IOException e) {
            e.printStackTrace();
        }
    } catch (FileNotFoundException e) {
        e.printStackTrace();
    }
    String all = new String(cbuf);
    array = all.split("\n");
    return array;
}

我正在读取的文件:https://nofile.io/f/8TO3pdnmS3W/States.txt MD5 以 8b961b5 开头

【问题讨论】:

  • Smth 是非常错误的,如果你得到你的数组并且它输出所有状态,但是在 Arrays.sort() 之后它不会 - 不可能:) 你为什么不在排序之前和之后调试你的代码() fn?
  • 使用String[] states = "FL GA SC NC VA MD ...".split(" "); 没有问题。检查split("\n"); 是否适用于文件中的所有数据(例如,没有任何\r\n 分隔符)。
  • @AaronFranke,那么您的日志正在截断输出! Arrays.toString() 将起作用。去检查截断。
  • 我怀疑数据文件中有^Z。
  • 学习使用调试器是必不可少的,试着把它放在你的待办事项清单上。它将为您节省数小时的痛苦和困惑。 trim() 起作用的原因是你的字符串在末尾有一堆空字符值,因为你的缓冲区比你的输入长,并且 trim() 删除了它们。最好使用较小的缓冲区,或者至少检查 fr.read() 的返回值以查看您读取了多少个字符,并在将其转换为字符串时使用该知识。

标签: java arrays string sorting


【解决方案1】:

文件末尾的换行符,特别是在文件“HI”的最后一个条目之后,似乎是导致问题的原因。可以在readFile函数中使用:

array = all.trim().split("\n");

【讨论】:

  • 这完美!但是,文件末尾没有换行符。该文件似乎只是在 HI 之后结束,但我想文件末尾隐藏着某种幽灵字符。也许这是我的文本编辑器的错。如果你们想进一步调查,我可以上传文件。
  • 请上传文件。它可能有助于我们中的一些人查明问题。我还通过在您提供的以空格分隔的输入的末尾插入 newline (newline = System.getProperty("line.separator");) 来模拟您的输入。观察到类似的行为。虽然我应该提到,虽然输出在HI 之后中断,但输出的其余部分打印在一个新行中。
  • 我上传了文件,我的问题底部有一个链接。我还发布了 MD5 总和的第一部分,以检查您是否拥有完全相同的文件。此外,我用来显示输出的 IDE 是 Eclipse 4.6.3。
  • 这可能是我的缓冲区大于输入的问题,这就是它需要修剪的原因。查看@Matt 的回答
【解决方案2】:

通过在线 Java 编译器确认“工件”行为:

import java.util.Arrays;

public class MyClass {
    public static void main(String args[]) {
        // instead of using readFile() the array is defined here.
        // note the \n on the last element
        String[] states = {"FL", "GA", "SC", "NC", "VA", "MD", "NY", "NJ", "DE", "PA", "CT", "RI", "MA", "VT", "NH", "ME", "AL", "TN", "KY", "WV", "OH", "MI", "MS", "AR", "MO", "KS", "NE", "IN", "IL", "WI", "MN", "LA", "TX", "OK", "IA", "SD", "ND", "NM", "CO", "WY", "ID", "AZ", "UT", "NV", "MT", "CA", "OR",
           "WA", "AL", "HI\n"};

        System.out.println(String.join(" ", states));
        System.out.println(states.length);

        Arrays.sort(states);

        System.out.println(String.join(" ", states));
        System.out.println(states.length);
    }
}

还有输出:

FL GA SC NC VA MD NY NJ DE PA CT RI MA VT NH ME AL TN KY WV OH MI MS AR MO KS NE IN IL WI MN LA TX OK IA SD ND NM CO WY ID AZ UT NV MT CA OR WA AL HI

50
AL AL AR AZ CA CO CT DE FL GA HI
 IA ID IL IN KS KY LA MA MD ME MI MN MO MS MT NC ND NE NH NJ NM NV NY OH OK OR PA RI SC SD TN TX UT VA VT WA WI WV WY
50

显然@Arjun Kay 使用的日志已经用换行符截断了在排序元素之后打印的元素。

【讨论】:

  • 其实问题是HI之后char[]缓冲区中有很多空字符,导致文本停止打印。
【解决方案3】:

您的readFile 方法很草率。您声明了一个包含 200 个元素的缓冲区数组 char[] cbuf = new char[200];

听起来你的文件在每一行都带有一个状态:

FL
GA
SC
NC

您将整个文件读入缓冲区,但没有填充缓冲区,因此尾随的 50 个元素仍被初始化为默认的空字符值\u0000(参见此question

cbuf = [F][L][\n][G][A][\n][S][C][\n][N][C][\n] ... [\u0000][\u0000]

然后将cbuff 转换为字符串:

all = "FL\nGA\nSC\nNC\n ... \u0000\u0000\u0000"

然后你拆分字符串以将其转换为数组:

array = [FL][GA][SC][NC]...[\u0000\u0000\u0000\u0000\u0000]

所以你可以看到你的最终数组中有一堆无用的字符,因为你的缓冲区比你读取的文件大。

我无法在我的机器上复制你丢失的状态,但你可以清理你的文件阅读器,我认为它对你有用。使用BufferedReader,然后你可以一次读取你的文件一行,它会节省你所有的手动拆分。我还建议使用List<String> 而不是String[] 数组,这样您就不必处理数组的大小。

考虑一下:

public static void main(String[] args) throws IOException {
    String[] states = readFile("States.txt");

    System.out.println(String.join(" ", states));
    System.out.println(states.length);

    Arrays.sort(states);

    System.out.println(String.join(" ", states));
    System.out.println(states.length);

    // now do the same thing but using a list
    List<String> statesList = readFileToList("States.txt");

    System.out.println(String.join(" ", statesList));
    System.out.println(statesList.size());

    Collections.sort(statesList);

    System.out.println(String.join(" ", statesList));
    System.out.println(statesList.size());
}

// read the file to an array
public static String[] readFile(String FileName) throws IOException {
    String[] states = new String[50];
    BufferedReader br = new BufferedReader(new FileReader(FileName));

    String state;
    int index = 0; // keep track of the array index
    // when readLine() returns null there are no more lines to read
    while((state = br.readLine()) != null && index < 50) {
        states[index] = state;
        index++;
    }

    return states;
}

// read the file to a list
public static List<String> readFileToList(String FileName) throws IOException {
    List<String> states = new ArrayList<>(); // no array size to worry about
    BufferedReader br = new BufferedReader(new FileReader(FileName));

    String state;
    while((state = br.readLine()) != null) {
        states.add(state); // no indexes to worry about
    }

    return states;
}

【讨论】:

  • 通常我会同意Lists,但是对于这个特定的程序,我需要使用字符串数组。如果您想使用原始文本文件进行测试,我已将其添加到我的问题中。
  • 如果你必须使用一个公平的数组。我用你上传的文件进行了测试,我的代码工作正常。我很确定您的问题与您的缓冲区大于您的输入有关。
  • 刚刚测试过了。使用150 的缓冲区,会出现错误,但使用149,则不会再出现错误。我不知道有一个比必要更大的缓冲区可能会导致问题。不过,.trim() 对我来说是一个更简单的解决方案。
  • @AaronFranke 即使您需要一个数组,使用Files#readAllLines 并在结果上执行toArray 的便利性在这里也是一个强有力的论据(除了您的情况之外,您 真的需要读取原始的char[]数组很少见...)
【解决方案4】:

您可以像这样使用BufferedReaderFileReader 中读取一行

 public static String[] readFile(String FileName) {
        ArrayList<String> stringArrayList = new ArrayList<>();
        BufferedReader bufferedReader;

        try {
            bufferedReader = new BufferedReader(new FileReader(FileName));
            String line;
            while ((line = bufferedReader.readLine()) != null) {
                stringArrayList.add(line);
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
        return stringArrayList.toArray(new String[0]);
    }

【讨论】:

猜你喜欢
  • 1970-01-01
  • 2017-11-27
  • 1970-01-01
  • 2021-10-19
  • 2021-10-03
  • 2017-01-01
  • 1970-01-01
  • 2014-09-21
  • 1970-01-01
相关资源
最近更新 更多