简体   繁体   English

圆形 function 似乎无法正常工作

[英]Round function doesn't seem to work properly

C++ C++

The job is to find the average length of series of strings.工作是找到一系列字符串的平均长度。

I used this code and it does work for 1st,2nd and 4th test cases (out of total 5)( ps the inputs are unknown)我使用了这段代码,它确实适用于第一个、第二个和第四个测试用例(总共 5 个)(ps 输入未知)

#include <cmath>
#include <iostream>

using namespace std;

int main() {
  string input;
  int k = 0;
  int sum = 0;

  while (cin >> input) {
    int n = input.size();
    k++;
    sum += n;
  }

  float out = (float)sum / k;
  cout << (int)round(out);

  return 0;
}

When I use cout<<round(out);当我使用cout<<round(out); It gives the same result.它给出了相同的结果。

When I use cout<<ceil(out);当我使用cout<<ceil(out); The last 4 cases are correct and the first one fails.最后4个案例是正确的,第一个案例失败了。

When I use cout<<floor(out);当我使用cout<<floor(out); Only the 1st case is correct and all else fail.只有第一种情况是正确的,其他的都失败了。

What am I missing?我错过了什么?

The question问题

You are in a college level English class, your professor wants you to write an essay, but you need to find out the average length of all the words you use.你是大学水平的英语 class,你的教授要你写一篇论文,但你需要找出你使用的所有单词的平均长度。 It is up to you to figure out how long each word is and to average it out.由您决定每个单词的长度并将其平均。 Task: Takes in a string, figure out the average length of all the words and return a number representing the average length.任务:接受一个字符串,计算出所有单词的平均长度,并返回一个代表平均长度的数字。 Remove all punctuation.删除所有标点符号。 Round up to the nearest whole number.四舍五入到最接近的整数。

Input Format: A string containing multiple words.输入格式:包含多个单词的字符串。

Output Format: A number representing the average length of each word, rounded up to the nearest whole number. Output 格式:一个数字,代表每个单词的平均长度,四舍五入到最接近的整数。

Sample Input: this phrase has multiple words示例输入:这个短语有多个单词

Sample Output: 6样品 Output: 6

Test case 1 Can you not do that?测试用例 1你不能这样做吗?

Answer 3答案3

Test case 2 The longest word in the dictionary is...测试用例2字典中最长的单词是...

Answer 5答案5

Without seeing example inputs, I'm just guessing at the format.没有看到示例输入,我只是在猜测格式。 When trying to run your code in my editor, I get an infinite loop.当试图在我的编辑器中运行你的代码时,我得到一个无限循环。 This is because std::cin doesn't convert to false if you just press Enter (Empty string).这是因为如果您仅按 Enter(空字符串), std::cin不会转换为false So my code makes the assumption that all the words are entered on a single line.所以我的代码假设所有单词都输入在一行中。 Which means I now have to split the line into individual words.这意味着我现在必须将行拆分为单个单词。

To make it work with std::cin , I'd have to press Ctrl+d (WSL Debian) to break out of the loop, and I don't like that at all.为了使它与std::cin一起工作,我必须按Ctrl+d (WSL Debian) 才能跳出循环,我一点也不喜欢这样。

The biggest issue you have is that you don't strip punctuation.你最大的问题是你没有去掉标点符号。 If you don't do that, the punctuation marks add to your string length and will throw your average off.如果你不这样做,标点符号会增加你的字符串长度,并且会让你的平均水平下降。 You also read "Round up the nearest whole number" as simply rounding, which can round up or down.您还将“四舍五入”理解为简单的四舍五入,它可以向上向下舍入。 The function you want is std::ceil() , as it will always go up to the next whole number.您想要的 function 是std::ceil() ,因为它总是 go 直到下一个整数。

#include <algorithm>  // std::remove_if, std::copy
#include <cctype>     // std::isalpha
#include <cmath>
#include <iostream>
#include <iterator>  // std::istream_iterator
#include <numeric>   // std::accumulate
#include <sstream>   // for easier (in code) string split on whitespace
#include <vector>    // Dynamic array for holding individual words

// Splits whole line string into vector of individual words
std::vector<std::string> split(std::string line) {
  std::vector<std::string> tmp;
  std::stringstream stream(line);

  std::copy(std::istream_iterator<std::string>(stream),
            std::istream_iterator<std::string>(), std::back_inserter(tmp));

  return tmp;
}

// Strips non-alphabetic characters from each word in a vector of words
std::vector<std::string> strip(std::vector<std::string> words) {
  for (auto& word : words) {
    word.erase(std::remove_if(word.begin(), word.end(),
                              [](const auto& x) { return !std::isalpha(x); }),
               word.end());
  }

  return words;
}

