将某些整数从一个数组写入另一个数组

时间:2015-11-30 00:55:26

标签: c++ arrays function

我一直试图将正整数从一个数组中移动到另一个数组中,其值为数值 51 144 5 16 8 0 -2 14 6 -4 173 263 11 9345 -135 777

我的代码是

void pullfilename (string, string&);
void pullnegativenumbers (ofstream&, int, int[], int[]);
void pullpositivenumbers (ofstream&, int, int[], int[]);

int main()
{


ifstream input;
  ofstream output;
  string fname;

  pullfilename("input", fname);
  input.open(fname.c_str());
  pullfilename("output", fname);
  output.open(fname.c_str());

  int n=0;
  int list[50];
  int positive[50];

  input>>list[n];

while (input)
    {
      n++;
        input>>list[n];
    }

 pullnegativenumbers(output, n, list, positive);
 pullpositivenumbers(output, n, list, positive);

  return 0;
}

void pullfilename(string filetype,string& fname)
{
cout<<"Enter name of"<<filetype<<"file"<<endl;
  cin>>fname;
}
void pullnegativenumbers(ofstream& out, int n, int list[], int positive[])
{
int ncount=0;
 int pcount=0;
int nsum=0;
int naverage=0;
 int i;
 for (i=0; i<n; i++)
{
     if (list[i]<0)
  {
    ncount++;
    nsum=nsum+list[i];
  naverage=nsum/ncount;
  out<<left<<setw(15)<<"Negative Values"<<endl;
  out<<left<<setw(6)<<"Count:"<<right<<setw(10)<<ncount<<endl;
  out<<left<<setw(4)<<"Sum:"<<right<<setw(10)<<nsum<<endl;
  out<<left<<setw(8)<<"Average"<<right<<setw(10)<<naverage<<endl;
  }
}
}

