How to lexicographically compare two vectors in reverse order? - c++

If I want to compare two vectors in lexicographical order, I can do as follows:
int main() {
std::vector<int> a{0, 7, 8, 9};
std::vector<int> b{1, 2, 3, 4};
std::cout << std::boolalpha;
std::cout << "a < b returns " << (a < b) << '\n';
}
But doing the same in reverse order fails to compile:
int main() {
std::vector<int> a{3, 2, 1};
std::vector<int> b{9, 8, 7, 6};
std::cout << std::boolalpha;
std::cout << "revrese a < reverse b returns " << ((a | std::views::reverse) < (b | std::views::reverse)) << '\n';
}
The latter code fails with:
<source>:23:81: error: no match for 'operator<' (operand types are 'std::ranges::reverse_view<std::ranges::ref_view<std::vector<int> > >' and 'std::ranges::reverse_view<std::ranges::ref_view<std::vector<int> > >')
23 | std::cout << "reverse a < reverse b returns " << ((a | std::views::reverse) < (b | std::views::reverse)) << '\n';
| ~~~~~~~~~~~~~~~~~~~~~~~~~ ^ ~~~~~~~~~~~~~~~~~~~~~~~~~
| | |
| reverse_view<[...]> reverse_view<[...]>
So, how to do achieve this properly?
I needed this because, I was creating a custom big integer class. In that, I was storing nodes in little endian order. Now, to compare if two integers are equal, first I compare their sizes. Then I would need to compare equal sized vectors in lexicographical order of their reverse view.

operator< is not defined for std::views::reverse and others. There is however a normal algorithm as normal function template for it in the standard library: std::lexicographical_compare with iterator interface and std::ranges::lexicographical_compare with range interface.
std::cout << "revrese a < reverse b returns "
<< std::ranges::lexicographical_compare(a | std::views::reverse, b | std::views::reverse)
<< '\n';

As #user17732522 said you can use std::lexicographical_compare && std::views::reverse but if you want use c++11 you can simply use reverse iterators with std::lexicographical_compare.
#include <algorithm>
#include <iostream>
#include <vector>
int main() {
std::vector<int> a{0, 7, 8, 9};
std::vector<int> b{1, 2, 3, 4};
std::cout << std::boolalpha;
std::cout << "a < b returns "
<< std::lexicographical_compare(a.cbegin(), a.cend(), b.rbegin(),
b.rend())
<< '\n';
}

Related

myProgrammingLab Palindrome Challenge Using Recursion

