Convert a set to a vector of vector - c++

I'm new to C++ and I'm trying to convert unordered_set<string> to vector<vector<int>>
The set contains ("1,2,2","1","1,2","2","2,2"), and each element is a string.
I would like to output a vector<vector<int>> containing
[
[2],
[1],
[1,2,2],
[2,2],
[1,2],
[]
]
So how would I parse each element (string) and make it looks like the above scheme?
#define SSTR( x ) dynamic_cast< std::ostringstream & >( \
( std::ostringstream() << std::dec << x ) ).str()
vector<vector<int> > subsetsWithDup(const vector<int> &num) {
unordered_set<string> result;
for (int i = 0; i < num.size(); i++)
{
result.insert(SSTR(num[i]));
for (int j = i+1; j < num.size(); j++)
{
string d = SSTR(num[i]) + "," +SSTR(num[j]);
result.insert(d);
}
}
string lastString= "";
for (int i = 0; i < num.size(); i++)
{
if ( i == num.size() -1)
{
lastString+= SSTR(num[i]);
}
else
{
lastString+= SSTR(num[i])+",";
}
}
result.insert(lastString);
// convert result back to vector<vector<int>>
return result;
}

If you don't need to validate your strings you can do a transform to construct the vector<vector<int>>:
set<string> foo{ "1,2,2", "1", "1,2", "2", "2,2" };
vector<vector<int>> bar(foo.size());
transform(foo.begin(), foo.end(), bar.begin(), [](const string& i){
vector<int> result;
auto it = const_cast<char*>(i.c_str());
for (result.push_back(static_cast<int>(strtol(it, &it, 10)));
it < i.c_str() + i.size();
result.push_back(static_cast<int>(strtol(++it, &it, 10))));
return result;
});
The lambda in the transform will step through the string:
Start it at the beginning of the string
Using strtol to extract each number
Pushing each number into result
Stepping over each ',' with ++it
Return the constructed result
Prerequisites: This lambda assumes that your input set doesn't contain:
An empty string
A string that begins or ends with a comma (as in "1,2,")
A string that has consecutive commas (as in "1,,2")
That the string contains only contains digits and commas
Note: As a general rule a const_cast is bad so I wanted to comment on why I'm making one. Note that *it is never written to, only it is written to. So this is not violating the const-ness of const string& i. An alternative to strtol that doesn't require a const_cast is stoi, but until we get string_view from C++14 we'll need to construct a new string at each comma, so that's dreadfully inefficient.

One of the possible solution can be:
vector<string> split (string str, string seq) {
vector<string> ret {};
size_t pos {};
while ((pos = str.find (seq)) != string::npos) {
ret.push_back (str.substr (0, pos));
str = str.substr (pos+seq.size ());
}
ret.push_back (str);
return ret;
}
vector<int> to_vec_int (vector<string>&& vec) {
vector<int> ret {};
for (const auto& v : vec) {
ret.push_back (stoi (v));
}
return ret;
}
int main () {
unordered_set<string> st {"1,2,2","1","1,2","2","2,2"};
vector<vector<int>> vec {};
for (const auto& s : st) {
vec.push_back (to_vec_int (split (s, ",")));
}
for (const auto& v : vec) {
for (const auto& s : v) {
cout << s << " ";
}
cout << endl;
}
return 0;
}
Since your elements are delimited by comma, we can split them using split () function and we get vector of strings. This vector has to be converted to vector of int, which is the reason of existence of to_vec_int ().

Here is another possible solution using istringstream to find the commas:
#include <iostream>
#include <string>
#include <vector>
#include <unordered_set>
#include <sstream>
void main()
{
using namespace std;
unordered_set<string> strSet;
strSet.insert("1,2,2");
strSet.insert("1");
strSet.insert("1,2");
strSet.insert("2");
strSet.insert("2,2");
vector<int> nums;
vector<vector<int>> arr_of_nums;
for (const auto &str : strSet) {
istringstream strStream(str);
string strToInt;
while (getline(strStream, strToInt, ',')) {
nums.push_back(stoi(strToInt));
}
arr_of_nums.push_back(nums);
nums.clear();
}
for(const auto &nums : arr_of_nums) {
for (const auto &num : nums) {
cout << num << ",";
}
cout << endl;
}
}

Related

Converting a Vector of Characters to a Vector of Strings in C++

