1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117
|
#include <algorithm> // max_element(), minmax_element(), max(), count_if()
#include <ciso646> // and or
#include <iostream> // cin, cout
#include <limits> // numeric_limits<>
#include <map> // map<>
#include <numeric> // accumulate()
#include <sstream> // istringstream
#include <string> // string
#include <vector> // vector
int main()
{
// This is our list of integer numbers.
std::vector <int> xs;
{
// Instruct the user and get input as a STRING.
std::cout << "Enter a bunch of numbers with value in [1,50], separated by spaces.\n";
std::string s;
getline( std::cin, s );
// Now we'll convert the string to the list of numbers, checking along the way that
// the user only inputs INTEGER numbers in the range [1,50]. If the user fails to
// input an integer, the stream state will fail automatically. Else if the number is
// out of range, we fail the stream ourselves.
std::istringstream ss{ s };
int x;
while (ss >> x)
if ((1 <= x) and (x <= 50)) xs.push_back( x );
else ss.setstate( std::ios::failbit );
// Either way, if we didn't read the ENTIRE stream, something went wrong.
// Tell the user and make him (or her) start over.
if (!ss.eof())
{
std::cout << "One of those things is not a number in [1,50].\nFooey.\n";
return 1;
}
}
// Great. Now to print our list of numbers.
std::cout << "Numbers:";
for (int x : xs) std::cout << " " << x;
std::cout << "\n";
// The average is the sum of all elements divided by the cardinality.
// We use two functions to help us:
// accumulate() sums all the numbers
// max() makes sure we don't try to divide by zero (in case the user entered nothing)
// (We could just say "None" like below, but this shows something useful.)
std::cout << "Average Number = "
<< std::accumulate( xs.begin(), xs.end(), 0 ) / std::max( 1ULL, xs.size() )
<< "\n";
// Finding the maximum value in a list is also a function in in C++.
// We just need to be careful again about the possiblity of an empty list.
std::cout << "Max Number = ";
if (xs.size()) std::cout << *std::max_element( xs.begin(), xs.end() ) << "\n";
else std::cout << "None\n";
// The range is a single number!
// It is the difference between the largest and the smallest values in the array.
// Here is another function, this time it finds both min and max at the same time.
// (We could have used it above and avoided finding the max twice.)
std::cout << "Range = ";
auto mm = std::minmax_element( xs.begin(), xs.end() );
if (xs.size()) std::cout << (*mm.second - *mm.first) << "\n";
else std::cout << "None\n";
// The mode is the number that appears most often in the list.
// In order to find it, we first need a histogram.
// A HISTOGRAM is a list of pairs. Each pair is composed of two parts:
// * an x value (from xs)
// * a count (the number of times x appears in xs)
// To build it we simply loop through xs and increment the count for every x
// we find. (Counts start at zero.)
std::map <int, unsigned> histogram;
for (int x : xs) histogram[ x ] += 1;
// Since the mode only exists if there is a SINGLE element that occurs most,
// we need to code against the possibility that it does not exist.
// First, we find ANY element with the largest count.
auto max0 = std::max_element( histogram.begin(), histogram.end(),
// This here magic is a LAMBDA -- it is a function, just without a name.
// It takes two (x, count) pairs and compares their counts. The max_element()
// function uses it to find the largest pair (the one with the largest count).
[]( auto a, auto b ) { return a.second < b.second; } );
// Now we want to know how many pairs in our histogram have the same count as
// the element we just found.
auto n = std::count_if( histogram.begin(), histogram.end(),
// Again we use a LAMBDA -- an unnamed function that takes a pair and
// returns whether or not that pair's count is the same as max0's count.
[&max0]( auto p ) { return p.second == max0->second; } );
// Finally, we can print our result, but only if the maximum count is unique.
if (n == 1) std::cout << "Mode = " << max0->first << "\n";
else std::cout << "No Mode\n";
// Printing the histogram is very much like printing xs: loop through
// all pairs and print both parts (x, count).
std::cout << "Histogram:\n";
for (auto p : histogram)
std::cout << "Value = " << p.first << " : " << p.second << " time(s)\n";
// To keep the terminal open, use something like the following.
// * The next line is commented out because we used getline() to read a string
// as our last input into the program.
// * If we had used something like "std::cin >> foo" as our last input, then
// we would need to uncomment the line in order to get rid of the unread
// newline sitting in the input buffer.
//std::cin.ignore( std::numeric_limits <std::streamsize> ::max(), '\n' );
// Finally, give the user instruction and wait.
std::cout << "Press Enter to quit...";
std::cin.get();
}
|