I'm taking an Intro to Programming class and a good chunk of the material is drilled into our heads through myProgrammingLab. I'm having a little trouble with the concept of Recursion... It's sort of been hit or miss for me. This particular problem has me stumped. When I submit my code, it offers me
CTest1.cpp: In function 'bool isPalindrome(int*, int)':
CTest1.cpp:9: error: invalid conversion from 'int' to 'int*'
CTest1.cpp:9: error: initializing argument 1 of 'bool isPalindrome(int*, int)'"
as advice, which I can assure you is not very helpful. Lol
I think my main problem is when I get to the actual recursion. I'm aware that something's off, but.. If you could just point me in the right direction, I would very much appreciate it.
A 'array palindrome' is an array which, when its elements are reversed, remains the same (i.e., the elements of the array are same when scanned forward or backward)
Write a recursive, bool-valued function, isPalindrome, that accepts an integer -valued array , and the number of elements and returns whether the array is a palindrome.
An array is a palindrome if: the array is empty (0 elements ) or contains only one element (which therefore is the same when reversed), or the first and last elements of the array are the same, and the rest of the array (i.e., the second through next-to-last elements ) form a palindrome.
My code so far:
bool isPalindrome(int arr[], int n)
{
if (n == 0 || n == 1)
{
return true;
}
else if (arr[n-1] == isPalindrome(arr[((n-1) - n) +1 ], n))
{
return true;
}
else
{
return false;
}
}
Recursion mostly has three main components:
a stopping condition (when you reach an array size small enough to be a guaranteed palindrome (0 or 1)),
a computation step (e.g. to compare the first and last item of the array and determine whether it makes sense to continue) and
a data subset selection for the nested recursion call (e.g. an array of size n - 2, excluding the first and last characters, which we already compared and found “palindrome-worthy”).
The three components in code:
bool isPalindrome(int arr[], size_t n) {
return n < 2 || (
arr[0] == arr[n - 1] &&
isPalindrome(arr + 1, n - 2));
}
Of course you may want to test the function a bit (and do not forget to run it under valgrind as well):
#include <iostream>
int main() {
std::cout << isPalindrome((int[0]){}, 0) << std::endl;
std::cout << isPalindrome((int[1]){1}, 1) << std::endl;
std::cout << isPalindrome((int[2]){1, 1}, 2) << std::endl;
std::cout << isPalindrome((int[2]){2, 1}, 2) << std::endl;
std::cout << isPalindrome((int[2]){1, 2}, 2) << std::endl;
std::cout << isPalindrome((int[3]){1, 2, 1}, 3) << std::endl;
std::cout << isPalindrome((int[3]){2, 2, 2}, 3) << std::endl;
std::cout << isPalindrome((int[3]){2, 2, 1}, 3) << std::endl;
std::cout << isPalindrome((int[4]){1, 2, 1, 2}, 4) << std::endl;
std::cout << isPalindrome((int[4]){1, 2, 2, 1}, 4) << std::endl;
std::cout << isPalindrome((int[4]){1, 2, 3, 2}, 4) << std::endl;
std::cout << isPalindrome((int[4]){2, 3, 2, 1}, 4) << std::endl;
std::cout << isPalindrome((int[4]){1, 3, 3, 1}, 4) << std::endl;
}
As a side note, this^^^ deadly struggle with arrays suggests that a different data type would be a much better choice. For example, std::string or std::vector can be initialized way easier, should be passed by reference and, as a bonus, STL containers carry size information with them. Additionally, you can use std::string_view for substrings and std::span for “subvectors” in your recursion, without copying the container over and over on each recursion level.
Here’s an example with std::string_view and three different implementations (one with recursion and two without recursion):
#include <iostream>
#include <string_view>
bool isPalindrome1(const std::string_view s) {
return s.size() < 2 || (
s[0] == s[s.size() - 1] &&
isPalindrome1(s.substr(1, s.size() - 2)));
}
bool isPalindrome2(const std::string_view s) {
const size_t end = s.size() / 2;
for (size_t i = 0; i < end; ++i)
if (s[i] != s[s.size() - i - 1])
return false;
return true;
}
bool isPalindrome3(const std::string_view s) {
auto b = s.begin();
const auto end = b + s.size() / 2;
auto e = s.rbegin();
for (; b < end; ++b, ++e)
if (*b != *e) return false;
return true;
}
int main() {
for (auto isPalindrome : {isPalindrome1,
isPalindrome2,
isPalindrome3}) {
std::cout << isPalindrome("") << std::endl;
std::cout << isPalindrome("a") << std::endl;
std::cout << isPalindrome("ab") << std::endl;
std::cout << isPalindrome("aa") << std::endl;
std::cout << isPalindrome("abc") << std::endl;
std::cout << isPalindrome("aba") << std::endl;
std::cout << isPalindrome("baab") << std::endl;
std::cout << isPalindrome("baba") << std::endl;
}
}
isPalindrome does not accept an int as a first argument. It accepts only an array, by doing this: arr[((n-1) - n) +1] you are feeeding it an int instead if an array of ints. This ((n-1) - n) +1 will evaluate to a “position” in the array, eg: arr[0] being the first element, your case an int.

How to get size of nested std::initializer_lists?

std::initializer_list has a member function size that returns the number of elements in the initializer list.
Considering there is no [] operator for a std::initializer_list, and a user does not want to use for-loop to access the size of each sub-list:
How can a user get the size of an inner std::initializer_list from std::initializer_list<std::initializer_list>.
For example, from the following example, could you please tell me how a user can access the size of the first nested initializer_list, {1, 2, 3}?
#include <iostream>
#include <string>
int main()
{
std::initializer_list<std::initializer_list<int>> a = { {1, 2, 3}, {2, 3, 4} };
std::cout << a.size() << std::endl; // Provides = 2
// Now I want to access the size of the first nested std::initializer_list:
// std::cout << a[0].size() << std::endl; // Does not compile
return 0;
}
You can take advantage of std::initializer_list::begin,
Returns a pointer to the first element in the initializer list.
e.g.
std::cout << a.begin()->size() << std::endl; // Provides = 3
std::cout << (a.begin() + 1)->size() << std::endl; // Provides = 3
You can do this:
for(const auto& ilist: a)
std::cout << ilist.size() << std::endl; // Compiles
See Demo.
If required, you can assign the sizes to different variables within the for loop.

Slicing a vector in C++