for the following problem, I need to return a vector of strings, where each element in the vector is of length 1. I have an answer that generates a vector of characters. I think it does what I need, but I'm not sure how to return the result as a vector of strings of length one. See my implementation below. Note, I can't change the return type of the function, it must be a vector of strings. Given that I operate on characters in my solution, I'm not sure how I'd change it.
vector<string> commonChars(vector<string>& A) {
vector<char> resVec;
unordered_map<char, int> mapObj;
for (const auto& str : A) {
for (const auto& letter : str) {
mapObj[letter]++;
}
}
int sizeOfInput = A.size();
for (int i{}; i < A[0].size(); i++) {
if (!mapObj.count(A[0][i])) continue;
resVec.insert(resVec.begin(), mapObj[(A[i])] / sizeOfInput, A[i]);
}
return resVec;
}
std::vector<char> resVec;
...
std::vector<std::string> returnVec;
returnVec.reserve(resVec.size());
for (char ch : resVec) {
returnVec.push_back(std::string(1, ch));
// or: returnVec.emplace_back(1, ch);
}
return returnVec;
Alternatively:
std::vector<char> resVec;
...
std::vector<std::string> returnVec;
returnVec.reserve(resVec.size());
std::transform(resVec.begin(), resVec.end(), std::back_inserter(returnVec),
[](char ch){ return std::string(1, ch); }
);
return returnVec;
Alternatively:
std::vector<char> resVec;
...
std::vector<std::string> returnVec(resVec.size());
std::transform(resVec.begin(), resVec.end(), returnVec.begin(),
[](char ch){ return std::string(1, ch); }
);
return returnVec;
That said, you could just eliminate the std::vector<char> altogether and just populate the final std::vector<std::string> directly from the std::map data:
std::vector<std::string> commonChars(std::vector<std::string>& A) {
std::vector<std::string> resVec;
std::unordered_map<char, int> mapObj;
for (const auto& str : A) {
for (const auto& letter : str) {
mapObj[letter]++;
}
}
size_t sizeOfInput = A.size();
if (sizeOfInput > 0) {
for (const auto& letter : A[0]) {
auto iter = mapObj.find(letter);
if (iter != mapObj.end()) {
resVec.insert(resVec.begin(), iter->second / sizeOfInput, std::string(1, letter));
}
}
}
return resVec;
}
vector<string> ret;
for(char ch: resVec)
ret.push_back(string(1,ch));
return ret;
This is a simple way of converting a std::vector<char> to a std::vector<std::string>.
If you are interested, you can also take a look at: Convert a single character to a string?
In short string(1,ch) is what does the actual conversion.
There's a different way to approach the problem. You could count the occurrences of each letter a-z in a vector for each string and loop through each vector, adding the minimum number of times a character occurs in all strings:
vector<string> commonChars(vector<string>& A) {
const int maxTimes=100;
vector<string> resVec;
vector<vector<int>> counts;
counts.reserve(A.size());
//Count occurrences of letters in each string
for (const auto& word : A) {
vector<int> count(26, 0);
for (const auto letter : word) {
count[letter-'a']++;
}
counts.push_back(count);
}
//Add minimum number of times a letter occurs in all strings
for (int i=0; i<26; ++i)
{
int min=maxTimes;
for (auto &count : counts)
{
if (count[i] < min) {
min = count[i];
}
}
for (int j=0; j<min; ++j) {
resVec.push_back(string(1, i+'a'));
}
}
return resVec;
}
Note: string(1, i+'a') creates a string of size 1 from a single char (value: i+'a').

Split vector to multiple array/vector C++

