首页 > 解决方案 > 读取文件中的文本并通过 java 上的数组进行验证

问题描述

所以基本上我必须验证在数组上的文件中计算单词的次数。

编辑#2(之后我将通过 cmd 运行这个程序)

该程序采用许多命令行参数:

1)要打开的文件

2+) 要搜索和计算的单词

如果你不给它任何要搜索的词,它会默认为这些词:“医生”、“科学怪人”、“the”、“monster”、“igor”、“student”、“college”、“lightning” 、“电”、“血”、“魂”。您可能希望使用更少或不同的单词来运行它,例如:

$ java ReadSearchAndSort frankenstein.txt frankenstein doctor igor monster

编辑/更新*:如果我们考虑简单的程序:

public class CopyCat{
public static void main(String[] arguments){
for (int ii = 0; ii < arguments.length; ii++){
System.out.println("Argument "+ ii + " = " +
arguments[ii]);
}
}
}

那么如果我们这样运行它:

$ java CopyCat a b c

我们将得到以下输出

Argument 0 = a
Argument 1 = b
Argument 2 = c

以此为基础:获取第一个参数并将其存储在名为的字符串中filename ● 获取其余参数并将它们放置在名为的字符串数组中 queryWords(这应该具有正确的大小以容纳所有要计数的单词,并且不应该有最大大小——忽略系统的内存需求)

在文件中保留内容时循环扫描扫描仪(即为hasNext()真)并获取文件中的下一个单词(即调用 next()) ● 将单词放入数组中 — 注意,您需要不断调整数组的大小 — ○所以首先在for循环之外实例化一个空数组

String[] words = new String[0]();

○ 然后,当您阅读一个单词时,使用 调整数组大小Arrays.copyof,即

words = Arrays.copyOf(words, words.length+1)

○ 然后将单词放在数组的最后一个位置 ■ … 但首先,我们要将其设为小写

word = word.toLowerCase();

■ 并删除所有非字母

word = word.replaceAll("[^a-zA-Z ]", "");

对于单词列表中的每个单词,我们需要遍历我们读入的单词数组,并计算每个实例。为此,我们将创建一个辅助函数:实现函数<code>countWordsInUnsorted

创建一个计数器变量来记录我们看到一个单词的次数。创建一个循环遍历数组中的每个单词。每次一个词与查询词匹配时,递增计数器。我们需要使用该equals方法,因为我们关心的是两个字符串中是否有相同的字符,而不是它们是完全相同的对象。

完成上述两项任务后,就可以运行代码了。验证 "frankenstein"出现 26 次

总的来说,我无法理解方向以及我应该如何订购我的代码,以便它可以理解。如果您能提供帮助,我将不胜感激。我知道它很长,但这甚至不是整个作业,所以它被缩短了。

编辑 2018 年 9 月 7 日更新说明在 Java 中计时您的代码运行了多长时间?

在本次作业中,我们将看到一些搜索算法比其他算法运行得更快。为了查看速度快多少,我们将记录代码运行所需的时间。

下面是一个计时码的例子:

// Look at the clock when we start
long t0 = (new Date()).getTime();
for (var i = 0; i < 100000; i++) {
 // Do something that takes time
}

// 完成后看时钟