int main() {
  std::string input;

  std::getline(std::cin, input);  // Reads a whole line of input until Enter
  auto words = split(input);
  words = strip(words);

  if (words.size() == 0) {
    std::cout << 0;
    return 0;
  }

  // Once words is cleaned up, it's possible to get the mean directly
  std::cout << static_cast<int>(std::ceil(std::accumulate(
      words.begin(), words.end(), 0.0,
      [numWords = words.size()](const auto& mean, const auto& x) {
        return mean + (static_cast<double>(x.length()) / numWords);
      })));

  // Or the mean can still be calculated in a more manual fashion
  // int sum = 0;
  // for (auto i : words) {
  //   sum += i.length();
  // }

  // int mean =
  //     static_cast<int>(std::ceil(static_cast<double>(sum) / words.size()));
  // std::cout << mean;

  return 0;
}

Inputs (separate run per line):输入(每行单独运行):

I want to write something
I() want, to. write*&^%$#@! something?

Output for both inputs is 5, which should be correct according to your requirements.两个输入的 Output 为 5,根据您的要求应该是正确的。

The main thing you will want is the strip() function.您需要的主要内容是strip() function。

I break the work up into a few functions, which makes the work in the main function easier to follow.我将工作分解为几个函数,这使得主 function 中的工作更容易理解。 I use a "one-liner" to directly calculate the mean and then print it, but I left a more manual approach in the comments.我使用“单线”直接计算平均值然后打印它,但我在评论中留下了更手动的方法。 Some extra verbosity is added by my explicitly casting the double returned from std::ceil() to an int .我将std::ceil()返回的double显式转换为int会增加一些额外的冗长。 Prefer static_cast over the C-style cast, it produces safer code.更喜欢static_cast而不是 C 风格的演员,它产生更安全的代码。

Because I'm using Standard Library functions and constructs where (mostly) possible, I'm also making heavy use of lambdas, the things that generally have the form []() {} .因为我在(大部分)可能的情况下使用标准库函数和构造,所以我也大量使用 lambdas,通常具有[]() {}形式的东西。 Understanding lambdas unlocks a lot of the Standard Library for use, and I highly recommend not putting the subject off for very long.理解 lambdas 可以解锁很多标准库的使用,我强烈建议不要把这个主题搁置很长时间。

If not for the needs to strip out punctuation and round up, the mean calculation would be a lot cleaner.如果不是因为需要去掉标点符号和四舍五入,平均计算会更干净。

It's possible that the structure of the input can simplify the code quite a bit, but it's also possible that your learning source simply didn't properly prepare you for how much effort string parsing usually involves.输入的结构可能会大大简化代码,但也有可能您的学习资源根本没有为您准备好字符串解析通常涉及的工作量。

I suspect you are getting tripped up on a corner-case like a string of all punctuation that goes unhandled leading to a floating point exception or something similar, like ",,, === !!!"我怀疑你被一个极端情况绊倒了,比如所有标点符号的字符串未处理导致浮点异常或类似的东西,比如",,, === !!!" . .

You can handle the case (and all cases) in a number of different ways.您可以通过多种不同的方式处理案件(以及所有案件)。 A direct approach is using the erase-remove of all punctuation and then counting words and characters by creating a stringstream and simply summing both characters and words.一种直接的方法是使用擦除所有标点符号,然后通过创建一个字符串流并简单地将字符和单词相加来计算单词和字符。 No need for a vector to save the words, you just care about the totals with punctuation and spaces removed, eg不需要向量来保存单词,您只关心删除了标点和空格的总数,例如

#include <iostream>
#include <sstream>
#include <string>
#include <cctype>
#include <algorithm>

int main (void) {

    std::string line {};
    size_t nchars = 0, nwords = 0;
    
    if (!getline (std::cin, line))                          /* read line of input */
        return 1;
    
    line.erase (std::remove_if (line.begin(),               /* erase-remove punct */
                                line.end(),
                                [](unsigned char c) {
                                    return ispunct(c);
                                }), line.end());
    
    if (line.find_first_not_of(" \t") == std::string::npos) {   /* all punct/space */
        std::cout << "avg: 0\n";
        return 0;
    }
    
    std::stringstream ss (line);                            /* stringstream from line */
    while (ss >> line) {                                    /* count words */
        nchars += line.length();                            /* add total chars */
        nwords += 1;                                        /* add total words */
    }
    
    std::cout << "avg: " << (nchars + nwords - 1)/nwords << '\n';   /* result */
}

Example Use/Output示例使用/输出

$ ./bin/mean_of_word_len
this phrase has multiple words
avg: 6

or或者

$ ./bin/mean_of_word_len
Can you not do that?
avg: 3

or或者

$ ./bin/mean_of_word_len
The longest word in the dictionary is...
avg: 5

or或者

$ ./bin/mean_of_word_len
The longest word in the dictionary is......................................
avg: 5

or或者

$ ./bin/mean_of_word_len
,,, === !!!
avg: 0

or或者

$ ./bin/mean_of_word_len
,,, a === !!!
avg: 1

Look things over, give it a try, and let me know if you have further questions.仔细检查一下,试一试,如果您还有其他问题,请告诉我。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM