Вычислить и напечатать сумму и среднее значение пар имен и значений


Я просто ищу более отзывы о стиль/подход к этой мелкой проблеме. Также, если у вас есть советы, чтобы сделать его более читабельным или C++-как, Пожалуйста, дайте мне знать.

Кроме того, почему проблема прошу сумму и среднее значение каждого имени и все имена, а сумма один элемент сам? Я ничего не упускаю в плане ответа на вопрос?

#include <stdio.h>
#include <stdlib.h>
#include <map>
#include <string>
#include <iostream>
#include <sstream>
#include <algorithm>
#include <iterator>

/********************************************************************
 * Read a sequence of possibly whitespace-separated (name,value)
 * pairs, where the name is a single whitespace-separated word and
 * the value is an integer or floating-point value. Compute and print
 * the sum and mean for each name and the sum and mean for all names
 * ******************************************************************/

using namespace std;

std::multimap<string,float> _map;

istream& operator>>(istream& stream, pair<string,float> &in ) {
    return stream >> in.first >> in.second;
}

ostream& operator<<(ostream& stream, pair<string,float> &out ) {
    return stream << "(" << out.first 
                  << ", " << out.second << ")" << endl;
}

int main( int argc, char *argv[ ] ) { 
    istream *is = &cin;
    do {
        pair<string,float> input;
        (*is) >> input;
        _map.insert(input);
    } while( is->peek( ) != EOF );

    ostream *os = &cout;
    multimap<string,float>::iterator mit = _map.begin( );
    float sum = 0.0;
    while( mit != _map.end( ) ) {
        pair<string,float> p_pair = (*mit);
        (*os) << p_pair;
        sum+=p_pair.second;
        mit++;
    }
    float mean = static_cast<float>( sum/_map.size( ) );
    (*os) << "Sum: " << sum << " Mean: " << mean << endl;
}


616
3
задан 1 августа 2011 в 09:08 Источник Поделиться
Комментарии
3 ответа

Хотя это может быть немного больше (я не удосужился сосчитать линии), я думаю, я бы предпочел что-то вроде этого:

#include <map>
#include <string>
#include <numeric>
#include <iostream>
#include <utility>
#include <iterator>
#include <algorithm>

typedef std::multimap<std::string, float> vtype;
typedef std::pair<std::string, float> ptype;

namespace std {
std::istream &operator>>(std::istream &is, ptype &v) {
return is >> v.first >> v.second;
}
}

float add_second(float a, vtype::value_type b) {
return a + b.second;
}

template <class FwdIt>
float average(FwdIt start, FwdIt end) {
float total = std::accumulate(start, end, 0.0f, add_second);
return total / std::distance(start, end);
}

int main() {
vtype values((std::istream_iterator<ptype>(std::cin)),
std::istream_iterator<ptype>());

vtype::iterator start, end;

for (start = values.begin(); start != values.end(); start=end) {
end = values.upper_bound(start->first);
std::cout << start->first << ": " << average(start, end) << "\n";
}
std::cout << "Overall: " << average(values.begin(), values.end()) << "\n";
return 0;
}

