【问题标题】:reading text on file and verifying through an array on java读取文件中的文本并通过 java 上的数组进行验证
【发布时间】:2018-09-06 05:49:21
【问题描述】:

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

Edit#2(之后我会通过 cmd 运行这个程序)

这个程序有许多命令行参数:

1) 要打开的文件

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

如果你不给它任何要搜索的词,它默认为这些词:“医生”, “科学怪人”、“那个”、“怪物”、“伊戈尔”、“学生”、“大学”、“闪电”、 “电”、“血”、“魂”。 你可能想用更少或不同的词来运行它,例如:

$ 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 ]", "");

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

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

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

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

EDIT 9/7/18 更新说明 在 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 中为您设置好了,它将输出您的代码运行所用的时间。 你的工作是实现和调用你的函数,并确保它们正常工作 正确。如果您查看起始代码,您会发现我们正在运行您的两个不同的 search 和 count 方法 100 次,以便得到一个很好的平均值。 需要。我们只进行一次排序,因为对 75289 个单词的数组进行排序已经需要 一会儿。 4. 使用合并排序对单词数组进行排序 (35 分) ● 实现mergeSort(不要使用Java 内置的Array.sort 进行这个赋值) ● 在 main 中调用你的新方法 ● 检查你是否正确:​ 单词(在输出中的 SORTED 之后)将在 按字母顺序。 执行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) &lt; 0 如果 s1 在 s2 之前按字母顺序排列。

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

在主目录中调用mergeSort​

要在main中调用mergeSort,首先需要创建一个与allWords长度相同的临时字符串数组。

我们要对整个数组进行排序,所以第三个参数应该是allWords 中第一个单词的索引,第四个参数应该是 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 中调用 getSmallestIndexgetLargestIndex 以获得最小的和

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

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

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

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

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

实现getSmallestIndex 方法getSmallestIndex 将是一个递归方法,它使用 binarySearch 方法来查找在数组中找到单词的最小索引。 这种方法的大纲是: ● 使用binarySearch 查找单词的索引。如果索引binarySearch 返回是 -1,然后找不到这个词,getSmallestIndex 应该只是 返回-1。这是基本情况。 ● 如果binarySearch 确实找到了这个词,则递归调用getSmallestIndex on 找到单词之前的数组部分。这是从索引 0 开始 到(但不包括)找到该单词的索引。如果返回 -1 则 我们知道我们已经有了最小的索引,否则递归调用 getSmallestIndex 找到了最小的索引,我们应该返回它。这是 递归情况。 实施getLargestIndex 方法getLargestIndex 将是一个使用binarySearch 的递归方法 方法来查找在数组中找到单词的最大索引。大纲为 此方法与上述getSmallestIndex 的大纲非常相似,不同之处在于 递归调用应该搜索从 where binarySearch 之后开始的数组部分 找到了这个词。 使用​getSmallestIndex​ 和​getLargestIndex​ in main​计算字数 由于您正在使用的数组已按这一点排序,所以都一样 单词彼此相邻出现(例如,单词“frankenstein”的所有 26 次出现 在数组中彼此相邻)。所以如果你找到了最小和最大的索引 一个词,那么你可以只减去两个索引来计算单词!但这并不完全 单词只出现一次(所以第一个和最后一个索引是相同的)和情况 这个词根本没有出现。 检查你是否正确 检查你得到的答案是否与迭代的幼稚方法相同 整个数组。另外,看看这种方法对天真的方法有多快 方法! 示例参数和输出

$​ 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;
    }

}

【问题讨论】:

  • toLowerCase() 是 String 而非 String[] 的方法。
  • 扔掉这个程序,重新开始。并按部就班地工作。这意味着:首先制作一个“获取第一个参数并将其存储在名为文件名的字符串中”的程序。比测试程序是否正确执行。比下一步扩展您的程序并再次测试它。以此类推。
  • 好的,所以我在顶部更新以显示更多上下文,我不确定以下示例代码如何与我的论点联系起来? (这在我完成后在 cmd 中运行)我是否使用扫描仪并自己输入参数?我文件中的文字是论据吗?如果很明显,对不起,我只是不明白被问到什么。
  • @Ralf Renz 我如何将字符串传递给数组然后使 toLowerCase() 工作?
  • 反过来:首先将 toLowerCase() 添加到字符串中,然后将修改后的字符串添加到数组中。

标签: java arrays java.util.scanner


【解决方案1】:

readWords 方法中,您应该仅在读取文件中的单词后调用.toLowerCase().replaceAll()

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

也可以看看我用过的try-with-resources statement的教程。

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;
}

方法很简单,建议使用enhanced for loop
还请考虑Java naming conventions:变量名应以小写字母开头。
编辑:关于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];

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

重构的main方法:

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 循环的标准上限。 NAIVE SEARCH: 块是 queryWords.lengthSORTING:​​m> 块是 words.length

编辑:

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

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

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

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

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

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

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

【讨论】:

  • 据我了解,“科学怪人”应该是查询词的示例。这意味着,程序应该以文件名和查询词“frankenstein”的参数启动。
  • @RalfRenz 实际上,程序从参数中获取文件名和查询词(main 方法的第 5 行)。它还打印每个 queryWords 的出现(第 22 行)。我留下了“弗兰肯斯坦”作为countWordsInUnsorted 方法的示例。无论如何,由于地图,该方法变得无用。
  • 使用映射和 lambda 以及增强的 for 循环对于知道如何编程的人来说是件好事。但 Jordles 只是一个初学者。简单的数组和循环会更好。
  • Ruben DG 和@Ralf Renz 我非常感谢您的帮助 :D,我会仔细查看所有这些并尝试将其合并到我的代码中。不幸的是,我不能使用任何先进的东西,比如地图,因为我的教授不允许。我不得不问,filename 和 queryWord 适合哪些参数? CountWordsInUnsorted 方法?一般来说,这整个赋值是令人困惑的,因为我不知道每个变量做什么和做什么以及我应该在哪里引用它们。我知道我不只是检查“弗兰肯斯坦”,因为这项任务是检查文件中的大量单词。
  • @Jordles 我编辑了答案。您必须像在示例 java CopyCat a b c 中那样提供文件名和要搜索的单词。 'a' 将是文件名(第一个参数),'b' 和 'c' 将被放入 queryWords 数组中,并将被搜索到文件 a 中。 countWordsInUnsorted 获取您要搜索的单词以及您将在其中搜索该单词的数组。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2015-12-02
  • 2015-09-11
  • 1970-01-01
  • 2021-08-09
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多