I'm trying to write a function which recursively checks if a given vector A is in any contiguous block in vector B. For example, if A={5,6,7} and B={1,2,3,4,5,6,7}, it should return true. If B = {1,2,3,4,5,7,6}, it should return false. Currently, my code keeps outputting true because I don't think my logic is correct. I have not been able to modify it to produce any results yet. Any help will be appreciated!
bool r_app(vector<int>& a1, vector<int> b1, size_t k)
{
k=0;
if (a1.size() == 0) {
cout << "true";
return true;;
}
for (int i=0;i<a1.size();i++){
for(int j=0;j<b1.size();j++){
if (a1.at(i)==b1.at(j)) {
cout << "true" << endl;
return true;
}
}
cout << "false" << endl;
return false;
return r_app(a1,b1,k+1);
}
}
EDIT: So this is what I got from Smac89, and I added the cout lines so that when I call the function in main, it outputs either true or false. The function currently outputs true for every true input, but doesnt output false.. I'm not sure why.
bool r_app(std::vector<int>& a1, std::vector<int> &b1, std::size_t start)
{
std::size_t savedPos = start + 1, k = 0;
for (; k < a1.size() && start < b1.size() && a1[k] == b1[start];
k++, start++)
{
if (k != 0 && a1[0] == b1[start])
savedPos = start;
}
if (k == a1.size())
cout << "true" << endl;
return true;
if (start < b1.size())
return r_app(a1, b1, savedPos);
cout << "false" << endl;
return false;
}
template <typename T>
bool r_app(std::vector<T>& a1, std::vector<T> &b1, std::size_t start) {
std::size_t savedPos = start + 1, k = 0;
for (; k < a1.size() && start < b1.size() && a1[k] == b1[start];
k++, start++)
{
if (k != 0 && a1[0] == b1[start])
savedPos = start;
}
if (k == a1.size())
return true;
if (start < b1.size())
return r_app(a1, b1, savedPos);
return false;
}
template <typename T>
bool r_app(std::vector<T>& a1, std::vector<T>& b1) {
return r_app(a1, b1, 0);
}
Example:
http://rextester.com/COR69755
EDIT:
V2
Now more efficient searching - start a search either where the last search ended or at a character that matches the start of the search string
You can also print out where the first match occurred by looking at savedPos - 1
You need1 two recursive functions here if you want to do everything recursively.
One to test if the sequence is found at a particular point, and one to use this other function to test for equality at every point. Here is a simple template implementation that will work with any STL container that allows iteration, as well as non-STL sequences (such as raw arrays):
template <typename NeedleIterator, typename HaystackIterator = NeedleIterator>
bool recursive_sequence_equals(
NeedleIterator needle_begin,
NeedleIterator needle_end,
HaystackIterator haystack_begin,
HaystackIterator haystack_end)
{
// The sequences are equal because we reached the end of the needle.
if (needle_begin == needle_end) {
return true;
}
// If we reached the end of the haystack, or the current elements are not equal
// then the sequences are not equal here.
if (haystack_begin == haystack_end || *needle_begin != *haystack_begin) {
return false;
}
// We are not at the end of the haystack nor the needle, and the elements were
// equal. Move on to the next element.
return recursive_sequence_equals(
++needle_begin, needle_end,
++haystack_begin, haystack_end);
}
template <typename NeedleIterator, typename HaystackIterator = NeedleIterator>
HaystackIterator recursive_sequence_find(
NeedleIterator needle_begin,
NeedleIterator needle_end,
HaystackIterator haystack_begin,
HaystackIterator haystack_end)
{
// We reached the end with no match.
if (haystack_begin == haystack_end) {
return haystack_begin;
}
// If the sequences are equal at this point, return the haystack iterator.
if (recursive_sequence_equals(needle_begin, needle_end,
haystack_begin, haystack_end)) {
return haystack_begin;
}
// Check the next position in the haystack.
return recursive_sequence_find(
needle_begin, needle_end,
++haystack_begin, haystack_end);
}
Used like this:
std::vector<int> a = { 5, 6, 7 };
std::vector<int> b = { 1, 2, 3, 4, 5, 6, 7 };
auto found = recursive_sequence_find(
a.begin(), a.end(),
b.begin(), b.end());
if (found != b.end()) {
// There was a match, found is an iterator to the beginning of the match in b.
} else {
// No match. (Or both containers were empty!)
}
(Demo)
1 Technically you can do this with one function if you use some extra parameters to convey whether or not you are in the middle of an equality test. However this adds a lot of extra complication to the logic for no gain. It's easier and more straightforward to implement using two different recursive functions.
#include <stdio.h>
#include <string.h>
#include <vector>
#include <iostream>
using namespace std;
bool r_app(vector<int> a, vector<int> b, int starta, int startb)
{
if(a.size() == 0) return 0;
if(starta == 0) {
int i=0;
while(1) {
while(a[0] != b[i] && i < b.size())
i++;
if(i >= b.size()) return 0;
if(r_app(a, b, starta+1, i+1) == 1)
return 1;
else i++;
}
}
else {
if(starta == a.size())
return 1;
else if(startb == b.size())
return 0;
else if(a[starta] == b[startb])
return r_app(a, b, starta+1, startb+1);
else
return 0;
}
}
int main() {
vector<int> a;
vector<int> b;
b.push_back(1);
b.push_back(2);
b.push_back(3);
b.push_back(4);
b.push_back(5);
a.push_back(3);
a.push_back(4);
cout << r_app(a,b,0,0);
return 0;
}
It will be easier if you do not use recursion. Also, KMP algorithm will give you much optimized solution.
My try, using iterator:
#include <iostream>
#include <vector>
#include <algorithm>
template<typename Iter>
bool r_app(Iter first_a, Iter last_a, Iter first_b, Iter last_b)
{
if(first_a == last_a) //trivial case
return true;
auto found = std::find(first_b, last_b, *first_a);
if(found == last_b)
return false;
else
return r_app(++first_a, last_a, found, last_b); //recursion
}
int main()
{
std::vector<int> a{5,6,7};
std::vector<int> b{1,2,3,4,5,6,7};
std::cout << r_app(a.begin(),a.end(),b.begin(),b.end());
return 0;
}
Related
So I have a search that tells me if a value is in a list but its giving me this error and not sure why?
bool find(pNode* t, deque<unique_ptr<pNode>>& openList)
{
for (auto p = openList.begin(); p != openList.end(); p++)
{
if (t->x == (*p)->x && t->y == (*p)->y)
{
cout << "The coords searched for are in the open list" << endl;
return true;
}
else
{
return false;
}
}
}
Your example does not iterate, it only reports if the first node match's t. When openList is empty, the for loop is never entered. Notice that if the loop is not entered no return statement is encountered before the end of the function. You probably meant to place the return false statement outside of the loop, which solves all of these problems and gives you the expected behavior. Additionally openList should be const in this case.
bool find(pNode* t, const deque<unique_ptr<pNode>>& openList)
{
for (auto p = openList.begin(); p != openList.end(); p++)
{
if (t->x == (*p)->x && t->y == (*p)->y)
{
cout << "The coords searched for are in the open list" << endl;
return true;
}
}
return false;
}
Consider using std::find_if or a range-based for loop instead.
#include <algorithm>
bool find(pNode* t, deque<unique_ptr<pNode>>& openList)
{
auto iter = std::find_if(openList.begin(), openList.end(),
[t](const unique_ptr<pNode> & p_Ptr){
return p_Ptr->x == t->x && p_Ptr->y == t->y;
});
return iter != openList.end();
}
Or
bool find(pNode* t, const deque<unique_ptr<pNode>>& openList)
{
for (auto && ptr : openList) {
if (t->x == ptr->x && t->y == ptr->y) {
return true;
}
}
return false;
}
You're making the classic newbie mistake when searching a list, putting the "false" result in the else clause inside the loop. You can't tell that something hasn't been found until you finish the loop, not after a single test failure.
bool find(pNode* t, deque<unique_ptr<pNode>>& openList)
{
for (auto p = openList.begin(); p != openList.end(); p++)
{
if (t->x == (*p)->x && t->y == (*p)->y)
{
cout << "The coords searched for are in the open list" << endl;
return true;
}
}
return false;
}
I need to remove the elements that appear in Vector A and Vector B, but keep the elements that are only in Vector A. The vectors can be of any size, but are not necessarily equal to each other.
For example, if:
vector A contains the values <1,4,66,22>
vector B contains the values <1,22,44,93,102,543>
Then after preforming the operation:
vector A should contain <4,66>
vector B should contain <44,93,102,543>
Do I need to loop through both with a for loop and strncmp the values or is the a function that I can use to streamline the process?
This is what I tried but doesn't seem to work.
string rawInput;
string fileInput;
vector<string> stdInput; //vector to hold standard input values
vector<string> fileList; //vector to hold file values
sizeIn = stdInput.size();
sizeFile = fileList.size();
if (sizeIn >= sizeFile)
{
for (count = 0;count <= sizeIn; count++)
{
for (count1 = 0; count1 <= sizeFile; count1++)
{
if (stdInput[count1] == fileList[count])
{
stdInput.erase(stdInput.begin()+count1-1);
fileList.erase(fileList.begin()+count-1);
}
}
}
}
else
{
for (count = 0; count <= sizeFile; count ++)
{
for (count1 = 0; count1 <= sizeIn; count1++)
{
if (stdInput[count] == fileList[count1])
{
stdInput.erase(stdInput.begin()+count-1);
fileList.erase(fileList.begin()+count1-1);
}
}
}
}
That's a lot of work there. I would have suggested std::set_difference, but since you want to do it in place, this code will do it for you with good algorithmic complexity:
template<typename T>
void remove_intersection(std::vector<T>& a, std::vector<T>& b){
std::unordered_multiset<T> st;
st.insert(a.begin(), a.end());
st.insert(b.begin(), b.end());
auto predicate = [&st](const T& k){ return st.count(k) > 1; };
a.erase(std::remove_if(a.begin(), a.end(), predicate), a.end());
b.erase(std::remove_if(b.begin(), b.end(), predicate), b.end());
}
Isn't C++ beautiful? :-)
A Demo:
int main(){
std::vector<int> a = {1,4,66,22};
std::vector<int> b = {1,22,44,93,102,543};
remove_intersection(a, b);
for(auto k : a) std::cout << k << ' ';
std::cout << std::endl;
for(auto k : b) std::cout << k << ' ';
}
Outputs:
4 66
44 93 102 543
See it Live On Coliru
There are many variations of the above method. For example, if you are worried that count may take too long when such count is really large, you can implement a simple function to find and count up to at most 2 elements; another one: you can simply use two different unordered sets.
No, I will resort them via sort(fileList.begin(), fileList.end() ); after
So asymptotically it's the same to sort before.
Using set_difference, you can do something like:
template<typename T>
void remove_intersection(std::vector<T>* c1, std::vector<T>* c2) {
assert(c1 != nullptr);
assert(c2 != nullptr);
std::sort(std::begin(*c1), std::end(*c1)); // O(n1 logn1)
std::sort(std::begin(*c2), std::end(*c2)); // O(n2 logn2)
std::vector<T> difference1, difference2;
difference1.reserve(c1->size());
difference2.reserve(c2->size());
std::set_difference(std::begin(*c1), std::end(*c1),
std::begin(*c2), std::end(*c2),
std::back_inserter(difference1));
// O(2*[N1 + N2 - 1])
std::set_difference(std::begin(*c2), std::end(*c2),
std::begin(*c1), std::end(*c1),
std::back_inserter(difference2));
// O(2*[N1 + N2 - 1])
*c1 = std::move(difference1); // O(1)
*c2 = std::move(difference2); // O(1)
}
Thanks to #WhiZTiM for the great code example.
For my application it had some issues:
only applicable to vectors
removes duplicates from a although they are not in b
does not pay attention to const correctness
This suggested variation deals with those issues.
template <typename ContainerT>
void remove_intersection(ContainerT& a, ContainerT& b)
{
std::unordered_set<ContainerT::value_type> const uniqueAs { a.cbegin(), a.cend() };
std::unordered_multiset<ContainerT::value_type> st { uniqueAs.cbegin(), uniqueAs.cend() };
st.insert(b.begin(), b.end());
auto const predicate = [&st](ContainerT::value_type const& k) { return st.count(k) > 1; };
a.erase(std::remove_if(a.begin(), a.end(), predicate), a.cend());
b.erase(std::remove_if(b.begin(), b.end(), predicate), b.cend());
}
I might try something like the following.
// Create sets from vectors. This eliminates the duplicate elements.
const unordered_set<int> setA{vecA.cbegin(), vecA.cend()};
const unordered_set<int> setB{vecB.cbegin(), vecB.cend()};
PopulateSetDiff(vecA, setA, setB);
PopulateSetDiff(vecB, setB, setA);
// Populate 'vec' with 'set1 - set2'
template <typename T>
void PopulateSetDiff(
vector<T>& vec,
unordered_set<T> const& set1,
unordered_set<T> const& set2) {
vec.clear();
for (const auto elem : set1) {
if (set2.find(elem) == set2.cend()) {
vec.push_back(elem);
}
}
vec.shrink_to_fit();
}
for (auto& d : deleteCommands) {
auto it = stackCommands.begin();
while (it != stackCommands.end()) {
if (d == *it._Ptr) {
commands[d]->Exit(this);
it = stackCommands.erase(it);
}
else { it++; }
}
}
I am trying to use a user defined type as a map key with a custom comparator as follows.
#include <map>
#include <iostream>
class RangeKey {
public:
int start;
int end;
RangeKey(int start, int end) : start(start), end(end) {
}
bool withinRange(int value, bool inclusive) const {
if (inclusive) {
return (value >= start && value <= end);
} else {
return (value > start && value < end);
}
}
bool overlapsWith(const RangeKey& r) const {
if (r.withinRange(start, true) ||
r.withinRange(end, true) ||
(start < r.start && end > r.end)) {
return true;
}
return false;
}
};
class RangeKeyComparator {
public:
bool operator()(const RangeKey& a, const RangeKey& b) const {
if (a.overlapsWith(b)) {
return true;
} else {
return a.start < b.start;
}
}
};
int main() {
std::map<RangeKey, int, RangeKeyComparator> m;
m.insert(std::pair<RangeKey, int>(RangeKey(1, 2), 1));
auto it = m.find(RangeKey(1, 2));
std::cout << it->first.start << "\n";
std::cout << it->first.end << "\n";
std::cout << it->second << "\n";
return 0;
}
The idea is to consider two RangeKey instances as equal if their ranges overlap. However when I try to retrieve a value after the insertion it gives me some garbage values as the main function output. What am I doing wrong here?
The comparator for a map needs to be a "strict weak ordering," i.e. it cannot be that Comp(A,B) returns true and also Comp(B,A) returns true. Your comparator is a violation of this.
Here is my code:
#include <functional>
#include <iostream>
#include<vector>
using namespace std;
// vector iterator
template <class T> class vit
{
private:
//vector<T>::iterator it;
vector<T> m_v;
function<bool (T, T)> m_fptr;
int len, pos;
public:
vit(vector<T> &v) { this->m_v = v; len = v.size(); pos = 0;};
// it= v.begin(); };
bool next(T &i) {
//if(it == m_v.end()) return false;
if(pos==len) return false;
//i = *it;
i = m_v[pos];
//if(idle) { idle = false ; return true; }
//it++;
pos++;
return true;};
//bool idle = true;
void set_same(function<bool (T,T)> fptr) { m_fptr = fptr ;};
//void set_same(function<bool(int, int)> fun) { return ; }
bool grp_begin() {
return pos == 0 || ! m_fptr(m_v[pos], m_v[pos-1]); };
bool grp_end() {
return pos == len || ! m_fptr(m_v[pos], m_v[pos+1]); };
};
bool is_same(int a, int b) { return a == b; }
main()
{
vector<int> v ={ 1, 1, 2, 2, 2, 3, 1, 1, 1 };
int total;
for(auto it = v.begin(); it != v.end(); it++) {
if(it == v.begin() || *it != *(it-1)) {
total = 0;
}
total += *it;
if(it+1 == v.end() || *it != *(it+1)) {
cout << total << endl;
}
}
cout << "let's gry a group" <<endl;
vit<int> g(v);
int i;
while(g.next(i)) { cout << i << endl; }
cout << "now let's get really fancy" << endl;
vit<int> a_vit(v);
//auto is_same = [](int a, int b) { return a == b; };
a_vit.set_same(is_same);
//int total;
while(a_vit.next(i)) {
if(a_vit.grp_begin()) total = 0;
total += i;
if(a_vit.grp_end()) cout << total << endl ;
}
}
When I compile it with g++ -std=c++11 iter.cc -o iter, I get the result:
iter.cc: In function 'int main()':
iter.cc:63:17: error: reference to 'is_same' is ambiguous
a_vit.set_same(is_same);
^
iter.cc:37:6: note: candidates are: bool is_same(int, int)
bool is_same(int a, int b) { return a == b; }
^
In file included from /usr/include/c++/5.3.0/bits/move.h:57:0,
from /usr/include/c++/5.3.0/bits/stl_pair.h:59,
from /usr/include/c++/5.3.0/utility:70,
from /usr/include/c++/5.3.0/tuple:38,
from /usr/include/c++/5.3.0/functional:55,
from iter.cc:1:
/usr/include/c++/5.3.0/type_traits:958:12: note: template<class, class> struct std::is_same
struct is_same;
^
By way of explanation, I have created a class called 'vit'. It does two things: iterate over a vector, and determine if a new group has been reached.
The class function 'set_same' is supposed to store a function provided by the calling class to determine if two adjacent elements of a vector are in the same group. However, I can't seem to store the function in the class for future use by grp_begin() and grp_end() on account of the ostensible ambiguity of is_same.
What gives?
There is an is_same function defined by you and there is a struct is_same defined by the C++ Standard Library. Since you are using namespace std, your compiler doesn't know which is_same you meant to use.
It's what the error says: it's not clear whether you mean your is_same (in the global namespace) or the class template is_same (in namespace std).
You may disambiguate as follows:
::is_same
… with the leading :: meaning "in the global namespace".
Though you should consider putting your code in a namespace of its own.
Thanks guys. This is my first time touching C++ after more than a decade. I have cleaned up the code, and used a lambda to bring the "is_same" function closer to where it is called.
Did you spot the bug in my code? 'pos' was off-by-one when calling grp_begin() and grp_end(). Here is the revised code:
#include <functional>
#include <iostream>
#include <vector>
// vector iterator
template <class T> class vit
{
private:
std::vector<T> m_v;
std::function<bool (T, T)> m_fptr;
int len, pos;
public:
vit(std::vector<T> &v) { m_v = v; len = v.size(); pos = -1;};
bool next(T &val) {
pos++;
if(pos==len) return false;
val = m_v[pos];
return true;};
void set_same(std::function<bool (T,T)> fptr) { m_fptr = fptr ;};
bool grp_begin() {
return pos == 0 || ! m_fptr(m_v[pos], m_v[pos-1]); };
bool grp_end() {
return pos+1 == len || ! m_fptr(m_v[pos], m_v[pos+1]); };
};
main()
{
std::vector<int> v ={ 1, 1, 2, 2, 2, 3, 1, 1, 1 };
vit<int> a_vit(v);
std::function<bool (int, int)> is_same = [](int a, int b) { return a == b; };
a_vit.set_same(is_same);
int i, total;
while(a_vit.next(i)) {
if(a_vit.grp_begin()) total = 0;
total += i;
if(a_vit.grp_end()) std::cout << total << std::endl ;
}
}
My class definition isn't bullet-proof and could be better: if the user forgets to 'set-same', for example, they'll be referring a random memory address as a function.
Nevertheless, I'm pretty chuffed with my solution so far. The class caller is relieved of all the bookkeeping relating iterating over the vector, and working out if a group boundary has been crossed.
The calling code looks very compact and intuitive to me.I can see C++ being my go to language.
Comparing version numbers as strings is not so easy...
"1.0.0.9" > "1.0.0.10", but it's not correct.
The obvious way to do it properly is to parse these strings, convert to numbers and compare as numbers.
Is there another way to do it more "elegantly"? For example, boost::string_algo...
I don't see what could be more elegant than just parsing -- but please make use of standard library facilities already in place. Assuming you don't need error checking:
void Parse(int result[4], const std::string& input)
{
std::istringstream parser(input);
parser >> result[0];
for(int idx = 1; idx < 4; idx++)
{
parser.get(); //Skip period
parser >> result[idx];
}
}
bool LessThanVersion(const std::string& a,const std::string& b)
{
int parsedA[4], parsedB[4];
Parse(parsedA, a);
Parse(parsedB, b);
return std::lexicographical_compare(parsedA, parsedA + 4, parsedB, parsedB + 4);
}
Anything more complicated is going to be harder to maintain and isn't worth your time.
I would create a version class.
Then it is simple to define the comparison operator for the version class.
#include <iostream>
#include <sstream>
#include <vector>
#include <iterator>
class Version
{
// An internal utility structure just used to make the std::copy in the constructor easy to write.
struct VersionDigit
{
int value;
operator int() const {return value;}
};
friend std::istream& operator>>(std::istream& str, Version::VersionDigit& digit);
public:
Version(std::string const& versionStr)
{
// To Make processing easier in VersionDigit prepend a '.'
std::stringstream versionStream(std::string(".") + versionStr);
// Copy all parts of the version number into the version Info vector.
std::copy( std::istream_iterator<VersionDigit>(versionStream),
std::istream_iterator<VersionDigit>(),
std::back_inserter(versionInfo)
);
}
// Test if two version numbers are the same.
bool operator<(Version const& rhs) const
{
return std::lexicographical_compare(versionInfo.begin(), versionInfo.end(), rhs.versionInfo.begin(), rhs.versionInfo.end());
}
private:
std::vector<int> versionInfo;
};
// Read a single digit from the version.
std::istream& operator>>(std::istream& str, Version::VersionDigit& digit)
{
str.get();
str >> digit.value;
return str;
}
int main()
{
Version v1("10.0.0.9");
Version v2("10.0.0.10");
if (v1 < v2)
{
std::cout << "Version 1 Smaller\n";
}
else
{
std::cout << "Fail\n";
}
}
First the test code:
int main()
{
std::cout << ! ( Version("1.2") > Version("1.3") );
std::cout << ( Version("1.2") < Version("1.2.3") );
std::cout << ( Version("1.2") >= Version("1") );
std::cout << ! ( Version("1") <= Version("0.9") );
std::cout << ! ( Version("1.2.3") == Version("1.2.4") );
std::cout << ( Version("1.2.3") == Version("1.2.3") );
}
// output is 111111
Implementation:
#include <string>
#include <iostream>
// Method to compare two version strings
// v1 < v2 -> -1
// v1 == v2 -> 0
// v1 > v2 -> +1
int version_compare(std::string v1, std::string v2)
{
size_t i=0, j=0;
while( i < v1.length() || j < v2.length() )
{
int acc1=0, acc2=0;
while (i < v1.length() && v1[i] != '.') { acc1 = acc1 * 10 + (v1[i] - '0'); i++; }
while (j < v2.length() && v2[j] != '.') { acc2 = acc2 * 10 + (v2[j] - '0'); j++; }
if (acc1 < acc2) return -1;
if (acc1 > acc2) return +1;
++i;
++j;
}
return 0;
}
struct Version
{
std::string version_string;
Version( std::string v ) : version_string(v)
{ }
};
bool operator < (Version u, Version v) { return version_compare(u.version_string, v.version_string) == -1; }
bool operator > (Version u, Version v) { return version_compare(u.version_string, v.version_string) == +1; }
bool operator <= (Version u, Version v) { return version_compare(u.version_string, v.version_string) != +1; }
bool operator >= (Version u, Version v) { return version_compare(u.version_string, v.version_string) != -1; }
bool operator == (Version u, Version v) { return version_compare(u.version_string, v.version_string) == 0; }
https://coliru.stacked-crooked.com/a/7c74ad2cc4dca888
Here's a clean, compact C++20 solution, using the new spaceship operator <=>, and Boost's string split algorithm.
This constructs and holds a version string as a vector of numbers - useful for further processing, or can be disposed of as a temporary. This also handles version strings of different lengths, and accepts multiple separators.
The spaceship operator lets us provide results for <, > and == operators in a single function definition (although the equality has to be separately defined).
#include <compare>
#include <boost/algorithm/string.hpp>
struct version {
std::vector<size_t> data;
version() {};
version(std::string_view from_string) {
/// Construct from a string
std::vector<std::string> data_str;
boost::split(data_str, from_string, boost::is_any_of("._-"), boost::token_compress_on);
for(auto const &it : data_str) {
data.emplace_back(std::stol(it));
}
};
std::strong_ordering operator<=>(version const& rhs) const noexcept {
/// Three-way comparison operator
size_t const fields = std::min(data.size(), rhs.data.size());
// first compare all common fields
for(size_t i = 0; i != fields; ++i) {
if(data[i] == rhs.data[i]) continue;
else if(data[i] < rhs.data[i]) return std::strong_ordering::less;
else return std::strong_ordering::greater;
}
// if we're here, all common fields are equal - check for extra fields
if(data.size() == rhs.data.size()) return std::strong_ordering::equal; // no extra fields, so both versions equal
else if(data.size() > rhs.data.size()) return std::strong_ordering::greater; // lhs has more fields - we assume it to be greater
else return std::strong_ordering::less; // rhs has more fields - we assume it to be greater
}
bool operator==(version const& rhs) const noexcept {
return std::is_eq(*this <=> rhs);
}
};
Example usage:
std::cout << (version{"1.2.3.4"} < version{"1.2.3.5"}) << std::endl; // true
std::cout << (version{"1.2.3.4"} > version{"1.2.3.5"}) << std::endl; // false
std::cout << (version{"1.2.3.4"} == version{"1.2.3.5"}) << std::endl; // false
std::cout << (version{"1.2.3.4"} > version{"1.2.3"}) << std::endl; // true
std::cout << (version{"1.2.3.4"} < version{"1.2.3.4.5"}) << std::endl; // true
int VersionParser(char* version1, char* version2) {
int a1,b1, ret;
int a = strlen(version1);
int b = strlen(version2);
if (b>a) a=b;
for (int i=0;i<a;i++) {
a1 += version1[i];
b1 += version2[i];
}
if (b1>a1) ret = 1 ; // second version is fresher
else if (b1==a1) ret=-1; // versions is equal
else ret = 0; // first version is fresher
return ret;
}