void pullpositivenumbers(ofstream& out, int n, int list[], int positive[])
{
  int i;
  for (i=0; i<n; i++)
if (n>=0)
      {
        list[i]=positive[i];
      }
  `out<<positive[i]<<endl;
}

它以我喜欢的方式将我的负数拉到一边,但正数组文件中的输出结果是-123908309 ???

2 个答案:

答案 0 :(得分:2)

  

但我仍然不知道如何将其余的积极因素复制到   单独的数组,以便我以后再使用它们。

您有一系列值,并且您希望将满足特定条件的值放入数组中。这需要一个简单的循环,如果你使用特定的算法函数,即使这是不必要的。

首先,您的代码出错的地方在于您使用list数组不仅可以获取原始值,还可以执行此操作:

void pullpositivenumbers(ofstream& out, int n, int list[], int positive[])
{
  int i;
  for (i=0; i<n; i++)
   if (n>=0)
   {
      list[i]=positive[i];  // you are storing an uninitialized value in list[i]
   }
  out<<positive[i]<<endl;
}

这是完全错误的,因为你用positive数组中的某些值覆盖了你读入的原始数组。

第二件事是错误的是positivelist必须使用不同的索引。您正在使用索引listi进行阅读,但您需要positive的单独索引变量。如果你有这个怎么办:

list -> -1, -2, -3, -4, 10

当你到达list[4]时,你会到达10。但是,您应该在positive[0]而不是positive[4]存储10,因为10之前的数字都是负数。

第三个错误是你的检查是肯定的。您应该比较list[i]以查看它是否为负数,而不是n

if (n>=0)

应该是

if (list[i] >= 0)

所以代码的修复程序似乎就是这样:

void pullpositivenumbers(ofstream& out, int n, int list[], int positive[])
{
  int i;
  int j = 0;
  for (i=0; i<n; i++)
  if ( list[i] >= 0)
  {
     positive[j] = list[i];
     ++j;
  }
}

现在,说完所有这些,你的整个逻辑可以被一些算法函数调用所取代,并且不需要引入任何循环来获取负数或正值。

#include <iostream>
#include <algorithm>
#include <vector>
#include <iterator>

using namespace std;

int main() 
{
    // your test values
    int values[] = {51, 144, 5, 16, 8, 0, -2, 14, 6, -4, 173, 263, 11, 9345, -135, 777};

    // partition negatives to left, positives to right of partition
    auto it = std::stable_partition(begin(values), end(values), [] (int i) { return i < 0;});

    // copy positives to vector
    std::vector<int> positives;
    copy_if(it, end(values), back_inserter(positives), [] (int i) { return i > 0;});

    // sum negatives
    // number of negatives is known, by getting the distance
    // between the start of the array and where partition point is
    size_t numNegatives = std::distance(begin(values), it);

    // get the sum of those negative numbers
    int sum = accumulate(begin(values), it, 0);

    // get the average
    double avg = 0;
    if ( numNegatives > 0 )
       avg = static_cast<double>(sum) / numNegatives;

    // output results
    cout << "Here are the negatives:\n";
    copy(begin(values), it, ostream_iterator<int>(cout, " "));
    cout << "\nSum: " << sum << "\n";
    cout << "Avg: " << avg << "\n\n";

    // Output the positive numbers
    cout << "Here are the positive:\n";
    copy(positives.begin(), positives.end(), ostream_iterator<int>(cout, " "));
}

请注意使用std::stable_partition来更改顺序,以便排列负数和正数,使负数落在左侧,正数落在分区点的右侧(it )。

此外,std::accumulate用于累加底片的用法是使用上面的代码完成的。复制到输出也会使用std::copy将输出流式传输到cout

正如您所看到的,没有任何手写循环来处理数据。相反,代码更具说明性(partition,accumulate,copy,copy_if)。

另外,我使用std::vector来存储积极因素。这将确保我们在存储正数时不限于50个输入项,并且更容易擦除可能在向量中的任何0。如果您仍想坚持使用(不安全)positive数组,那么这一行:

    // copy positives to vector
    std::vector<int> positives;
    copy(it, end(values), back_inserter(positives));

将被替换为:

    // copy positives to vector
    int positives[50];
    //...
    // get number of positives
    size_t numItems = std::distance(it, end(values));

    // copy this number of items or 50 items, whichever is smaller, to the positives array
    copy(it, it + std::min(50, numItems), positives));

请注意我们如何将项目数量限制为最多50项。

See Live Example

答案 1 :(得分:0)

这是根据我认为你想要实现的目标编写的程序。我已经包含了一个带有一些有用功能的实用程序类。它具有错误处理功能。在我的大项目中,我有实际的类,它们将记录到控制台和/或文本文件,处理异常,管理文件句柄以读取和写入特定类型,如基本文本文件,纹理(图像)文件或自定义数据结构文件类型。我没有包括这些,因为它会使这个简单的基本任务程序变得很大,从而不再需要实现和算法。我删除了我的可重用库,只包含了我认为需要的内容以及其他一些有用的有用功能。这段代码可以清除错误,并且可以很好地处理许多常见任务。

<强> stdafx.h中

#ifndef STDAFX_H
#define STDAFX_H

//#define VC_EXTRALEAN

//#include <Windows.h>
//#include <process.h>

//#include <memory>
//#include <numeric>

#include <array>
#include <vector>
#include <list>
#include <unordered_map>
#include <queue>
//#include <regex> - included in <queue> and <array> - needed for std::transform
#include <algorithm>
#include <iterator>

#include <tchar.h>
#include <conio.h>

#include <string>
#include <sstream>
#include <iostream>
#include <iomanip>
#include <fstream>

enum ReturnCode {
    RETURN_OK = 0,
    RETURN_ERROR = 1,
}; // ReturnCode

#endif // STDAFX_H

我评论了在这种情况下不需要的常见基本有用包括,并删除了所有其他完全不相关的包含,如DirectX,OpenGL,Op​​enAL,OggVorbis,GLM包括等。

<强> stdafx.cpp

#include "stdafx.h"

<强> Utility.h

#ifndef UTILITY_H
#define UTILITY_H

class Utility {
public:

    static void pressAnyKeyToQuit();

    static std::string  toUpper( const std::string& str );
    static std::string  toLower( const std::string& str );
    static std::string  trim( const std::string& str, const std::string elementsToTrim = " \t\n\r" );
    static std::vector<std::string> splitString( const std::string& strStringToSplit, const std::string& strDelimiter, const bool keepEmpty = true ); 

    static unsigned     convertToUnsigned( const std::string& str );
    static int          convertToInt( const std::string& str );
    static float        convertToFloat( const std::string& str );    

private:
    Utility(); // Private - Not A Class Object
    Utility( const Utility& c ); // Not Implemented
    Utility& operator=( const Utility& c ); // Not Implemented

    template<typename T>
    static bool stringToValue( const std::string& str, T* pValue, unsigned uNumValues );

    template<typename T>
    static T getValue( const std::string& str, std::size_t& remainder );

}; // Utility

#include "Utility.inl"

#endif // UTILITY_H

<强> Utility.inl

// ----------------------------------------------------------------------------
// stringToValue()
template<typename T>
static bool Utility::stringToValue(const std::string& str, T* pValue, unsigned uNumValues) {
    int numCommas = std::count(str.begin(), str.end(), ',');
    if (numCommas != uNumValues - 1) {
        return false;
    }

    std::size_t remainder;
    pValue[0] = getValue<T>(str, remainder);

    if (uNumValues == 1) {
        if (str.size() != remainder) {
            return false;
        }
    }
    else {
        std::size_t offset = remainder;
        if (str.at(offset) != ',') {
            return false;
        }

        unsigned uLastIdx = uNumValues - 1;
        for (unsigned u = 1; u < uNumValues; ++u) {
            pValue[u] = getValue<T>(str.substr(++offset), remainder);
            offset += remainder;
            if ((u < uLastIdx && str.at(offset) != ',') ||
                (u == uLastIdx && offset != str.size()))
            {
                return false;
            }
        }
    }
    return true;
} // stringToValue 

<强> Utility.cpp

#include "stdafx.h"
#include "Utility.h"

// ----------------------------------------------------------------------------
// pressAnyKeyToQuit()
void Utility::pressAnyKeyToQuit() {
    std::cout << "Press any key to quit" << std::endl;
    _getch();
} // pressAnyKeyToQuit

// ----------------------------------------------------------------------------
// toUpper()
std::string Utility::toUpper(const std::string& str) {
    std::string result = str;
    std::transform(str.begin(), str.end(), result.begin(), ::toupper);
return result;
} // toUpper


// ----------------------------------------------------------------------------
// toLower()
std::string Utility::toLower(const std::string& str) {
    std::string result = str;
    std::transform(str.begin(), str.end(), result.begin(), ::tolower);
    return result;
} // toLower

// ----------------------------------------------------------------------------
// trim()
// Removes Elements To Trim From Left And Right Side Of The str
std::string Utility::trim(const std::string& str, const std::string elementsToTrim) {
    std::basic_string<char>::size_type firstIndex = str.find_first_not_of(elementsToTrim);
    if (firstIndex == std::string::npos) {
        return std::string(); // Nothing Left
    }

    std::basic_string<char>::size_type lastIndex = str.find_last_not_of(elementsToTrim);
    return str.substr(firstIndex, lastIndex - firstIndex + 1);
} // trim

// ----------------------------------------------------------------------------
// getValue()
template<>
float Utility::getValue(const std::string& str, std::size_t& remainder) {
    return std::stof(str, &remainder);
} // getValue <float>

// ----------------------------------------------------------------------------
// getValue()
template<>
int Utility::getValue(const std::string& str, std::size_t& remainder) {
    return std::stoi(str, &remainder);
} // getValue <int>

// ----------------------------------------------------------------------------
// getValue()
template<>
unsigned Utility::getValue(const std::string& str, std::size_t& remainder) {
    return std::stoul(str, &remainder);
} // getValue <unsigned>

// ----------------------------------------------------------------------------
// convertToUnsigned()
unsigned Utility::convertToUnsigned(const std::string& str) {
    unsigned u = 0;
    if (!stringToValue(str, &u, 1)) {
        std::ostringstream strStream;
        strStream << __FUNCTION__ << " Bad conversion of [" << str << "] to unsigned";
        throw strStream.str();
    }
    return u;
} // convertToUnsigned

// ----------------------------------------------------------------------------
// convertToInt()
int Utility::convertToInt(const std::string& str) {
    int i = 0;
    if (!stringToValue(str, &i, 1)) {
        std::ostringstream strStream;
        strStream << __FUNCTION__ << " Bad conversion of [" << str << "] to int";
        throw strStream.str();
    }
    return i;
} // convertToInt

// ----------------------------------------------------------------------------
// convertToFloat()
float Utility::convertToFloat(const std::string& str) {
    float f = 0;
    if (!stringToValue(str, &f, 1)) {
        std::ostringstream strStream;
        strStream << __FUNCTION__ << " Bad conversion of [" << str << "] to float";
        throw strStream.str();
    }
    return f;
} // convertToFloat

// ----------------------------------------------------------------------------
// splitString()
std::vector<std::string> Utility::splitString( const std::string& strStringToSplit, const std::string& strDelimiter, const bool keepEmpty ) {
    std::vector<std::string> vResult;
    if ( strDelimiter.empty() ) {
        vResult.push_back( strStringToSplit );
        return vResult;
    }

    std::string::const_iterator itSubStrStart = strStringToSplit.begin(), itSubStrEnd;
    while ( true ) {
        itSubStrEnd = search( itSubStrStart, strStringToSplit.end(), strDelimiter.begin(), strDelimiter.end() );
        std::string strTemp( itSubStrStart, itSubStrEnd );
        if ( keepEmpty || !strTemp.empty() ) {
            vResult.push_back( strTemp );
        }

        if ( itSubStrEnd == strStringToSplit.end() ) {
            break;
        }

        itSubStrStart = itSubStrEnd + strDelimiter.size();
    }

    return vResult;

} // splitString

我从Utility类中删除了很多函数。例如,我有其他转换函数,将字符串转换为GLM :: Vec2,Vec3,Vec4对象的int,浮点数和双精度数,转换为不同的自定义枚举等。以及其他函数用于测试不同的东西。而不是有一堆常见的有用函数只是浮动处理基本的重复性任务,大多数都处理简单的字符串,转换,测试常见条件等,我喜欢将它们放在类充当类的类中所有这些函数的容器都声明为static。如果您注意到构造函数是私有的,并且该类只有方法没有成员变量。您无法创建实用程序对象。它的工作方式类似于命名空间,您需要使用的是用于访问实用程序功能的范围解析运算符。

<强>的main.cpp

#include "stdafx.h"
#include "Utility.h"

void parseLine( std::string& strLine, std::vector<int>& vPositiveInts, std::vector<int>& vNegativeInts ) {
    if ( strLine.size() == 0 ) {
       // Skip Blank Line
        return;
    }

    std::vector<std::string> vElements = Utility::splitString( strLine, " " );

    int value = 0;
    for ( unsigned u = 0; u < vElements.size(); u++ ) {
        value = Utility::convertToInt( vElements.at( u ) );

        if ( value > 0 ) {
            vPositiveInts.push_back( value );
        } else if ( value < 0 ) {
            vNegativeInts.push_back( value );
        } else {
            // value = 0? Not Sure What User Wants To Do With 0
            continue;
        }
    }

} // parseLine

int main() {

    try {
        std::string strFilename;

        std::cout << "Enter the filename to read in data." << std::endl;    
        std::getline( std::cin, strFilename );

        std::fstream in;
        in.open( strFilename.c_str(), std::ios_base::in );
        if ( !in.is_open() ) {
            std::ostringstream strStream;
            strStream << "Error reading in file " << strFilename << std::endl;
            throw strStream.str();
        }

        if ( in.eof() ) {
            std::ostringstream strStream;
            strStream << "No Data in " << strFilename << std::endl;
            throw strStream.str();
        }
        std::string strLine;
        std::getline( in, strLine );

        std::vector<int> vPositiveInts;
        std::vector<int> vNegativeInts;

        parseLine( strLine, vPositiveInts, vNegativeInts );


        std::cout << "\nPositive Integers" << std::endl;
        for ( unsigned u = 0; u < vPositiveInts.size(); u++ ) {
            std::cout << vPositiveInts.at( u ) << " ";
        }       
        std::cout << std::endl;

        std::cout << "\nNegative Integers" << std::endl;
        for ( unsigned u = 0; u < vNegativeInts.size(); u++ ) {
            std::cout << vNegativeInts.at( u ) << " ";
        }
        std::cout << std::endl << std::endl;

        // User Can Use Similar Methods To Write Data To Their Corresponding Files
        // And Perform The Appropriate Calculations On This Data Using The Vectors Above

    } catch ( std::string& str ) {
        std::cout << "Exception Thrown: " << str << std::endl;
        Utility::pressAnyKeyToQuit();
        return RETURN_ERROR;
    } catch ( ... ) {
        std::cout << __FUNCTION__ << " Caught Unknown Exception" << std::endl;
        Utility::pressAnyKeyToQuit();
        return RETURN_ERROR;
    }

    Utility::pressAnyKeyToQuit();
    return RETURN_OK;
} // main

这基于文本文件中的数据在单行上以空格分隔。如果文件中有多行,或者分隔符是其他内容(如逗号或半冒号),则可以稍微修改。我没有编写代码来将这些值写入文件,也没有编写任何代码来对上述数据进行任何计算,因为我将留给您完成。然而,我确实将它们打印到控制台。我只是简单地告诉你如何轻松地将整数分成正负两组。另外,作为注释,从文件中的字符串中找到的任何0都将被丢弃,并且不予考虑。还有另一个声明,只有在考虑0时才会继续。您可以通过更改第一个if语句中的比较将这些添加到肯定的情况中,但是因为0不是正数也不是负数,所以我没有将它包含在任何一个中。您可以使用另一个vector<int>来存储所有0,以便在需要时跟踪它们。

<强> integers.txt

51 144 5 16 8 0 -2 14 6 -4 173 263 11 9345 -135 777 

节目输出

Enter the filename to read in data.
integers.txt

Positive Integers
51 144 5 16 8 14 6 173 263 11 9345 777

Negative Integers
-2 -4 -135

Press any key to quit