[英]C++ 2D Struct Array data
I want to be able to store values from a file into a user defined struct. 我希望能够将文件中的值存储到用户定义的结构中。 I want to have columns that hold different types of data such as: a std::string for Character names, a float for Character health and an int for Character experience. 我想拥有保存不同类型数据的列,例如:std :: string代表角色名称,float代表角色状态,int代表角色体验。
My desired output is to have a 6 by 3 array as shown below 我想要的输出是具有6 x 3的数组,如下所示
Alice 23.4 3210
Xander 45.3 1110
Bernard 12.9 2024
Yanni 23.7 1098
Craw 50.5 980
Zack 11.9 1024
Here is what I have tried so far: 到目前为止,这是我尝试过的:
struct charData
{
string charName;
float charHealth;
int charExp;
};
int main() {
const int NUM_COLS = 3;
int NUM_ROWS = 6;
int charNumber = 0;
int userInput;
int loop = 0;
int i,j;
string line;
ifstream myIn; // Declare read file stream
myIn.open("party.dat"); // Open file
struct charData charArray[NUM_ROWS][NUM_COLS];
while( !myIn.eof() ) {
for ( j = 0; j < NUM_COLS ; j++) {
for ( i = 0; i < NUM_ROWS ; i++) {
myIn >> charArray[i][j].charName;
myIn >> charArray[i][j].charHealth;
myIn >> charArray[i][j].charExp;
}
}
}
return 0;
}
I am also planning on to allow the user to sort the data by each column type. 我还计划允许用户按每种列类型对数据进行排序。 To sort names alphabetically, sort by health and or experience: I am thinking of using a 2D array. 要按字母顺序对名称进行排序,按健康状况或经验进行排序:我正在考虑使用2D数组。 Would this be the best option? 这是最好的选择吗?
I think you are confusing the number of fields in your structure with the number of columns of data. 我认为您将结构中的字段数与数据的列数混淆了。 You show data for only 6 records of 3 fields each. 您仅显示3条字段的6条记录的数据。 Try setting NUM_COLS to 1 and see if it works any better for you. 尝试将NUM_COLS设置为1,看看是否对您更好。
Or, get rid of the second dimension (j) of your array entirely. 或者,完全摆脱数组的第二维(j)。
I don't know if you are reading your file as binary or as a text; 我不知道您是以二进制文件还是文本文件形式读取文件; but within my answer I'm reading from a text file where each field on a line of text is separated by a space character. 但是在我的回答中,我正在从一个文本文件中读取,其中一行文本中的每个字段都由一个空格字符分隔。 I will include all files necessary to compile and build a proper working program of what you are looking for. 我将包括所有必要的文件,这些文件可用来编译和构建您所寻找的正确的工作程序。 Some of these includes may not be needed but are within my solution for I have larger project that depends on these to properly build. 其中一些可能不需要使用,但在我的解决方案中,因为我有一个较大的项目,需要依靠这些项目才能正确构建。
stdafx.h stdafx.h
#ifndef STDAFX_H
#define STDAFX_H
#include <Windows.h>
#include <stdio.h>
#include <tchar.h>
#include <conio.h>
#include <string>
#include <sstream>
#include <fstream>
#include <iostream>
#include <iomanip>
#include <vector>
#include <array>
#include <memory>
#include <queue>
#include <functional>
#include <algorithm>
// User Application Specific
// #include "ExceptionHandler.h" // Required For My Solution But Isn't Used In Yours
namespace util {
enum ReturnCode {
RETURN_OK = 0,
RETURN_ERROR = 1,
}; // ReturnCode
extern const unsigned INVALID_UNSIGNED;
extern const unsigned INVALID_UNSIGNED_SHORT;
} // namespace util
#endif // STDAFX_H
stdafx.cpp stdafx.cpp
#include "stdafx.h" #include“ stdafx.h”
namespace util {
const unsigned INVALID_UNSIGNED = static_cast<const unsigned>( -1 );
const unsigned INVALID_UNSIGNED_SHORT = static_cast<const unsigned short>( -1 );
} // namespace util
Utility.h 实用程序
#ifndef UTILITY_H
#define UTILITY_H
namespace util {
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 unsigned convertToUnsigned(const std::string& str);
static int convertToInt(const std::string& str);
static float convertToFloat(const std::string& str);
static std::vector<std::string> splitString(const std::string& strStringToSplit, const std::string& strDelimiter, const bool keepEmpty = true);
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"
} // namespace util
#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 Utility.cpp
#include "stdafx.h"
#include "Utility.h"
namespace util {
// ----------------------------------------------------------------------------
// 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
} // namspace util
CharacterData.h 字符数据
#ifndef CHARACTER_DATA_H
#define CHARACTER_DATA_H
class CharacterData {
private:
std::string m_name;
float m_health;
unsigned m_exp;
public:
CharacterData();
CharacterData( const std::string& name, float health, unsigned exp );
void setName( const std::string& name );
void setHealth( float health );
void setExperience( unsigned exp );
std::string getName() const;
float getHealth() const;
unsigned getExperience() const;
private:
CharacterData( const CharacterData& c ); // Not Implemented
CharacterData& operator=( const CharacterData& c ); // Not Implemented
}; // CharacterData
#endif // CHARACTER_DATA_H
CharacterData.cpp CharacterData.cpp
#include "stdafx.h"
#include "CharacterData.h"
// ----------------------------------------------------------------------------
// CharacterData()
CharacterData::CharacterData() :
m_name( std::string() ),
m_health( 0.0f ),
m_exp( 0 ) {
} // CharacterData
// ----------------------------------------------------------------------------
// CharacterData()
CharacterData::CharacterData( const std::string& name, float health, unsigned exp ) :
m_name( name ),
m_health( health ),
m_exp( exp ) {
} // CharacterData
// ----------------------------------------------------------------------------
// setName()
void CharacterData::setName( const std::string& name ) {
m_name = name;
} // setName
// ----------------------------------------------------------------------------
// getName()
std::string CharacterData::getName() const {
return m_name;
} // getName
// ----------------------------------------------------------------------------
// setHealth()
void CharacterData::setHealth( float health ) {
m_health = health;
} // setHealth
// ----------------------------------------------------------------------------
// getHealth()
float CharacterData::getHealth() const {
return m_health;
} // getHealth
// ----------------------------------------------------------------------------
// setExperience()
void CharacterData::setExperience( unsigned exp ) {
m_exp = exp;
} // setExperience
// ----------------------------------------------------------------------------
// getExperience()
unsigned CharacterData::getExperience() const {
return m_exp;
} // getExperience
CharacterDatabase.h CharacterDatabase.h
#ifndef CHARACTER_DATABASE_H
#define CHARACTER_DATABASE_H
class CharacterData;
class CharacterDatabase {
private:
std::string m_filename;
std::vector<std::shared_ptr<CharacterData>> m_vpCharacters;
public:
explicit CharacterDatabase( const std::string& filename );
// ~CharacterDatabase(); // Default Okay
void displayByOption( unsigned option = 0 );
private:
CharacterDatabase( const CharacterDatabase& c ); // Not Implemented
CharacterDatabase& operator=( const CharacterDatabase& c ); // Not Implemented
void parseFile();
void display() const;
static bool sortByName( const std::shared_ptr<CharacterData>& d1, const std::shared_ptr<CharacterData>& d2);
static bool sortByHealth( const std::shared_ptr<CharacterData>& d1, const std::shared_ptr<CharacterData>& d2);
static bool sortByExperience(const std::shared_ptr<CharacterData>& d1, const std::shared_ptr<CharacterData>& d2);
}; // CharacterDataase
#endif // CHARACTER_DATABASE_H
CharacterDatabase.cpp CharacterDatabase.cpp
#include "stdafx.h"
#include "CharacterDatabase.h"
#include "CharacterData.h"
#include "Utility.h"
// ----------------------------------------------------------------------------
// CharacterDatabase()
CharacterDatabase::CharacterDatabase( const std::string& filename ) :
m_filename( filename ) {
parseFile();
} // CharacterDatabase
// ----------------------------------------------------------------------------
// parseFile()
void CharacterDatabase::parseFile() {
using namespace util;
if ( m_filename.empty() ) {
std::cout << "Missing or invalid filename." << std::endl;
return;
}
std::string line;
std::vector<std::string> results;
std::ifstream in;
// Try To Open File For Reading
in.open( m_filename.c_str(), std::ios_base::in );
if ( !in.is_open() ) {
std::cout << "Can not open file(" << m_filename << ") for reading.";
return;
}
// Read Line By Line And Store Contents Into String & Parse Each Line One At A Time.
while ( !in.eof() ) {
std::getline( in, line );
results = Utility::splitString( line, " " );
// On Each Pass We Want To Construct A CharacterData Object & Save It Into Our Container
m_vpCharacters.push_back( std::make_shared<CharacterData>( results[0], Utility::convertToFloat( results[1] ), Utility::convertToUnsigned( results[2] ) ) );
}
// Close File Pointer
in.close();
} // parseFile
// ----------------------------------------------------------------------------
// display()
void CharacterDatabase::display() const {
for (unsigned u = 0; u < m_vpCharacters.size(); u++) {
std::cout << m_vpCharacters[u]->getName() << "\t"
<< m_vpCharacters[u]->getHealth() << "\t"
<< m_vpCharacters[u]->getExperience() << std::endl;
}
std::cout << std::endl;
} // display
// ----------------------------------------------------------------------------
// displayByOption() Default 0 = Order In Which File Is Read In,
// 1 = Sorted By Name, 2 = Sorted By Health, 3 = Sorted By Experience
void CharacterDatabase::displayByOption( unsigned option ) {
switch ( option ) {
case 1: { // Sorted By Name
std::sort( m_vpCharacters.begin(), m_vpCharacters.end(), sortByName );
display();
break;
}
case 2: { // Sorted By Health
std::sort( m_vpCharacters.begin(), m_vpCharacters.end(), sortByHealth );
display();
break;
}
case 3: { // Sorted By Experience
std::sort( m_vpCharacters.begin(), m_vpCharacters.end(), sortByExperience );
display();
break;
}
default: { // Unsorted - Order Read In By File
display();
}
}
} // displayByOption
// ----------------------------------------------------------------------------
// sortByName()
bool CharacterDatabase::sortByName( const std::shared_ptr<CharacterData>& d1, const std::shared_ptr<CharacterData>& d2 ) {
return d1->getName() < d2->getName();
} // sortByName
// ----------------------------------------------------------------------------
// sortByHealth()
bool CharacterDatabase::sortByHealth( const std::shared_ptr<CharacterData>& d1, const std::shared_ptr<CharacterData>& d2 ) {
return d1->getHealth() < d2->getHealth();
} // sortByHealth
// ----------------------------------------------------------------------------
// sortByExperience()
bool CharacterDatabase::sortByExperience( const std::shared_ptr<CharacterData>& d1, const std::shared_ptr<CharacterData>& d2) {
return d1->getExperience() < d2->getExperience();
} // sortByExperience
characterData.txt characterData.txt
Alice 23.4 3210
Xander 45.3 1110
Bernard 12.9 2024
Yanni 23.7 1098
Craw 50.5 980
Zack 11.9 1024
main.cpp main.cpp
#include "stdafx.h"
#include "Utility.h"
#include "CharacterDatabase.h"
int main() {
using namespace util;
CharacterDatabase cd( "characterData.txt" );
cd.displayByOption();
cd.displayByOption( 1 );
cd.displayByOption( 2 );
cd.displayByOption( 3 );
Utility::pressAnyKeyToQuit();
return RETURN_OK;
} // main
Just make sure that you are calling the file from the correct path, also when using the Utility::splitString() method make sure the second parameter or the delimiter matches what you have in your stored file. 只要确保您从正确的路径调用文件,就在使用Utility :: splitString()方法时,请确保第二个参数或分隔符与您存储的文件中的内容匹配。 The splitString() method will divide the string from each line of the file every time it sees that character. 每次看到该字符时,splitString()方法都会将字符串从文件的每一行中分开。 If you happen to have multiple names such as a first & last name that you want stored to a single string then a little more care needs to be taken. 如果您碰巧要将多个名称(例如名字和姓氏)存储到单个字符串中,则需要多加注意。
for sorting on the basis of any col you can use sort()
in algorithm
header with your own compare function. 要基于任何col进行排序,您可以在algorithm
标头中将sort()
与您自己的compare函数一起使用。
Define your compare function like this: 定义您的比较函数,如下所示:
on the basis of Health: 在健康的基础上:
bool MyCompHealth(struct charData a,struct charData b)
{
return (a.charHealth>b.charHealth);
}
on the basis of Exp: 根据Exp:
bool MyCompExp(struct charData a,struct charData b)
{
return (a.charExp > b.charExp);
}
on the basis of Name: 根据名称:
bool MyCompName(struct charData a,struct charData b)
{
int r = a.charName.compare(b.charName);
return (r > 0);
}
code: 码:
#include<algorithm>
#include<iostream>
#include<fstream>
using namespace std;
struct charData
{
string charName;
float charHealth;
int charExp;
};
bool MyCompHealth(struct charData a,struct charData b)
{
return (a.charHealth<b.charHealth);
}
//on the basis of Exp:
bool MyCompExp(struct charData a,struct charData b)
{
return (a.charExp < b.charExp);
}
//on the basis of Name:
bool MyCompName(struct charData a,struct charData b)
{
int r = a.charName.compare(b.charName);
return !(r > 0);
}
int main() {
const int NUM_COLS = 3;
int NUM_ROWS = 6;
int charNumber = 0;
int userInput;
int loop = 0;
int i,j;
string line;
ifstream myIn; // Declare read file stream
myIn.open("party.dat",ios::in); // Open file
struct charData charArray[NUM_ROWS];
while( !myIn.eof() ) //taking input
{
for ( i = 0; i < NUM_ROWS ; i++)
{
myIn >> charArray[i].charName;
myIn >> charArray[i].charHealth;
myIn >> charArray[i].charExp;
}
}
cout<<"How you want to sort?(1:health 2:Exp 3:Name)\n";
cin>>userInput; //input from user how he wants to sort
if(userInput==1)
{
//sorting on the basis of health
sort(charArray,charArray+NUM_ROWS,MyCompHealth);
}
else if(userInput==1)
{
//sorting on the basis of Experience
sort(charArray,charArray+NUM_ROWS,MyCompExp);
}
else
{
//sorting on the basis of Name
sort(charArray,charArray+NUM_ROWS,MyCompName);
}
//display result
for ( i = 0; i < NUM_ROWS ; i++)
{
cout<<charArray[i].charName<<" ";
cout<<charArray[i].charHealth<<" ";
cout<<charArray[i].charExp<<endl;
}
return 0;
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.