Reputation: 1359
I have a string array with numbers i want to sort (i only want to sort the [i][0]):
string test[4][2];
test[0][0] = "3";
test[0][1] = "4";
test[1][0] = "1";
test[1][1] = "2";
test[2][0] = "6";
test[2][1] = "8";
test[3][0] = "5";
test[3][1] = "4";
std::sort(std::begin(test), std::end(test), NumericGreaterThan);
bool NumericGreaterThan(const string u[], const string v[])
{
// more code ..
return true;
}
the result should be:
1 - 2
3 - 4
5 - 4
6 - 8
The compiler says:
[Error] invalid array assignment
Update
The above example was just a test case. In reality my 2th array dimension is wider than in the example. For example:
string test[4][2];
test[0][0] = "3";
test[0][1] = "Name";
test[0][2] = "Name";
test[0][3] = "5";
Based on @coincoin's solution i did something like this:
// create tmp array with index and sorting value
int testsCount = sizeof(test) / sizeof(test[0]);
vector< pair<string, string> > tmpTest;
for (int i = 0; i < testsCount; i++) {
pair<string, string> aPair;
aPair.first = std::to_string(i);
aPair.second = test[i][3];
tmpTest.push_back(aPair);
}
// sort
std::sort(std::begin(tmpTest), std::end(tmpTest), compare);
bool compare(const pair<string, string>&i, const pair<string, string>&j)
{
return std::stoi(i.second)>std::stoi(j.second);
}
Now i have a copied and sorted vector of test
which i can use to loop through the original test array.
for (int i = 0; i < testsCount; i++) {
cout << i+1 << ". " << test[std::stoi(tmpTest[i].first)][0] << endl;
}
I know this is not the best way to achieve this, but it fits my needs.
Upvotes: 0
Views: 109
Reputation: 4685
I think you are overcomplicated things unnecessarily (and also some answers...)
You should revise your code design.
You can simply use an array of pair for instance and you can reuse the built in bool operator< (const pair<T1,T2>& lhs, const pair<T1,T2>& rhs)
which will do what you want...
#include <array>
#include <algorithm>
int main() {
std::array<std::pair<int,int>, 4> test { std::make_pair(3,4), std::make_pair(1,2), std::make_pair(6,8), std::make_pair(5,4) };
std::sort(std::begin(test), std::end(test));
}
Output is
(1,2) (3,4) (5,4) (6,8)
That's all...
Upvotes: 2
Reputation: 2822
Prefer std::array<>
over C-arrays:
auto test = std::array<std::array<std::string, 2>, 4>{{"3"s, "4"s},
{"1"s, "2"s},
{"6"s, "8"s},
{"5"s, "4"s}};
std::sort(std::begin(test), std::end(test), NumericGreaterThan);
auto NumericGreaterThan(const std::array<std::string, 2>& u, const std::array<std::string, 2>& v)
-> bool
{
// more code ..
return true;
}
This is untested code!
In know, that many text books first teach you C-style before introducing C++ idioms. I think, those are doing it wrong.
Also consider to use Lambdas, if that is the only place, where you use NumericGreaterThan:
auto test = std::array<std::array<std::string, 2>, 4>{{"3"s, "4"s},
{"1"s, "2"s},
{"6"s, "8"s},
{"5"s, "4"s}};
std::sort(std::begin(test), std::end(test),
[](const std::array<std::string, 2>& u, const std::array<std::string, 2>& v)
-> bool {
// more code ..
return true;
});
If you already use C++14, you can have generic lambdas, which make this code even simpler a little bit:
auto test = std::array<std::array<std::string, 2>, 4>{{"3"s, "4"s},
{"1"s, "2"s},
{"6"s, "8"s},
{"5"s, "4"s}};
std::sort(std::begin(test), std::end(test),
[](const auto& u, const auto& v) -> bool {
// more code ..
return true;
});
Please also consider to convert your string arrays to numbers before sorting. That reduces the number of array<string>
-> int
conversions quite noticeably:
int convertToNumber(std::array<std::string, 2>);
auto test =
std::array<std::pair<std::array<std::string, 2>, int> 4>{{{"3"s, "4"s}, 0},
{{"1"s, "2"s}, 0},
{{"6"s, "8"s}, 0},
{{"5"s, "4"s}, 0}};
for(auto& i: test) i.second = convertToNumber(i.first);
std::sort(std::begin(test), std::end(test),
[](const auto& u, const auto& v) -> bool {
return u.second > v.second;
});
Upvotes: 0
Reputation: 1677
You could separate each part of the string into different classes and then just address the lowest child class in the sort function. This is a bit convoluted but answers your question.
Please Note: This method only allows for the lowest child class to be iterated through. I would not recommend this method for practical use as it is not extendable and becomes increasingly more convoluted as you increase the dimensional structure of you application. For every new dimension you will need a new class (This becomes increasingly tedious as your "array becomes increasingly n-dimensional").
#include <iostream>
#include <string>
#include <vector>
using namespace std;
class string_container_length {
public:
string_container_length(int &length)
{
level2.resize(length);
}
// Level to iterated [i][0] where i is important.
std::vector<std::string> level2;
};
class string_container {
public:
string_container(int &length, int &width)
{
level1.reserve(width);
for (int i = 0; i < width; ++i)
{
// Creates a new string_container_length using constructor with a set length.
level1.push_back(string_container_length(length));
}
}
std::vector<string_container_length> level1;
};
int main(){
// Will not be iterated in example.
int length = 2;
// Will be iterated in example
int width = 4;
string_container test(length,width);
test.level1[0].level2[0] = 7;
test.level1[0].level2[1] = 4;
test.level1[0].level2[2] = 3;
test.level1[0].level2[3] = 8;
// Passes beginning and end positions to the child class.
std::sort(std::begin(test.level1[0].level2), std::end(test.level1[0].level2));
}
Recomendation: Write your own custom sort function under another namespace specifically for your needs. This can be done using a simple loop, a couple if statements and your already existing NumericGreaterThan()
function. An example aswell as a tutorial on how sort functions work can be found here.
Upvotes: 0
Reputation: 838
In order to sort an array of arrays you have to assign an array to another array wich is not possible. You should probably use an array of pairs and compare pairs.
Upvotes: 0