Can I do something like this?
std::vector<std::vector<std::string>> vec;
vec.push_back(std::vector<std::string>("abc", "cde", "fgh", "ijk"));
vec.push_back(std::vector<std::string>("abc", "cde", "fgh", "ijk"));
vec.push_back(std::vector<std::string>("abc", "cde", "fgh", "ijk"));
I already know which values I want and I'm trying to create a 3 x 4 vector like this.
Edit: I would also prefer a C++03 solution since my compiler doesn't support C++11.
You need to use :
vec.push_back(std::vector<std::string>( { "abc", "cde", "fgh", "ijk" } ) ) ;
~~ ~~
I already know which values
Then why not this ? (C++11)
std::vector<std::vector<std::string>> vec
{
{ "abc", "cde", "fgh", "ijk" },
{ "abc", "cde", "fgh", "ijk" },
{ "abc", "cde", "fgh", "ijk" },
} ;
For repeating vectors of strings, you can use another constructor overload taking a count and the repeated element:
#include <iostream>
#include <string>
#include <vector>
int main ()
{
std::vector<std::vector<std::string>> vec
(
3, { "abc", "cde", "fgh", "ijk" }
);
for (v : vec) {
for (s : v)
std::cout << s << ",";
std::cout << "\n";
}
}
Live Example
You can have vector of vectors, but you initialize them wrongly. There is no constructor that accepts 4 parameters of type T. You can however make them an initialization list since c++11.
#include <iostream>
#include <vector>
#include <string>
using namespace std;
int main() {
std::vector<std::vector<std::string>> vec;
vec.push_back(std::vector<std::string>({"abc", "cde", "fgh", "ijk"}));
vec.push_back(std::vector<std::string>({"abc", "cde", "fgh", "ijk"}));
vec.push_back(std::vector<std::string>({"abc", "cde", "fgh", "ijk"}));
return 0;
}
Another one (even for prior to C++11):
int main() {
std::vector<std::vector<std::string> > vec;
std::string aa[] = {"abc", "cde", "fgh", "ijk"};
std::vector<std::string> vec1(aa, aa+sizeof(aa)/sizeof(std::string));
vec.push_back(vec1);
vec.push_back(vec1);
vec.push_back(vec1);
return 0;
}
Related
std::map<int, std::vector<int>> tmp_map = { { 1, [10,5,4] }, { 2, [5,5,1] },
{ 3, [2,4,3] }, { 4, [9,7,8] } };
I want to order this map by the 3rd value in vector value.
So the outcome will be like :
{ { 2, [5,5,1] },{ 3, [2,4,3] },{ 1, [10,5,4] },{ 4, [9,7,8] } }
Standard approach . . .
Copy map to vector
Sort vector with custom comparator
#include <iostream>
#include <map>
#include <vector>
#include <utility>
#include <algorithm>
int main() {
std::map<int, std::vector<int>> tmp_map = { { 1,{10,5,4} }, { 2,{5,5,1} },
{ 3,{2,4,3} }, { 4,{9,7,8} } };
// For easier and shorter writing
using DataType = std::pair<int, std::vector<int>>;
// Create Vector with Elements from Map
std::vector<DataType> data(tmp_map.begin(), tmp_map.end());
// Sort data
std::sort(data.begin(), data.end(), [](const DataType& d1, const DataType& d2) { return d1.second[2] < d2.second[2]; });
// show result
for (const auto& [key, value] : data) {
std::cout << key << " --> ";
for (const int i : value) std::cout << i << " ";
std::cout << "\n";
}
return 0;
}
You're map is already sorted by its key value so you cannot reorder it inplace. What you should do instead is copy it into a vector and then sort it using a custom operator like this:
#include <map>
#include <vector>
#include <algorithm>
int main()
{
std::map<int, std::vector<int>> tmp_map = { { 1, {10,5,4} }, { 2, {5,5,1} },
{ 3, {2,4,3} }, { 4, {9,7,8} } };
//! Copy the map
using P = std::pair<int, std::vector<int>>;
std::vector<P> copy(tmp_map.begin(), tmp_map.end());
//! Sort it the way you want (here I'm sorting on based on the second element
//! of the array.
std::sort(copy.begin(), copy.end(), [](const P& a, const P& b)
{
return a.second[2] < b.second[2];
});
}
I have a double dimension std::string array which I need to pass as argument of function sortString but I get a runtime error when variable student is first read. "0" is output via cout, but not "1". Any idea of where I am wrong?
Here is my code:
#include <iostream>
#include <string>
void sortString(std::string **student, std::string **output, int size)
{
std::string names[5];
std::cout << "0" << std::endl;
for (int i = 0 ; i < size ; i++)
names[i] = student[i][0];
std::cout << "1" << std::endl;
}
int main()
{
std::string student1 [ ] = {"Joe Lime", "15", "2019"};
std::string student2 [ ] = {"Bob Green", "3", "2020"};
std::string student3 [ ] = {"SallyAnne Green" , "1", "2017"};
std::string student4 [ ] = {"Annie Blue", "10", "2020"};
std::string student5 [ ] = {"Jose Lemon", "25", "2016"};
int const size = 5;
std::string student [5][3] = {student1, student2, student3, student4, student5};
std::string sortedByName[5][3];
sortString((std::string**)student, (std::string**)sortedByName, size);
return 0;
}
** ------------ EDIT ------------ **
I wanted to do the same thing as I do for unidimensional arrays, so I don't understand why it doesn't work for 2-dimensional arrays
e.g, this works :
#include <iostream>
int test(int *a)
{
std::cout << a[0] << std::endl;
}
int main()
{
int a[] = {1,2,3,4,5,6,7};
test(a);
}
int test(int *a)
{
std::cout << a[0] << std::endl;
}
You have a big confusion with arrays, pointers and strings. As #Quentin and
#molbdnilo pointed you out, you are doing a C-style conversion from a bidimensional array of std::strings to a pointer to a pointer to a string, and neither arrays are pointers nor pointers are arrays.
My guess is that you want to sort all the students according to their name, while keeping the rest of the student information associated to the corresponding student.
A couple of advices:
Do not use C-style arrays whenever you can use std::array.
To define the constants in your code, create a constant variable, do not write, for example, 5 as size, this can involve multiple changes in different parts of your code when you want to change that constant value, since it can be written in multiple locations.
You don't need to use pointers in your example. They don't make sense in this scenario.
An example of what you are trying to achieve that uses the std::sort function:
#include <string>
#include <array>
#include <iostream>
#include <algorithm>
const unsigned NUMBER_OF_STUDENTS = 5;
const unsigned NUMBER_OF_STUDENT_DATA_FIELDS = 3;
using studentType = std::array<std::string, NUMBER_OF_STUDENT_DATA_FIELDS>;
int main()
{
std::array<std::string, NUMBER_OF_STUDENT_DATA_FIELDS> student1 = {"Joe Lime", "15", "2019"};
std::array<std::string, NUMBER_OF_STUDENT_DATA_FIELDS> student2 = {"Bob Green", "3", "2020"};
std::array<std::string, NUMBER_OF_STUDENT_DATA_FIELDS> student3 = {"SallyAnne Green" , "1", "2017"};
std::array<std::string, NUMBER_OF_STUDENT_DATA_FIELDS> student4 = {"Annie Blue", "10", "2020"};
std::array<std::string, NUMBER_OF_STUDENT_DATA_FIELDS> student5 = {"Jose Lemon", "25", "2016"};
std::array<studentType, NUMBER_OF_STUDENTS> students = {student1, student2, student3, student4, student5};
std::sort(students.begin(), students.end(), [](const studentType& student1, const studentType& student2) {
// first string in the array is the name
const std::string& nameStudent1 = student1.front();
const std::string& nameStudent2 = student2.front();
// we return if the name of student 1 is lexicographically smaller than the name of student 2
return nameStudent1 < nameStudent2;
});
// Let's print the students to see we have order everything correctly
for (const auto& student: students) // for each student
{
for (const auto& studentData : student) // for each field in the student string
{
std::cout << studentData << " ";
}
std::cout << "\n"; // jump to the next line
}
}
Annie Blue 10 2020
Bob Green 3 2020
Joe Lime 15 2019
Jose Lemon 25 2016
SallyAnne Green 1 2017
i fixed your code a bit and got it to work:
#include <iostream>
#include <string>
void sortString(std::string student[][3], std::string output[][3], int size)
{
std::string names[5];
std::cout << "0" << std::endl;
for (int i = 0; i < size; i++)
{
names[i] = student[i][0];
std::cout << names[i] << "\n";
}
std::cout << "1" << std::endl;
}
int main()
{
int const size = 5;
std::string students[5][3] =
{
{ "Joe Lime", "15", "2019" },
{ "Bob Green", "3", "2020" },
{ "SallyAnne Green", "1", "2017" },
{ "Annie Blue", "10", "2020" },
{ "Jose Lemon", "25", "2016" }
};
std::string sortedByName[5][3];
sortString(students, sortedByName, size);
return 0;
}
but i highly recommend you use arrays, vectors and structs/classes. following a made up an example with vector and arrays and vector and structs
#include <iostream>
#include <string>
#include <vector>
#include <array>
#include <algorithm>
void sortString(std::vector<std::array<std::string, 3>>& students)
{
// for example: print all names with range base for loop
for (const auto& s : students)
{
std::cout << s[0] << std::endl;
}
// for example: print all names with "normal" for loop
for (std::size_t i = 0; i < students.size(); ++i)
{
std::cout << students[i][0] << std::endl;
}
// sort by name
std::sort(std::begin(students), std::end(students), [](const std::array<std::string, 3>& a, const std::array<std::string, 3>& b){ return a[0] < b[0]; });
}
int main()
{
int const size = 5;
std::vector<std::array<std::string, 3>> students;
students.push_back({ "Joe Lime", "15", "2019" });
students.push_back({ "Bob Green", "3", "2020" });
students.push_back({ "SallyAnne Green", "1", "2017" });
students.push_back({ "SallyAnne Green", "1", "2017" });
students.push_back({ "Jose Lemon", "25", "2016" });
sortString(students);
return 0;
}
with struct:
#include <iostream>
#include <string>
#include <vector>
#include <algorithm>
struct Student
{
std::string name;
std::string dontKnow;
std::string year;
};
void sortString(std::vector<Student>& students)
{
// for example: print all names with range base for loop
for (const auto& s : students)
{
std::cout << s.name << std::endl;
}
// for example: print all names with "normal" for loop
for (std::size_t i = 0; i < students.size(); ++i)
{
std::cout << students[i].name << std::endl;
}
// sort by name
std::sort(std::begin(students), std::end(students), [](const Student& a, const Student& b){ return a.name < b.name; });
}
int main()
{
int const size = 5;
std::vector<Student> students;
students.push_back({ "Joe Lime", "15", "2019" });
students.push_back({ "Bob Green", "3", "2020" });
students.push_back({ "SallyAnne Green", "1", "2017" });
students.push_back({ "SallyAnne Green", "1", "2017" });
students.push_back({ "Jose Lemon", "25", "2016" });
sortString(students);
return 0;
}
i hope you see how much cleaner your code gets
Forgive me if this is an easy problem to fix, I am new to C++.
I have a class and a main method:
class Test
{
public:
static std::list<std::string> list1[];
};
std::list<std::string> Test::list1[] = { "apple", "orange", "pear" };
int main()
{
std::list<std::string> list2[] = { "banana", "mango", "pineapple" };
Test::list1.merge(list2);
std::cout << list1 << endl;
return 0;
}
I want to add list1 and list2 together so that they output "apple", "orange", "pear", "banana", "mango", "pineapple". However, when I try the method above I get an error like:
no suitable constructor exists to convert from "const char [24]" to "std::list>"
Thanks for any help.
#include <iostream>
#include <list>
#include <string>
class Test
{
public:
static std::list<std::string> list1;
};
std::list<std::string> Test::list1 = { "apple", "orange", "pear" };
int main()
{
std::list<std::string> list2 = { "banana", "mango", "pineapple" };
Test::list1.merge(list2);
for(const auto& itr : Test::list1)
std::cout << itr << std::endl;
return 0;
}
List don't use operator []. If you want display list, you must use itr, something like above.
I need to convert an std::unordered_multimap<Key,T> to an std::vector<std::vector<T>>. I need to do this because my program will need to sort all the data, and maps can't be sorted. An example:
// Map:
{ "A", 1 },
{ "A", 3 },
{ "A", 2 },
{ "B", 5 },
{ "B", 2 },
// Map converted to vector<vector<Value>>:
{ 1, 3, 2 },
{ 5, 2 }
Right now I have this code which works. But I'm wondering if it's the best way to do it.
#include <unordered_map>
#include <iostream>
#include <string>
#include <vector>
int main()
{
typedef std::string Key_t;
typedef int Value_t;
typedef std::unordered_multimap<Key_t, Value_t> Map_t;
const Map_t map = {
{ "A", 1 },
{ "A", 3 },
{ "A", 2 },
{ "B", 5 },
{ "B", 2 },
};
std::vector< std::vector< Value_t > > output;
for ( Map_t::const_iterator it = map.cbegin(); it != map.cend(); )
{
std::vector< Value_t > temp;
const Map_t::const_iterator end = map.upper_bound( it->first );
for ( ; it != end; ++it )
temp.push_back( it->second );
output.push_back( temp );
}
// Print the result
for ( const std::vector< Value_t >& values : output )
{
for ( const Value_t& value : values )
std::cout << value << " ";
std::cout << std::endl;
}
}
Output:
1 3 2
5 2
So, now I'm wondering if there's a faster/better way.
here's my attempt.
proof is here: http://goo.gl/JVpHw9
#include <unordered_map>
#include <iostream>
#include <string>
#include <vector>
#include <algorithm>
int main()
{
typedef std::string Key_t;
typedef int Value_t;
typedef std::unordered_multimap<Key_t, Value_t> Map_t;
const Map_t map = {
{ "A", 1 },
{ "A", 3 },
{ "A", 2 },
{ "B", 5 },
{ "B", 2 },
};
std::vector< std::vector< Value_t > > output;
for (auto it = map.begin(); it != map.end(); )
{
auto er = map.equal_range(it->first);
auto tmp = std::vector< Value_t >{};
for( ; it != er.second ; ++it) {
tmp.push_back(it->second);
};
output.push_back(std::move(tmp));
}
// Print the result
for ( const std::vector< Value_t >& values : output )
{
for ( const Value_t& value : values )
std::cout << value << " ";
std::cout << std::endl;
}
}
The usual multimap iteration should work here:
std::vector<std::vector<T>> out;
for (auto it1 = m.begin(), it2 = it1, end = m.end(); it1 != end; it1 = it2)
{
out.emplace_back();
for ( ; it1->first == it2->first; ++it2)
{
out.back().push_back(it2->second);
}
}
Following works for me:
#include <vector>
#include <iostream>
#include <algorithm>
#include <unordered_map>
int main () {
std::unordered_multimap<std::string, int> map;
map = {
{ "A", 1 },
{ "A", 3 },
{ "A", 2 },
{ "B", 5 },
{ "B", 2 },
};
std::vector<int> values;
std::transform(map.begin(), map.end(),
std::back_inserter(values),
[](std::pair<std::string, int> element) {
return element.second;
});
for (auto const& value : values) {
std::cout << value << std::endl;
}
return 0;
}
Consider the following vector
vector<vector<string>> a_words(80000,vector<string>(3));
which is a three dimension vector;
Now consider the following elements:
Joan Williams 30
Mike Williams 40
Joan Smith 30
William Anderson 20
Sara Jon 33
Basically I want to search by row, and I want to find Joan Williams, keep in mind that Joan is an element in the first column and Williams is an element is the second column
Should I use the "find" function? if yes how would it be written, else which function should I use?
Here are two demonstrative programs one for C++ 2003 and other for C++ 2011 that do the search
C++ 2003
#include <iostream>
#include <string>
#include <vector>
#include <algorithm>
#include <utility>
#include <functional>
struct FindName : std::unary_function<bool,
const std::pair<std::string, std::string>>
{
FindName( const std::pair<std::string, std::string> &p ) : p( p ){}
bool operator ()( const std::vector<std::string> &v ) const
{
return v.size() > 1 &&
v[0] == p.first && v[1] == p.second;
}
protected:
const std::pair<std::string, std::string> p;
};
int main()
{
const size_t N = 5;
std::vector<std::vector<std::string>> v;
v.reserve( N );
const char * initial[N][3] =
{
{ "Joan", "Williams", "30" },
{ "Mike", "Williams", "40" },
{ "Joan", "Smith", "30" },
{ "William", "Anderson", "20" },
{ "Sara", "Jon", "33" }
};
for ( size_t i = 0; i < N; i++ )
{
v.push_back( std::vector<std::string>( initial[i], initial[i] + 3 ) );
}
std::pair<std::string, std::string> p( "Joan", "Williams" );
typedef std::vector<std::vector<std::string>>::iterator iterator;
iterator it = std::find_if( v.begin(), v.end(), FindName( p ) );
if ( it != v.end() )
{
for ( std::vector<std::string>::size_type i = 0; i < it->size(); ++i )
{
std::cout << ( *it )[i] << ' ';
}
}
std::cout << std::endl;
}
C++ 2011
#include <iostream>
#include <string>
#include <vector>
#include <algorithm>
#include <utility>
int main()
{
std::vector<std::vector<std::string>> v =
{
{ "Joan", "Williams", "30" },
{ "Mike", "Williams", "40" },
{ "Joan", "Smith", "30" },
{ "William", "Anderson", "20" },
{ "Sara", "Jon", "33" }
};
std::pair<std::string, std::string> p( "Joan", "Williams" );
auto it = std::find_if( v.begin(), v.end(),
[&]( const std::vector<std::string> &row )
{
return row.size() > 1 &&
row[0] == p.first && row[1] == p.second;
} );
if ( it != v.end() )
{
for ( const auto &s : *it ) std::cout << s << ' ';
}
std::cout << std::endl;
}
The both programs' putput is
Joan Williams 30
I strongly advise you to use a data structure with an overloaded equality operator instead of vector<string> (especially since it seems like the third element should be saved in an integer, not a string).
Anyway, this is one possibility:
auto iter = std::find_if( std::begin(a_words), std::end(a_words),
[] (std::vector<std::string> const& vec)
{ return vec[0] == "Joan" && vec[1] == "Williams";};
If the list is lexicographically sorted by the first or second column, a binary search can be used instead.
As of C++11, a range based for loop would be a simple and readable solution:
for(auto r: a_words)
if(r[0] == "Joan" && r[1] == "Williams")
cout << r[0] << " " << r[1] << " " << r[2] << endl;
Essentially the answer of #Columbo is nice, eliminating C++ 11 features (besides initialization):
#include <algorithm>
#include <iostream>
#include <string>
#include <vector>
int main() {
// Requires C++11
std::vector<std::vector<std::string>> words = {
{ "Joan", "Williams", "30" },
{ "Mike", "Williams", "40" },
{ "Joan", "Smith", "30" },
{ "William", "Anderson", "20" },
{ "Sara", "Jon", "33" },
};
// Below does not require C++11
struct EqualName
{
const char* first;
const char* second;
EqualName(const char* first, const char* second)
: first(first), second(second)
{}
bool operator () (const std::vector<std::string>& element) {
return element[0] == first && element[1] == second;
}
};
std::vector<std::vector<std::string>>::const_iterator
pos = std::find_if(words.begin(), words.end(), EqualName("Joan", "Smith"));
if(pos != words.end())
std::cout << (*pos)[0] << ' ' << (*pos)[1] << ' ' << (*pos)[2] << '\n';
}