Is there an equivalent of list slicing [1:] from Python in C++ with vectors? I simply want to get all but the first element from a vector.
Python's list slicing operator:
list1 = [1, 2, 3]
list2 = list1[1:]
print(list2) # [2, 3]
C++ Desired result:
std::vector<int> v1 = {1, 2, 3};
std::vector<int> v2;
v2 = v1[1:];
std::cout << v2 << std::endl; //{2, 3}
This can easily be done using std::vector's copy constructor:
v2 = std::vector<int>(v1.begin() + 1, v1.end());
In C++20 it is pretty easy:
#include <span>
#include <vector>
#include <iostream>
template<int left = 0, int right = 0, typename T>
constexpr auto slice(T&& container)
{
if constexpr (right > 0)
{
return std::span(begin(std::forward<T>(container))+left, begin(std::forward<T>(container))+right);
}
else
{
return std::span(begin(std::forward<T>(container))+left, end(std::forward<T>(container))+right);
}
}
int main()
{
std::vector v{1,2,3,4,5,6,7,8,9};
std::cout << "-------------------" << std::endl;
auto v0 = slice<1,0>(v);
for (auto i : v0)
{
std::cout << i << std::endl;
}
std::cout << "-------------------" << std::endl;
auto v1 = slice<0,-1>(v);
for (auto i : v1)
{
std::cout << i << std::endl;
}
std::cout << "-------------------" << std::endl;
auto v2 = slice<1,3>(v);
for (auto i : v2)
{
std::cout << i << std::endl;
}
std::cout << "-------------------" << std::endl;
auto v3 = slice<1,-1>(v);
for (auto i : v3)
{
std::cout << i << std::endl;
}
std::cout << "-------------------" << std::endl;
auto v4 = slice<3,3>(v);
for (auto i : v4)
{
std::cout << i << std::endl;
}
}
Result:
Program returned: 0
-------------------
2
3
4
5
6
7
8
9
-------------------
1
2
3
4
5
6
7
8
-------------------
2
3
-------------------
2
3
4
5
6
7
8
-------------------
You can also add boundary checks and other cases like negative left indices etc... but this is only an example.
Run in compiler explorer: https://godbolt.org/z/qeaxvjdbj
I know it's late but have a look at valarray and its slices. If you are using a vector of some sort of NumericType, then it's worth giving it a try.
It depends on whether you want a view or a copy.
Python's slicing for lists copies references to the elements, so it cannot be simply regarded as a view or a copy. For example,
list1 = [1, 2, 3]
list2 = list1[1:]
list2[1] = 5
print(list1) # does not change, still [1, 2, 3]
list1 = [1, 2, [3]]
list2 = list1[1:]
list2[1][0] = 5
print(list1) # changes, becomes [1, 2, [5]]
See this post for details.
DimChtz's anwer models the copy situation. If you just want a view, in C++20, you can use ranges (besides std::views::drop, std::views::take and std::views::counted are also useful):
auto v2 = v1 | std::views::drop(1); // #include <ranges>
for (auto &e: v2) std::cout << e << '\n';
or std::span:
std::span v2{v1.begin() + 1, v1.end()}; // #include <span>
for (auto &e: v2) std::cout << e << '\n';
You can follow the above answer. It's always better to know multiple ways.
int main
{
std::vector<int> v1 = {1, 2, 3};
std::vector<int> v2{v1};
v2.erase( v2.begin() );
return 0;
}
It seems that the cheapest way is to use pointer to the starting element and the number of elements in the slice. It would not be a real vector but it will be good enough for many uses.

Lower bound error

I am following this tutorial on Lower_bound() in C++. I have made a simple code to find a number in a vector lesser than or equal to a number from the vector + any number that I want. My code goes like this
cout << *lower_bound(A.begin(), A.end(), A[x] + 3);
where the vector A[] is sorted. But the code points it to a number greater than the sum of both the numbers.
For example if my vector has values as 0, 3, 5, 8, 12 and I want it to print the nearest number lesser than or equal to A[3] + 3 = 11 it should give output as 8 but it gives the output of 12. Any reasons?
Here is my code:
#include <bits/stdc++.h>
using namespace std;
int main() {
vector<int> A = {0, 5, 3, 12, 8};
sort(A.begin(), A.end());
cout << "A[3] = " << A[3] << endl;
cout << *lower_bound(A.begin(), A.end(), A[3] + 3) << endl;
return 0;
}
lower_bound
Returns an iterator pointing to the first element in the range [first,last) which does not compare less than val.
In your case it is not returning the last value less than 11. It returns the first value not less than 11, which in your example is 12.
If you want the largest number not greater than your target, you can use std::greater<> and reverse iterators (or sort by std::greater<>)
#include <vector>
#include <iostream>
#include <algorithm>
int main() {
std::vector<int> A = {0, 5, 3, 12, 8};
std::sort(A.begin(), A.end());
std::cout << "A[3] = " << A[3] << std::endl;
std::cout << *std::lower_bound(A.rbegin(), A.rend(), A[3] + 3, std::greater<int>{}) << std::endl;
return 0;
}