I have problem to split a string vector to smaller integer vector\array. My input vector data looks like:
std::vector<std::string> v(2);
v[0] = "0 14 150";
v[1] = "1 2 220";
//...
I know one solution, to make three arrays and to use sstream to convert data to integer. But i want to avoid making "spaghetti" code.
Thank you,
Peter.
I found a split function at stackoverflow some time ago. Unfortunatly, I cannot post the link anymore.
void split(const std::string & str, std::vector<std::string>& cont, const std::string & delims)
{
std::size_t current, previous = 0;
current = str.find_first_of(delims);
while (current != std::string::npos)
{
cont.push_back(std::move(str.substr(previous, current - previous)));
previous = current + 1;
current = str.find_first_of(delims, previous);
}
cont.push_back(std::move(str.substr(previous, current - previous)));
}
I will need delimiter in your strings (seems to be backspace in your case) and call the function on each element of your string vector:
int main()
{
std::vector<std::string> vec{ "0 14 150","1 2 220" };
std::vector<std::vector<int>> intVec(3,std::vector<int>(vec.size()));
for (int i = 0; i < vec.size(); i++)
{
std::vector<std::string> singleStr;
split(vec[i], singleStr, " ");
for (int j=0; j < singleStr.size();j++)
intVec[j][i] = (std::stoi(singleStr[j]));
}
system("pause");
}
A more generic solution could look like this. You can add further types to BasicVariant
#include <string>
#include <vector>
class BasicVariant
{
private:
std::string str;
public:
BasicVariant(const std::string& _str) :str(_str) {}
BasicVariant(int value) :str(std::to_string(value)) {}
BasicVariant(double value) :str(std::to_string(value)) {}
inline int toInt()const { return *this; }
inline double toDouble()const { return *this; }
inline std::string toString()const { return *this; }
inline bool toBool()const { return toDouble(); }
inline operator int()const { return std::stoi(str); }
inline operator double()const { return std::stof(str); }
inline operator std::string()const { return str; }
inline operator bool()const { return toDouble(); }
};
template<typename T>
void split(const std::string& str, std::vector<T>& sink, const std::string& delims)
{
std::size_t current, previous = 0;
current = str.find_first_of(delims);
while (current != std::string::npos)
{
sink.push_back(std::move(BasicVariant(str.substr(previous, current - previous))));
previous = current + 1;
current = str.find_first_of(delims, previous);
}
sink.push_back(std::move(BasicVariant(str.substr(previous, current - previous))));
}
int main()
{
std::vector<std::string> vec{ "0 14 150","1 2 220" };
std::vector<std::vector<int>> intVec(3, std::vector<int>(vec.size()));
for (int i = 0; i < vec.size(); i++)
{
std::vector<int> row;
split(vec[i], row, " ");
for (int j = 0; j < row.size(); j++)
intVec[j][i] = row[j];
}
system("pause");
}
Edit: I removed a verbose transposing function.
I assume that you want to convert std::vector<std::string> to a 2D matrix std::vector<std::vector<int>>.
For instance, for your example, the desired result is assumed to be arr1 = {0,1,...}, arr2 = {14,2,...} and arr3 = {150,220,...}.
First,
We can use std::istream_iterator to extract integers from strings.
We can also apply the range constructor to create a std::vector<int> corresponding to each string.
So the following function would work for you and it does not seem to be a spaghetti code at least to me.
First, this function extract two integer arrays {0,14,150,...} and {1,2,220,...} as matrices from a passed string vector v.
Since a default constructed std::istream_iterator is an end-of-stream iterator, each range constructor reads each string until it fails to read the next value.
And finally, transposed one is returned:
#include <vector>
#include <string>
#include <sstream>
#include <iterator>
template <typename T>
auto extractNumbers(const std::vector<std::string>& v)
{
std::vector<std::vector<T>> extracted;
extracted.reserve(v.size());
for(auto& s : v)
{
std::stringstream ss(s);
std::istream_iterator<T> begin(ss), end; //defaulted end-of-stream iterator.
extracted.emplace_back(begin, end);
}
// this also validates following access to extracted[0].
if(extracted.empty()){
return extracted;
}
decltype(extracted) transposed(extracted[0].size());
for(std::size_t i=0; i<transposed.size(); ++i){
for(std::size_t j=0; j<extracted.size(); ++j){
transposed.at(i).push_back(std::move(extracted.at(j).at(i)));
}
}
return transposed;
}
Then you can extract integers from a string vector as follows:
DEMO
std::vector<std::string> v(n);
v[0] = "0 14 150";
v[1] = "1 2 220";
...
v[n-1] = "...";
auto matrix = extractNumbers<int>(v);
where matrix[0] is arr1, matrix[1] is arr2, and so on.
We can also quickly get internal pointers of them by auto arr1 = std::move(matrix[0]);.
We have here some misunderstands.
Output of my program should have three arrays/vectors.
The output looks like:
arr1| arr1| arr3
0 | 14 | 150
1 | 2 | 220
2 | 4 | 130

Efficient Combinations of String Vectors