Если вы предпочитаете, вы можете использовать СТД::вектор вместо СТД::Мультикарты. Это потребует внесения некоторых незначительных изменений в код (например, с помощью функции std::объектом upper_bound , а не с std::multimap, в::объектом upper_bound, и добавление вызова функции std::сортировать прочитав данные, но в противном случае были бы очень похожи. Было бы, однако, вероятно, быть немного более эффективным (меньше процессорного времени и памяти).

В то время как я полагаю, другие могут не согласиться, я предпочитаю это по той простой причине, что мне легче понять. Мы начнем с чтения всех данных. Мы потом найти каждого запуска одинаковыми ключами, и вычислить среднее значение для этого бегите и распечатать его. Когда мы достигнем конца данных, мы делаем то же самое для среднего.

Справедливости ради, если вы работаете с огромными объемами данных, это, вероятно, не лучший способ делать вещи. Он проводит больше времени, проходя через одни и те же данные, чем это представляется строго необходимым. В то же время, если вы собираетесь переписать код, чтобы перекрывать чтение данных с вычислением результата, маловероятно, чтобы сделать, сколько реальная разница-почти независимо от того, как вы сделаете расчет, что I/O будет почти наверняка занимают подавляющее большинство из общего времени.

3
ответ дан 1 августа 2011 в 08:08 Источник Поделиться

Комментарии:

На уровне файла все слова, начинающиеся с подчеркивания зарезервированы.
См.: https://stackoverflow.com/questions/228783/what-are-the-rules-about-using-an-underscore-in-a-c-identifier/228797#228797

std::multimap<string,float> _map;

Правила aexct являются боль, чтобы помнить (я должен был пойти и проверить, чтобы убедиться, что он был зарезервирован). Поэтому я никогда не префикс идентификатора с '_'.

Я не мог бы определить операторы потока для стандартных типов.

istream& operator>>(istream& stream, pair<string,float> &in ) 
ostream& operator<<(ostream& stream, pair<string,float> &out )

Проблема с этим заключается в том, что вы можете (в крупных проектах) столкновение с другими людьми, выполняющими ту же или со стандартными операторами. (Я правда это уже будет работа для std::пара без какой-либо работы (очевидно, я ошибся)) я хотел только написать операторам трансляций от моих собственных видах.

Ссылки вашего друга:

istream *is = &cin;

Почему взять адрес потока. Создать ссылку:

istream& is = &cin;

Это почти наверняка не так:

    (*is) >> input;
_map.insert(input);

Что произойдет, если оператор ввода не удается?

    while(is >> input)
{
// Do until the input fails.
}

Так что переписывание вашего цикла:

pair<string,float> input;
while(is >> input)
{
// Is not the whole point that a name may appear multiple times.
// Otherwise why compute the sum and average for each name
// Thus you need to increment the count.
myMap[input.first] += input.second;
}

Не большое дело с небольшим объектом, но я хотел бы получить в привычку использовать ссылки.

pair<string,float> p_pair = (*mit);         // This makes a copy.

pair<string,float> const& p_pair = (*mit); // This is an alias to the object.

Вот что я бы сделал:

#include <map>
#include <memory>
#include <iterator>
#include <algorithm>
#include <iostream>

// Simple formatter used to
// Print the data in a particular way. This formatter is tied to the particular storage format.
struct OutputFormater
{
std::map<std::string, std::pair<int, int> >::value_type const& data;

OutputFormater(std::map<std::string, std::pair<int, int> >::value_type const& d)
: data(d)
{}

friend std::ostream& operator<<(std::ostream& stream, OutputFormater const& value)
{
std::string const& name = value.data.first;
int const& count = value.data.second.first;
int const& sum = value.data.second.second;

return stream << name << ": " << sum << ": " << (sum/count) << " ";
}
};

Это я надеюсь, делает главное очень удобно читать.

int main()
{
std::map<std::string, std::pair<int, int> > data;
std::string name;
int count;

int totalCount = 0;
int totalSum = 0;

// Read in the data
while(std::cin >> name >> count)
{
totalCount++;
totalSum += count;
data[name].first++; // increment the count;
data[name].second += count; // increment the sum of counts;
}

// Copy the container to a stream using a formatter.
std::copy(data.begin(), data.end(), std::ostream_iterator<OutputFormater>(std::cout, "\n"));
if (totalCount > 0)
{
std::cout << totalSum << ": " << totalSum/totalCount << "\n";
}
}

2
ответ дан 1 августа 2011 в 07:08 Источник Поделиться

Это альтернативное решение, которое также использует многие вещи из стл. Это не имеет отдельного входа из расчета, хотя.

#include <algorithm>
#include <iostream>
#include <map>
#include <numeric>
#include <string>
#include <utility>

using std::cin;
using std::cout;
using std::map;
using std::pair;
using std::string;

/********************************************************************
* Read a sequence of possibly whitespace-separated (name,value)
* pairs, where the name is a single whitespaace-separated word and
* the value is an integer or floating-point value. Compute and print
* the sum and mean for each name and the sum and mean for all names
* ******************************************************************/

void data_print_plain(const string &name, double sum, int count) {
double mean = sum / count;
cout << name << " sum " << sum << " mean " << mean << "\n";
}

void data_print(const pair<string, pair<double, int> > &p) {
data_print_plain(p.first, p.second.first, p.second.second);
}

double add(double x, const pair<string, pair<double, int> > &p) {
return x + p.second.first;
}

int main() {
map<string, pair<double, int> > data;

string name;
double value;
while (cin >> name >> value) {
pair<double, int> &p = data[name];
p.first += value;
p.second++;
}

for_each(data.begin(), data.end(), data_print);

cout << "\n";
double total = accumulate(data.begin(), data.end(), 0.0, add);
data_print_plain("total", total, data.size());

return 0;
}

0
ответ дан 20 августа 2011 в 07:08 Источник Поделиться