I want to create a view that will have views of both halves of the string. I added some code examples of what I would like to achieve. How could I do it?
#include <iostream>
#include <string>
#include <ranges>
#include <vector>
#include <cassert>
int main() {
std::vector<std::string> data{
"abcdef",
"12345678910",
"ab",
"qwerty",
"xyzxyz",
"987654321"
};
// Ok:
auto chunk3 = std::views::chunk(data, 3);
assert(std::ranges::size(chunk3) == 2);
for (auto chunk : chunk3) {
assert(std::ranges::size(chunk) == 3);
}
// Problem:
auto view = /*...*/
assert(std::ranges::size(view) == 6);
for (auto halves : view) {
assert(std::ranges::size(halves) == 2);
}
}
What does chunk3 look like:
/*
chunk3 {
{"abcdef", "12345678910", "ab"}
{"qwerty", "xyzxyz", "987654321"}
}
*/
What the view would look like:
/*
view {
{{"abc"}, {"def"}}
{{"123456"}, {"78910"}}
// ...
}
*/
You can use views::transform to convert the original element string into an array containing two half-string_views
auto view = data | std::views::transform([](std::string_view s) {
return std::array{s.substr(0, s.size() / 2),
s.substr(s.size() / 2)};
});
Related
I have a function in cpp that i want to use to sort an array of strings according to the individual length of each string, i tried to compare the length of an element at a particular index with the length of the element residing in the next index. If the length of the next index is lower than the length of the string in the first index then i push the shorter length string to the index of the string with higher length. The code i tried is shown below, i have a problem using it in my main, there is an error generated by the compiler that states
:[Error] could not convert '{"Mario", "Bowser", "Link"}' from '<brace-enclosed initializer list>' to 'std::vector<std::basic_string<char> >'.
#include <iostream>
#include <ctype.h>
#include <vector>
//below is my sort according to length function
using namespace std;
std::vector<std::string> sortByLength(std::vector<std::string> arr) {
for(int k=0;k<arr.size();k++){
if(arr[k+1].size()<arr[k].size()){
//push the shorter string to the lower index
arr[k]=arr[k+1];
}
}
return arr;
}
//below is the main function
int main(){
//this line below generates compile error
std::vector<string> myarr=sortByLength({"Mario", "Bowser", "Link"})<<endl;
cout<<myarr<<endl;
return 0;
}
Here you go.
#include <iostream>
#include <vector>
#include <algorithm>
#include <string>
void printVec(std::vector<std::string>& vec) {
for(auto&& v:vec) {
std::cout<<v<<std::endl;
}
}
int main() {
std::vector<std::string> vec {"abc","ab","a","abcd"};
printVec(vec);
std::sort(vec.begin(), vec.end(), [](std::string& a, std::string& b) {
return a.length() > b.length();
});
printVec(vec);
return 0;
}
Note: Works on for c++11 or greater.
As an alternative to sorting, you can move your strings into a sorted container:
#include <iostream>
#include <set>
#include <string>
#include <vector>
struct StringLengthComparer
{
bool operator ()(std::string left, std::string right) const
{
return left.length() < right.length();
}
};
using StringMultiset = std::multiset<std::string, StringLengthComparer>;
using std::cout;
StringMultiset sortByLength(std::vector<std::string> arr)
{
return StringMultiset{arr.begin(), arr.end()};
}
int main()
{
auto myset = sortByLength({"Mario", "Bowser", "Link"});
for(auto item : myset)
{
cout << item<< '\n';
}
return 0;
}
We have as input a vector, as an example
std::vector<std::int32_t> allnumbers{1,2,-3,4,5,-6,7,8,9};
We have a boolean condition, as an example output numbers have to be larger 3.
What we want is as output the longest subvector fullfilling the condition. All elements of the output have to have been connected in the input.
std::vector<std::int32_t> allnumbers{4,5,7,8,9};
Is wrong, as 5 and 7 have not been adjacent before (-6 between them).
std::vector<std::int32_t> allnumbers{4,5};
Is wrong, as it is not the longest subvector.
std::vector<std::int32_t> allnumbers{7,8,9};
Is finally correct.
How to write the algorithm elegantly with C++17 standard, possibly without using the Boost library? By elegantly I mean few lines of code with good readability. Utilizing prefarably as much as possible. Performance or memory consumption is here less of an issue. I think the "brute force" solution I post below already has here enough performance. One time iterate through input and only few iterators to keep track during exectuion.
The following is a working "brute force" solution:
#include <functional>
#include <iostream>
#include <stdint.h>
#include <vector>
std::vector<std::int32_t> longestConnectedVectorFullfillingPredicate(
std::function<bool(const std::int32_t)> predicate,
std::vector<std::int32_t> &inputVector)
{
auto currentIt = inputVector.begin();
auto endIt = inputVector.end();
auto beginLongestConnectedSubvector = endIt;
auto endLongestConnectedSubvector = endIt;
auto longestConnectedSubvectorLength = 0;
while (currentIt != endIt)
{
const auto currentBeginConnectedSubvector = std::find_if(
currentIt, endIt, [predicate](const std::int32_t &value) { return predicate(value); });
const auto currentEndConnectedSubvector = std::find_if(
currentBeginConnectedSubvector, endIt, [predicate](const std::int32_t &value) {
return !predicate(value);
});
const auto currentConnectedSubvectorLength =
std::distance(currentBeginConnectedSubvector, currentEndConnectedSubvector);
if (currentConnectedSubvectorLength > longestConnectedSubvectorLength)
{
longestConnectedSubvectorLength = currentConnectedSubvectorLength;
beginLongestConnectedSubvector = currentBeginConnectedSubvector;
endLongestConnectedSubvector = currentEndConnectedSubvector;
}
currentIt = currentEndConnectedSubvector;
}
return std::vector<std::int32_t>(beginLongestConnectedSubvector, endLongestConnectedSubvector);
}
int main()
{
const auto largerThree = [](std::int32_t value) { return value > 3; };
std::vector<std::int32_t> allnumbers{1, 2, -3, 4, 5, -6, 7, 8, 9};
auto result = longestConnectedVectorFullfillingPredicate(largerThree, allnumbers);
for (auto res : result)
{
std::cout << res << std::endl;
}
return 0;
}
This is quite a few lines... Would like to shorten it without loosing much readability.
You might like this, which does the following
include needed headers, define useful namespace aliases, and a couple of useful function objects
pipes allnumbers into group_by which puts all adjacent numbers greater than 3 in a range/chunk (all other numbers remain in singleton range each)
pipes that into filter which says goodby to the singletons with the number not greater than 3
then finds the longest range by using max_element to which an appropriate lambda is passed
#include <boost/hana/functional/on.hpp>
#include <boost/hana/functional/partial.hpp>
#include <boost/hana/functional/reverse_partial.hpp>
#include <boost/range/numeric.hpp>
#include <functional>
#include <iostream>
#include <range/v3/algorithm/max_element.hpp>
#include <range/v3/range/conversion.hpp>
#include <range/v3/view/filter.hpp>
#include <range/v3/view/group_by.hpp>
#include <range/v3/view/transform.hpp>
#include <vector>
using boost::hana::on;
using boost::hana::reverse_partial;
using namespace ranges::views;
using namespace ranges;
auto both = [](bool x, bool y){ return x && y; };
auto greater_than_3 = reverse_partial(std::greater<>{}, 3);
int main() {
std::vector<int> allnumbers{1,2,-3,4,5,-6,7,8,9};
auto chunks
= allnumbers
| group_by(both ^on^ greater_than_3)
| filter([](auto v){ return greater_than_3(v.front()); })
| transform(to_vector)
| to_vector;
auto result = *max_element(
chunks,
std::less<>{} ^on^ std::mem_fn(&decltype(allnumbers)::size));
for (auto i : result) {
std::cout << i << ',';
}
}
I have 2 string tables and I would like to display the differences between the two tables.
Example :
Tab1 = "user1, user2, user3, user4"
Tab2 = "user3, user4, user2"
The difference in this case is that user 1 is missing.
I would like to know if there is a function that allows you to do this in the standard library or in Qt.
Thank you in advance.
What you need is std::set_difference which copies the elements from the sorted v1 which are not found in the sorted v2 to the diff. As mentioned, you should first sort your vectors and then search for difference.
#include <iostream>
#include <algorithm>
#include <vector>
#include <iterator>
int main() {
std::vector<std::string> v1 { "user1", "user2", "user3", "user4" };
std::vector<std::string> v2 { "user3", "user4", "user2" };
std::vector<std::string> diff;
std::sort(v1.begin(), v1.end());
std::sort(v2.begin(), v2.end());
std::set_difference(v1.begin(), v1.end(), v2.begin(), v2.end(),
std::inserter(diff, diff.begin()));
for (auto const& i : diff)
std::cout << i << std::endl;
}
If your string tables are stored as a string as you depicted, i.e,
Tab1 = "user1, user2, user3, user4"
Tab2 = "user3, user4, user2"
then you can use regular expression to first find out the users in Tab1 and store them in a set.
While searching for users in the Tab2, you can check if that user is already present in the set, if yes then remove that user from the set, if no then insert that user in the set.
Code:
#include <iostream>
#include <string>
#include <regex>
#include <set>
using namespace std;
ostream& operator<< (ostream& out, const set<string>& S)
{
for (const string& s : S)
out << s << endl;
return out;
}
int main()
{
string Tab1 = "user1, user2, user3, user4";
string Tab2 = "user3, user4, user2";
regex reg("user[0-9]{1,}");
set<string> S;
sregex_iterator pos1(Tab1.cbegin(), Tab1.cend(), reg);
sregex_iterator end1;
while (pos1 != end1)
{
S.insert(pos1->str());
++pos1;
}
sregex_iterator pos2(Tab2.cbegin(), Tab2.cend(), reg);
sregex_iterator end2;
while (pos2 != end2)
{
string temp = pos2->str();
if (S.find(temp) != S.cend())
S.erase(temp);
else
S.insert(temp);
++pos2;
}
cout << S << endl;
}
You can reduce computational complexity if you present you tables with std::set (or std::unordered_set). Then no need to sort tables (it's not cheap operation). I modify
NutCracker answer with usage of std::unordered_set:
#include <iostream>
#include <unordered_set>
#include <vector>
int main()
{
std::unordered_set<std::string> set1{ "user1", "user2", "user3", "user4" };
std::unordered_set<std::string> set2{ "user3", "user4", "user2", "user8" };
std::vector<std::string> diff;
for (const auto& s : set1)
{
auto it = set2.find(s);
if (it == set2.cend())
{
diff.emplace_back(s);
}
}
for (const auto& s : set2)
{
auto it = set1.find(s);
if (it == set1.cend())
{
diff.emplace_back(s);
}
}
for (const auto& s : diff)
std::cout << s.c_str() << std::endl;
}
Finding an element in a vector of structures
this link showed me, how to look for a value inside a structure.
but i have something like this,
struct sample {
string name;
vector<string> values;
};
vector<sample>v1;
and this is a vector of structures. how to search for a particular string in the values vector, that is present inside the structure samples ? which itself, is a vector of structures ?
thanks.
You can iterate through the vector v1 containing sample structures accessing each vector v1 member as a struct. Then, you can access the struct member vector to search for desired string:
for (const sample &it : v1) {
for (const string &st : it.values) {
if (st == ...) {
}
}
}
You can use a combination of std::find_if and std::find.
The std::find_if goes through the sample objects and checks every element with a predicate which itself uses std::find to go through all std::string elements inside and compares each of them to the token you want to find.
Here is an example, using a lambda function to create the predicate:
#include <vector>
#include <iostream>
#include <string>
#include <algorithm>
struct sample
{
std::string name;
std::vector<std::string> values;
};
int main()
{
std::vector<sample> const v1 =
{
{ "one", { "a", "b" } },
{ "two", { "c", "token to find", "d", "e" } },
{ "three", { "f"} }
};
using std::begin;
using std::end;
auto const token = "token to find";
// go through all samples
auto const sample_iter = std::find_if(begin(v1), end(v1), [&token](sample const& s)
{
// in each sample, go through all values
auto const string_iter = std::find(begin(s.values), end(s.values), token);
return string_iter != end(s.values);
});
if (sample_iter == end(v1))
{
std::cout << "not found\n";
}
else
{
std::cout << sample_iter->name << '\n';
}
}
Output:
two
Let
typedef pair<int, double> Element;
I then have two vectors:
vector<Element> A, B;
These vectors are sorted by the integer in Element.first. I want to get a third vector, C, which is the union of A and B. This sounds like set_union, but I need different behavior when A[i].first == B[j].first. set_union will simply choose one of the source elements to include in C, but I need the result to "combine" the two elements instead. In other words, something like this:
C[k].first = A[i].first; // == B[j].first. set_union does this
C[k].second = A[i].second + B[j].second; // set_union does NOT do this.
I'm interested if this is possible using the standard library (or something like Boost). The code to do this manually is not particularly complicated, but I'd like to not re-invent the wheel.
The only other related operation I can find is merge. It doesn't merge elements either, and would involve another combining pass.
I think the use of std::merge with boost::function_output_iterator is pretty clean.
#include <algorithm>
#include <iostream>
#include <vector>
#include <boost/function_output_iterator.hpp>
/* Convenience type alias for our element. */
using Elem = std::pair<int, double>;
/* Convenience type alias for the container of our elements. */
using Elems = std::vector<Elem>;
/* Our appender that will be created with boost::function_output_iterator. */
class Appender {
public:
/* Cache the reference to our container. */
Appender(Elems &elems) : elems_(elems) {}
/* Conditionally modify or append elements. */
void operator()(const Elem &elem) const {
if (!elems_.empty() && elems_.back().first == elem.first) {
elems_.back().second += elem.second;
return;
} // if
elems_.push_back(elem);
}
private:
/* Reference to our container. */
Elems &elems_;
}; // Appender
int main() {
// Sample data.
Elems lhs {{1, 2.3}, {2, 3}, {5, 3.4}};
Elems rhs {{1, 1.3}, {3, 5.5}, {4, 2.2}};
Elems result;
// Merge and use appender to append elements.
std::merge(std::begin(lhs),
std::end(lhs),
std::begin(rhs),
std::end(rhs),
boost::make_function_output_iterator(Appender(result)));
// Print result.
for (const auto &elem : result) {
std::cout << elem.first << ' ' << elem.second << std::endl;
} // for
}
Prints:
1 3.6
2 3
3 5.5
4 2.2
5 3.4
Note. The use of function_output_iterator was suggested by Benjamin Lindley.
Here's an implementation with a standalone generic algorithm merge_elements:
#include <algorithm>
#include <utility>
template <typename LInput, typename RInput, typename Output>
Output merge_elements(LInput lbegin, LInput lend,
RInput rbegin, RInput rend,
Output out) {
while(true) {
if (lbegin == lend) {
return std::copy(rbegin, rend, out);
}
if (rbegin == rend) {
return std::copy(lbegin, lend, out);
}
if (lbegin->first < rbegin->first) {
*out++ = *lbegin++;
} else if (rbegin->first < lbegin->first) {
*out++ = *rbegin++;
} else {
*out++ = std::make_pair(lbegin->first, lbegin->second + rbegin->second);
++lbegin;
++rbegin;
}
}
}
#include <iostream>
#include <iterator>
#include <vector>
/* Convenience type alias for our element. */
using Elem = std::pair<int, double>;
/* Convenience type alias for the container of our elements. */
using Elems = std::vector<Elem>;
int main() {
// Sample data.
Elems lhs {{1, 2.3}, {2, 3}, {5, 3.4}};
Elems rhs {{1, 1.3}, {3, 5.5}, {4, 2.2}};
Elems result;
// Merge and use appender to append elements.
merge_elements(std::begin(lhs),
std::end(lhs),
std::begin(rhs),
std::end(rhs),
std::back_inserter(result));
// Print result.
for (const auto &elem : result) {
std::cout << elem.first << ' ' << elem.second << std::endl;
} // for
}
It doesn't require boost, but has almost exactly the same total line count as mpark's boost solution. Interestingly, this algorithm is generic enough to work unchanged with a std::map<int,double> as well as std::vector<std::pair<int,double>>:
#include <iostream>
#include <iterator>
#include <map>
/* Convenience type alias for the container of our elements. */
using Elems = std::map<int, double>;
int main() {
// Sample data.
Elems lhs {{1, 2.3}, {2, 3}, {5, 3.4}};
Elems rhs {{1, 1.3}, {3, 5.5}, {4, 2.2}};
Elems result;
// Merge and use appender to append elements.
merge_elements(std::begin(lhs),
std::end(lhs),
std::begin(rhs),
std::end(rhs),
std::inserter(result, result.begin()));
// Print result.
for (const auto &elem : result) {
std::cout << elem.first << ' ' << elem.second << std::endl;
} // for
}