I need to run an efficient function to generate string combinations. I used multiple answers in SO to write something that works. The vectors are combined, the resultant strings then sorted by character and then duplicates are removed by inserting the resultant vector into an unordered set. The function needs to run 1e7 times on long vectors (100K) and I need help running more efficient code. Here's what I have now:
vector<string> vec_combos(vector<string> v1, vector<string> v2) {
vector<string> res;
unordered_set<string> s;
for(int i=0;i<v1.size();i++) {
for(int j=0;j<v2.size();j++){
res.push_back(v1[i]+v2[j]);
sort(res.back().begin(),res.back().end());
}
}
for( int i = 0; i < res.size(); ++i ) s.insert( res[i] );
res.assign( s.begin(), s.end() );
return res;
}
int main() {
vector<string> v1 = {"ab","bc","ca"}, v2 = {"a","b"},v3;
// combined vector = {"aba","bca","caa","abb","bcb","cab"}
// sort string chars = {"aab","abc","aac","abb","bbc","abc"}
// remove duplicates = {"aab","abc","aac","abb","bbc"}
v3 = vec_combos(v1, v2);
for(int i=0;i<v3.size();i++) {
cout << v3[i] << ",";
}
return(0);
}
Passing by reference, and avoid temporary unneeded container.
You may use something like:
std::vector<std::string> vec_combos2(const std::vector<std::string>& v1,
const std::vector<std::string>& v2)
{
std::unordered_set<std::string> words; // Or std::set<std::string>
for (const auto& s1 : v1) {
for (const auto& s2 : v2) {
std::string s = s1 + s2;
std::sort(s.begin(), s.end());
words.insert(std::move(s));
}
}
return { words.begin(), words.end() };
}
Demo

Including delimiters in output tokens with std::sregex_token_iterator C++ (no Boost)

I'm attempting to tokenize a scripting language in C++ and am struggling currently with including further delimiters as tokens.
#ifndef TOKENIZER_H
#define TOKENIZER_H
#include <regex>
#include <vector>
#include <string>
#include <iostream>
#include <fstream>
#include <cctype>
using namespace std;
regex re("[\\s]+");
vector<string> deconstructDelimit(const string &input) {
string trimmed = input.substr(input.find_first_not_of(" \t\f\v\n\r"));
vector<string> decons;
sregex_token_iterator it(trimmed.begin(), trimmed.end(), re, -1);
sregex_token_iterator reg_end;
for (; it != reg_end; ++it) {
decons.push_back(it->str());
}
return decons;
}
vector<string> tokenize(const string &input) {
vector<string> whitespace;
string currToken;
for (auto it = input.begin(); it != input.end(); ++it) {
if (*it == '\'') {
if (currToken.length()) {
vector<string> decons = deconstructDelimit(currToken);
whitespace.insert(whitespace.end(), decons.begin(), decons.end());
currToken.clear();
}
whitespace.push_back("\'");
++it;
while (*it != '\'' && it != input.end()) {
currToken += *it;
++it;
}
if (currToken.length()) whitespace.push_back(currToken);
whitespace.push_back("\'");
currToken.clear();
} else if (*it == '\"') {
if (currToken.length()) {
vector<string> decons = deconstructDelimit(currToken);
whitespace.insert(whitespace.end(), decons.begin(), decons.end());
currToken.clear();
}
whitespace.push_back("\"");
++it;
while (*it != '\"' && it != input.end()) {
currToken += *it;
++it;
}
if (currToken.length()) whitespace.push_back(currToken);
whitespace.push_back("\"");
currToken.clear();
} else {
currToken += *it;
}
}
if (currToken.length()) {
vector<string> decons = deconstructDelimit(currToken);
whitespace.insert(whitespace.end(), decons.begin(), decons.end());
}
return whitespace;
}
#endif
So far, it is able to convert this code:
i = 1
while(i <= 10) {
print i + " " then i++
}
into these tokens:
i
=
1
while(i
<=
10)
{
print
i
+
"
"
then
i++
}
However, I want to then split this string vector of tokens by other delimiters, such as operators (++, =, <=, +, etc.), keywords (while, then, etc.), and other grammar like parentheses and brackets, preferably without using boost. What would be the best way for me to achieve this, given the string vector output of my current progress?
Edit:
For example, the result of further tokenization would be:
i
=
1
while(i -> while, (, i
<=
10) -> 10, )
{
print
i
+
"
"
then
i++ -> i, ++
}
Which, expanded, would be:
i
=
1
while
(
i
<=
10
)
{
print
i
+
"
"
then
i
++
}
I had the exact same problem as you when I tried to separate items of a math expression using a regex. I successfully found a well working way to do it :
std::vector<std::string> resplit(const std::string& s, std::string rg_str = "\\s+"){
std::cmatch cm;
std::string reg_str = std::string("(.*?)(")+rg_str+std::string(")");
std::string str = s+std::string(" ");
unsigned a = 0;
unsigned b = 1;
std::string subs = str.substr(a, b-a);
std::vector<std::string> elements;
while(b <= str.length()){
subs = str.substr(a, b-a);
if(std::regex_match(subs.c_str(), cm, std::regex(reg_str), std::regex_constants::match_default)){
for(unsigned i=1; i<cm.size(); i++){
std::string cmi(cm[i]);
// The following part can be adapted if you want to include whitespaces or empty strings
if(!std::regex_match(cmi.c_str(), std::regex("\\s*"))){
elements.push_back(std::string(cm[i]));
}
}
a = b;
b = b+1;
} else {
b++;
}
}
return elements;
}
When I use it on resplit("sin(x^2) + 1", "[^0-9a-zPI.]|[ \\(\\)]");, I get : ["sin", "(", "x", "^", "2", ")", "+", "1"].
Don't forget to change :
if(!std::regex_match(cmi.c_str(), std::regex("\\s*"))){
elements.push_back(std::string(cm[i]));
}
into :
if(!std::regex_match(cmi.c_str(), std::regex(""))){
elements.push_back(std::string(cm[i]));
}
if you want to include spaces (it will remove empty strings though, but this is preferable).
I hope it's useful to someone. Have a nice day.
I had the same problem and here is my complete solution which consists of few helper functions:
#include <regex>
#include <string>
#include <iostream>
#include <algorithm>
void ltrim(std::string& str) {
str.erase(str.begin(), std::find_if(str.begin(), str.end(), [](int character) {
return !std::isspace(character);
}));
}
void rtrim(std::string& str) {
str.erase(std::find_if(str.rbegin(), str.rend(), [](int character) {
return !std::isspace(character);
}).base(), str.end());
}
void trim(std::string& str) {
ltrim(str);
rtrim(str);
}
bool is_empty(std::string const& str) {
return str.empty() || str.find_first_not_of(' ') == std::string::npos;
}
std::vector<std::string> split(std::string const& str, std::string const& pattern) {
std::regex regex(pattern);
std::vector<std::string> result(
std::sregex_token_iterator(str.begin(), str.end(), regex, {-1, 0}),
std::sregex_token_iterator()
);
for (auto& token : result) {
trim(token);
}
result.erase(
std::remove_if(
result.begin(),
result.end(),
[](std::string const& str) { return is_empty(str); }
),
result.end()
);
return result;
}
int main() {
for (auto &s: split("sin(x^2) + 1", "[^0-9a-zPI.]|[ \\(\\)]")) {
std::cout << s << '\n';
}
return 0;
}
The key thing I used is std::sregex_token_iterator. As the last argument to its constructor I passed {-1, 0} where -1 represents the parts that are not matched and 0 represents the entire match.
The result of the above code snippet is:
sin
(
x
^
2
)
+
1