long t1 = (new Date()).getTime();
long elapsed = t1 - t0;
System.out.println("My code took " + elapsed + "milliseconds to
run.")

这已经在 main 中为您设置好了,并将输出您的代码运行多长时间。你的工作是实现和调用你的函数,并确保它们正常工作。如果您查看起始代码,您会看到我们正在运行您的两种不同的搜索和计数方法 100 次,以便获得所需时间的良好平均值。我们只进行一次排序,因为对 75289 个单词的数组进行排序已经花费了一段时间。4. 使用 Merge Sort 对单词数组进行排序(35 分) ● 实现 mergeSort(不要使用 Java 内置的 Array.sort 进行此作业) ● 在 main 中调用你的新方法 ● 检查你是否正确:单词(在输出中排序之后)将按字母顺序排列。实现​<code>mergeSort 实现一个mergeSort对字符串数组进行排序的方法。此方法的签名应为:

public static void mergeSort(String[] arrayToSort, String[]
tempArray, int first, int last)

第一个参数是String[]要排序的,第二个参数是一个空的临时数组,它应该与要排序的数组大小相同,第三个参数是要排序的数组部分的起始索引,第四个参数是要排序的数组部分的结束索引。

请注意,我们将在适当的位置实现排序 arrayToSort 的 mergeSort 版本。这意味着您将未排序的数组传递给 mergeSort 并在调用之后

现在对相同的数组进行排序。请注意,mergeSort 涉及比较值以查看哪个更大。对于数字,您可以使用 < 或 > 来比较它们。

如果您有两个字符串 s1 和 s2,则: ●s1.compareTo(s2) == 0如果 s1 和 s2 包含相同的字符串。

s1.compareTo(s2) < 0如果s1 将在s2 之前按字母顺序排列。

s1.compareTo(s2) > 0如果s1 在s2 之后按字母顺序排列。

在 ​main 中调用​<code>mergeSort​</code>

要调用mergeSortmain,首先需要创建一个长度与allWords.

我们要对整个数组进行排序,所以第三个参数应该是 in 第一个单词的索引,allWords第四个参数应该是 in 最后一个单词的索引allWords。调用 mergeSort 的四个参数是:

● 我们正在排序的数组,即allWords.

● 我们创建的新临时数组的长度与allWords.

● 第一个单词的索引allWords(提示:数组的第一个元素的索引总是什么?)。

● 最后一个单词的索引allWords(提示:如果你知道数组的长度,你可以很容易地计算出最后一个元素的索引)。

检查你是对的 这是否对单词数组进行了排序?该程序每 500 个字打印一次。它们看起来排序了吗?5. 数词(使用二分法)并计时(35 分)

● 实施

public static int binarySearch(String[] sortedWords,
String query, int startIndex, int endIndex)

● 实施

public static int getSmallestIndex(String[] words,
String query, int startIndex, int endIndex)

● 实施

public static int getLargestIndex(String[] words, String
query, int startIndex, int endIndex)

● 在 main 中调用getSmallestIndexandgetLargestIndex以获得最小的和

您要查找的单词出现在排序数组中的最大索引。

使用这两个值来计算该单词出现的次数。● 检查您是否正确:您将获得与第一个搜索部分相同的值,但要快得多。

实现​binarySearch binarySearch 的参数是: ● 要搜索的单词的排序数组。 ● 要搜索的单词。● 数组中开始搜索的索引。● 数组中停止搜索的索引。二进制搜索返回找到单词的数组索引。如果单词在数组中只出现一次,那么这个索引就是它出现的地方。

但是,如果单词在排序后的数组中出现多次(因此该单词的所有实例将在数组中彼此相邻),则该索引将指向组中间的单词之一。

二进制搜索算法不保证这将是组中的第一个元素或组中的最后一个元素。所以我们需要实现一些其他的方法来做到这一点。

实现​<code>getSmallestIndex 方法getSmallestIndex将是一个递归方法,它使用该 binarySearch方法查找在数组中找到单词的最小索引。此方法的概要是: ●binarySearch用于查找单词的索引。如果索引binarySearch 返回 -1,则未找到该词,getSmallestIndex应仅返回 -1。这是基本情况。● 如果binarySearch确实找到了单词,则递归调用getSmallestIndex在找到单词之前的数组部分。这是从索引 0 到(但不包括)找到单词的索引。如果返回 -1,那么我们知道我们已经有了最小的索引,否则递归调用 getSmallestIndex找到最小的索引,我们应该返回它。这是递归的情况。实现 <code>getLargestIndex 方法getLargestIndex将是一个递归方法,它使用 binarySearch 方法来查找在数组中找到一个单词的最大索引。此方法的大纲与上面的大纲非常相似getSmallestIndex,除了递归调用应该搜索从 binarySearch 找到单词之后开始的数组部分。使用 main 中的 <code>getSmallestIndex​ 和 <code>getLargestIndex​ 来计算单词 由于您正在使用的数组已经排序,因此所有相同的单词会彼此相邻出现(例如,所有 26单词“frankenstein”的出现在数组中彼此相邻)。因此,如果您找到了单词的最小和最大索引,那么您只需减去两个索引即可计算单词!但这并不是单词只出现一次(因此第一个和最后一个索引相同)以及单词根本没有出现的情况。检查你是否正确 检查你得到的答案是否与遍历整个数组的幼稚方法相同。还,看看这种方法比天真的方法快多少!示例参数和输出

$​ java ReadSearchAndSort frankenstein.txt student college frankenstein blood the
Arguments: use ''student,college,frankenstein,blood,the'' words, time 100 iterations, search for words:
student,college,frankenstein,blood,the
NAIVE SEARCH:
student:2
college:3
frankenstein:26
blood:19
the:4194
96 ms for 500 searches, 0.192000 ms per search
SORTING:
38 ms to sort 75097 words
SORTED (every 498 word): a a aboard affection all although ancient and and and and and angel approached
as asked attended be been believe boat but but by cause clerval comprehensive continued country dante
decay desire died do duvillard end escape exception eyes favourite few flourishing for frankenstein from
girl grief had happiness have he heart her his histories however i i i i i ice impossible in in
inhabitants investigating it its know leaves limbs love man me me might mixture most my my my my nature
no not oatmeal of of of of of old on or over passed philosophy possession profoundly rain regular
resolve room saved seem shape should smiles some spirit straw sun tavernier that that the the the the
the the the the the then thick those time to to to to town uncle upon vessels was was was were when
which while will with with would you you
BINARY SEARCH:
student:2
college:3
frankenstein:26
blood:19
the:4194
6 ms for 500 searches, 0.012000 ms per search

当然,运行搜索和排序的实际时间会因您的计算机而异,具体取决于您的计算机的速度以及在其上运行的其他进程的数量。

编辑 9/7/18

 import java.io.*;
import java.util.*;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.Scanner;

public class ReadSearchAndSort {
    public static void main(String[] args) throws FileNotFoundException {
        String filename = args[0];
        int n = args.length - 1;
        String[] queryWords = null;
        String[] allWords = readWords("frankenstein.txt");
        String[] tempAllWords = new String[allWords.length];
        if (n > 0) { //if user provides the querywords
            queryWords = new String[n];
            for (int i = 1; i < args.length; i++) {
                queryWords[i - 1] = args[i];
            }
        } else { //if user doesn't provide querywords
            queryWords = new String[]{"doctor", "frankenstein", "the", "monster", "igor", "student", "college", "lightning", "electricity", "blood", "soul"};
        }
        ReadSearchAndSort.readWords("C:/Users/Jordles/IdeaProjects/TimeConversionToSecond.java/out/production/GettingStarted/cs141/frankenstein.txt");


        int timingCount = 100;
        System.out.println("\nArguments: use '" + String.join(",", queryWords) + "' words, time " + timingCount + " iterations, search for words: " + String.join(",", queryWords) + "\n");


        System.out.println("NAIVE SEARCH:");


        // Record the current time
        long t0 = new Date().getTime();

        // Time how long it takes to run timingCount loops
        //   for countWordsInUnsorted
        for (int j = 0; j < timingCount; j++) {
            for (int i = 0; i < queryWords.length; i++) {
                int count = countWordsInUnsorted(allWords, queryWords[i]);
                if (j == 0) {
                    System.out.println(queryWords[i] + ":" + count);
                }
            }
        }

        long t1 = (new Date()).getTime();

        long timeToSearchNaive = t1 - t0;
        int searchCount = timingCount * queryWords.length;

        // Output how long the searches took, for how many searches
        // (remember: searches = timingcount * the number of words searched)
        int searches = timingCount * 500;
        System.out.printf("%d ms for %d searches, %f ms per search\n", timeToSearchNaive, searchCount, timeToSearchNaive * 1.0f / searchCount);

        // Sort the list of words
        System.out.println("\nSORTING: ");
        mergeSort(allWords, tempAllWords, 0, allWords.length);

        long t2 = (new Date()).getTime();

        // Output how long the sorting took
        long timeToSort = t2 - t1;
        System.out.printf("%d ms to sort %d words\n", timeToSort, allWords.length);

        // Output every 1000th word of your sorted wordlist
        int step = (int) (allWords.length * .00663 + 1);
        System.out.print("\nSORTED (every " + step + " word): ");
        for (int i = 0; i < allWords.length; i++) {
            if (i % step == 0)
                System.out.print(allWords[i] + " ");
        }
        System.out.println("\n");


        System.out.println("BINARY SEARCH:");

        // Run timingCount loops for countWordsInSorted
        // for the first loop, output the count for each word

        for (int j = 0; j < timingCount; j++) {
            for (int i = 0; i < queryWords.length; i++) {
                int count = countWordsInUnsorted(allWords, queryWords[i]);
                if (j == 0) {
                    System.out.println(queryWords[i] + ":" + count);
                }
            }
        }
        long t3 = (new Date()).getTime();

        long timeToSearchBinary = t3 - t2;
        System.out.printf("%d ms for %d searches, %f ms per search\n", timeToSearchBinary, searchCount, timeToSearchBinary*1.0f/searchCount);

    }
    public static String[] readWords(String fileName) throws FileNotFoundException{
        String[] words = new String[0];
        int i = 0;

        File file = new File(fileName);
        Scanner input = new Scanner(file, "UTF-8");
        input.useDelimiter("\\s+|\\-");

        while(input.hasNext()){
            String word = input.next();
            word = word.toLowerCase();
            word = word.replaceAll("[^a-zA-Z ]", "");
            words = Arrays.copyOf(words, words.length + 1);
            words[i++] = word;
        }
        return null;
    }


    public static int countWordsInUnsorted(String[] WordsToCount, String countedWord){
        if ((countedWord == null) || (WordsToCount == null)){
            return 0;
        }
        int counter = 0;
        for( String word : WordsToCount){
            if (word.equals(countedWord)){
                counter++;
            }
        }

        return counter;
    }
    public static void mergeSort(String[] arrayToSort, String[] tempArray, int first, int last){
        if (first == last){
            return;
        }
        int mid = (first + last)/2;
        mergeSort(arrayToSort, tempArray, first, mid);
        mergeSort(arrayToSort, tempArray, mid + 1, last);
        merge(arrayToSort, tempArray, first, mid, mid + 1, last);


    }
    public static void merge(String[] arrayToSort, String[] tempArray, int first, int mid, int mid1, int last){
        int j = first;
        int k = mid1;
        int l = first;
        do{
            if (tempArray[j].compareTo(tempArray[k]) < 0){
                arrayToSort[l] = tempArray[j];
                j++;
            }
            else{
                arrayToSort[l] = tempArray[k];
                k++;
            }
        }
        while (j <= mid && k <= last){

        }
    }
    public static int binarySearch(String[] sortedWords, String query, int startIndex, int endIndex){
        if (startIndex > endIndex){

        }
        int mid = (startIndex + endIndex)/2;
        if(query.compareTo(sortedWords[mid]) == 0){
            return;
        }
        if (query.compareTo(sortedWords[mid]) < 0){
            binarySearch(sortedWords, query, startIndex, mid -1 );
        }
        if (query.compareTo(sortedWords[mid]) > 0){
            binarySearch(sortedWords, query, mid + 1, endIndex);
        }
        return -1;
    }
    public static int getSmallestIndex(String[] words, String query, int startIndex, int endIndex){
        return -1;
    }
    public static int getLargestIndex(String[] words, String query, int startIndex, int endIndex){
        return -1;
    }
    public static int countWordsInSorted(String[] wordsTocount, String countedWord){
        return 0;
    }

}

标签: javaarraysjava.util.scanner

解决方案


readWords您应该调用的方法中,.toLowerCase()并且.replaceAll()只有在读取文件中的单词之后。

编辑:return null;不能是方法的唯一返回,否则你只是扔掉了方法所做的一切。你可以用它来处理错误,但我强烈建议返回一个空数组。
如果您返回一个空数组(或集合),您可以避免意外的 NullPointerException 让该方法的使用者(调用您的方法的人)感到惊讶,因此他们不必防范它。

还可以查看我使用过的try-with-resources 语句的教程。

public static String[] readWords(final String filename) {
    // Check on input
    if (filename == null) {
        return null;
    }
    String[] words = new String[0];
    int i = 0; // index of the first empty position in the array
    final File inputFile = new File(filename);
    try (Scanner in = new Scanner(inputFile)) {
        in.useDelimiter("\\s+|\\-");
        while (in.hasNext()) {
            String word = in.next().toLowerCase();
            word = word.replaceAll("[^a-z ]", ""); // No need of A-Z since we called .toLowerCase()
            words = Arrays.copyOf(words, words.length + 1);
            words[i++] = word; // Put the current word at the bottom of the array, then increment the index
        }
    } catch (final FileNotFoundException e) {
        System.err.println("The file " + filename + " does not exist");
        return null;
    }

    return words;
}

方法很简单,建议使用增强的for循环
还请考虑Java 命名约定:变量名应以小写字母开头。
编辑:关于return 0;. 它不能是方法的唯一返回。

public static int countWordsInUnsorted(final String searchedWord, final String[] words) {
    // Check on input
    if ((searchedWord == null) || (words == null)) {
        return 0;
    }

    int count = 0;
    for (final String word : words) {
        if (word.equals(searchedWord)) {
            count++;
        }
    }
    return count;
}

编辑4

该程序采用一个命令行参数:要搜索和计数的单词。
java SearchAndSort "科学怪人,医生,伊戈尔,怪物"

由于赋值使用逗号作为分隔符,您可以使用String.split()来获取字符串数组。

由于需要计算经过的时间,无法搜索和打印单词:打印操作非常耗时,因此会扭曲结果。这就是为什么我使用一个 int 数组来存储每个单词的计数。
int[] wordsCounter = new int[queryWords.length];

为了计算每次搜索的时间,您需要 a double,但如果您在 之间进行算术运算long,您将始终得到 a long。这就是为什么您需要将至少一个操作数转换为double.
double timePerSearch = ((double) elapsedTime) / totalSearches;

重构的主要方法:

public static void main(final String[] args) {
    // Default words to search for
    String queryWordsString = "doctor,frankenstein,the,monster,igor,student,college,lightning,electricity,blood,soul";

    if (args.length > 0) { // If the user provided  query words
        queryWordsString = args[0];
    }

    final String[] queryWords = queryWordsString.split(","); // split the string into an array

    System.out.println("SEARCH AND SORT");
    System.out.println();
    System.out.println("Searching and counting the words " + queryWordsString); // print the words to search for
    System.out.println();

    // Just the name of the file if it's in the same directory of program
    // The absolute path if they are in different directory
    final String filename = "frankenstein.txt";

    // Read words from file
    final String[] words = SearchAndSort.readWords(filename);
    if (words == null) {
        return;
    }

    final int[] wordsCounter = new int[queryWords.length];

    // Store the starting time
    final long startTime = System.currentTimeMillis();

    // Search the words and store their count
    for (int i = 0; i < queryWords.length; i++) {
        final int count = SearchAndSort.countWordsInUnsorted(queryWords[i], words);
        wordsCounter[i] = count;
    }

    final long elapsedTime = System.currentTimeMillis() - startTime;

    System.out.println("NAIVE SEARCH:");
    // Print how many time each word appears
    for (int i = 0; i < queryWords.length; i++) {
        System.out.println(queryWords[i] + ": " + wordsCounter[i]);
    }

    final int totalSearches = queryWords.length * words.length;
    final double timePerSearch = ((double) elapsedTime) / totalSearches;
    // Print the elapsed time in ms
    System.out.println(elapsedTime + " ms for " + totalSearches + " searches, " + timePerSearch + " ms per search");
}

编辑4

long t0 = ( new Date()).getTime();  
for (var i = 0 ; i < 100000 ; i++) {  
    // Do something that takes time  
}  

在这个例子中,这100000不是一个新变量,它是你将要使用的 for 循环的标准上限。它queryWords.length适用于NAIVE SEARCH:块和words.lengthSORTING :块。

编辑:

// Record the current time  
long t0 = (new Date()).getTime();  

不要这样做。如果你想测量经过的时间,你应该使用long t0 = System.nanoTime(). 从文档

返回正在运行的 Java 虚拟机的高分辨率时间源的当前值,以纳秒为单位。

此方法只能用于测量经过的时间,与系统或挂钟时间的任何其他概念无关。返回的值表示自某个固定但任意的原始时间以来的纳秒(可能在将来,因此值可能为负数)。在 Java 虚拟机实例中,此方法的所有调用都使用相同的来源;其他虚拟机实例可能使用不同的来源。

此方法提供纳秒精度,但不一定提供纳秒分辨率(即值更改的频率) - 不保证分辨率至少与 currentTimeMillis() 的分辨率一样好。
[...] 只有在计算同一 Java 虚拟机实例中获得的两个此类值之间的差异时,此方法返回的值才有意义。

例如,要测量一些代码需要多长时间执行:

可能您也会阅读System.currentTimeMillis() 文档


推荐阅读