How to write a n-ary negator?

The usefulness of unary and binary negators is easily understandable.
Example with unary negator (not1):
class Even
{
public:
bool operator() (const int& x) const { return x % 2 == 0; }
typedef int argument_type;
};
int values[] = { 9, 1, 8, 2, 7, 3, 6, 4, 5 };
int even = count_if(values, values + 9, Even());
int odd = count_if(values, values + 9, not1(Even())); // <= unary negator
cout << "We have " << even << " even elements in the array.\n";
cout << "We have " << odd << " odd elements in the array.\n";
Output:
We have 4 even elements in the array.
We have 5 odd elements in the array.
Example with binary negator (not2):
int values[] = { 9, 1, 8, 2, 7, 3, 6, 4, 5 };
// original array
for (int i : values)
cout << i << " ";
cout << "\n";
// array in ascending order
sort(values, values + 9, less<int>());
for (int i : values)
cout << i << " ";
cout << "\n";
// array in descending order
sort(values, values + 9, not2(less<int>())); // <= binary negator
for (int i : values)
cout << i << " ";
cout << "\n\n";
Output:
9 1 8 2 7 3 6 4 5
1 2 3 4 5 6 7 8 9
9 8 7 6 5 4 3 2 1
What about n-ary negators (not3, not4, not5 ... notn) ?
Let's assume that I need to count the number of elements that are not between two numbers (lower bound limit and upper bound limit) in a collection (maybe an array).
.
int elems_betweem = count_if(values, values + n, not3(bind(Between<int>(), _1, lowerValue, upperValue)));
.
How do I write the not3 negator?
Even more, do we have a generic not as a replacer of not1 and not2 in the same way as bind vs bind1st and bind2nd ?
Thank you
Since C++17 std::not_fn will be available:
auto between = [](int value, int lowerValue, int upperValue) {
return lowerValue < value && value < upperValue;
};
int elems_between = std::count_if(std::cbegin(values), std::cend(values),
std::bind(std::not_fn(between), std::placeholders::_1, lowerValue, upperValue));
wandbox example
How do I write the not3 negator?
A C++03 compliant example:
template<class Pred>
class ternary_predicate {
Pred pred;
public:
ternary_predicate(Pred pred): pred(pred){}
template<class A, class B, class C>
bool
operator()(A const& a, B const& b, C const& c) const {
return !pred(a, b, c);
}
};
template<class Pred>
ternary_predicate<Pred>
not3(Pred pred) {
return ternary_predicate<Pred>(pred);
}
Even more, do we have a generic not as a replacer of not1 and not2 in the same way as bind vs bind1st and bind2nd ?
We will, once C++17 is official. It is proposed to introduce std::not_fn as a replacement for std::not1 and std::not2 which will then be deprecated.
If you feel impatient, it's should not be difficult to implement yourself in C++14:
template<class Pred>
auto
not_fn(Pred&& pred) {
return [pred=std::forward<Pred>(pred)](auto&&... args){
return !pred(std::forward<decltype(args)>(args)...);
};
}
You can write your own std::not_fn as long as it's not available:
template <typename T>
struct not_func
{
template <typename...Args>
constexpr bool operator()(const Args&...args) const { return !T{}(args...); }
};
Example usage:
int main()
{
bool a1 = std::less<int>{}(1, 2);
bool a2 = not_func<std::less<int>>{}(1, 2);
bool b1 = Even{}(1);
bool b2 = not_func<Even>{}(1);
std::cout
<< "a1 = " << (a1 ? "true" : "false") << "\n"
<< "a2 = " << (a2 ? "true" : "false") << "\n"
<< "b1 = " << (b1 ? "true" : "false") << "\n"
<< "b2 = " << (b2 ? "true" : "false") << "\n";
}
[On Coliru]
[On Godbolt]
I haven't tested all possible variants so this might still be buggy.