How to insert a character every N characters in a string in C++

How can I insert a character into a string exactly after 1 character?
I need to insert '|' into
the string after every other character.
In other words (C++): "Tokens all around!"
Turns into: "T|o|k|e|n|s| |a|l|l| |a|r|o|u|n|d|!" (no thats not an array)
Thanks
std::string tokenize(const std::string& s) {
if (!s.size()) {
return "";
}
std::stringstream ss;
ss << s[0];
for (int i = 1; i < s.size(); i++) {
ss << '|' << s[i];
}
return ss.str();
}
I think I'd use a standard algorithm and iterator:
std::string add_seps(std::string const &input, std::string sep="|") {
std::ostringstream os;
std::copy(input.begin(), input.end(), std::ostream_iterator<char>(os, sep));
return os.str();
}
As it stands, this adds a separator after the last character of the input. If you only want them between characters, you'd use an infix_ostream_iterator.
Here is my C++11 example (with gcc 4.7):
#include <string>
#include <iostream>
template<const unsigned num, const char separator>
void separate(std::string & input)
{
for ( auto it = input.begin(); (num+1) <= std::distance(it, input.end()); ++it )
{
std::advance(it,num);
it = input.insert(it,separator);
}
}
int main(void)
{
std::string input{"aaffbb3322ff77c"};
separate<3,' '>(input);
std::cout << input << std::endl;
separate<4,'+'>(input);
std::cout << input << std::endl;
return 0;
}
The result output is:
aaf fbb 332 2ff 77c
aaf +fbb +332 +2ff +77c
You can use
string& insert (size_t pos, const string& str);
You would have to loop through the string, inserting a character each time.
for (int i = 1; i < str.size(); i++) {
str << str.insert(i, '|');
i++;
}
Here's a slightly different approach that will only do 1 allocation for the resultant string so it should be slightly more efficient than some other suggestions.
std::string AddSeparators(const std::string & s)
{
if(s.size() <= 1)
return s;
std::string r;
r.reserve((s.size()*2)-1);
r.push_back(s[0]);
for(size_t i = 1; i < s.size(); ++i)
{
r.push_back('|');
r.push_back(s[i]);
}
return r;
}