Adjacent adaptor using boost::range - c++

I'm asking myself if it is possible to extend boost-range by an adaptor, which I call adjacentAdaptor. This adaptor should basically iterate over all pairs of adjacent elements in a vector, list and so on.
I think this function is very useful in my use cases, where I often have to iterate over lists representing time steps.
The output of the last for loop should be something like:
0 1
1 2
2 3
A vector having only one element or no elements should produce nothing.
I tried using boost::adaptors::sliced producing the necessary sublist, but then I don't know how boost::range can help me to zip both subranges to one.
I just found a probable solution using boost::iterators, but I really don't like the amount of code one has to write. Also I'm missing the first and second instead I have to write a clumsy get<>. Unfortunately, the program crashes if the vector is empty!
#include <vector>
#include <iostream>
#include <boost/range.hpp>
#include <boost/range/algorithm/transform.hpp>
#include <boost/range/adaptor/sliced.hpp>
#include <boost/iterator.hpp>
#include <boost/iterator/zip_iterator.hpp>
int main()
{
std::vector<int> v = { 0,1,2,3 };
for (auto iter : v | boost::adaptors::sliced(0, v.size() - 1)) {
std::cout << "First: " << iter << std::endl;
}
for (auto iter : v | boost::adaptors::sliced(1, v.size())) {
std::cout << "Second: "<< iter << std::endl;
}
auto s = boost::iterators::make_zip_iterator(boost::make_tuple(v.begin(), v.begin() + 1));
auto e = boost::iterators::make_zip_iterator(boost::make_tuple(v.end()-1, v.end()));
for (auto iter : boost::make_iterator_range(s, e)) {
std::cout << iter.get<0>() << " " << iter.get<1>() << std::endl;
}
// for (auto iter : v | adjacentAdaptor) {
// std::cout << iter.first << " " << iter.second << std::endl;
// }
}
I'm very glad for any help I can receive in this question.
Own partial solution
After some template type deduction I came up with something relatively useable.
#include <vector>
#include <iostream>
#include <boost/range.hpp>
#include <boost/range/algorithm/transform.hpp>
#include <boost/range/adaptor/sliced.hpp>
#include <boost/iterator.hpp>
#include <boost/iterator/zip_iterator.hpp>
template<typename T>
using retHelperType = decltype(boost::iterators::make_zip_iterator(boost::make_tuple(T().begin(), T().begin() + 1)));
template<typename T>
using retType = decltype(boost::make_iterator_range(retHelperType<T>(), retHelperType<T>()));
template<typename T>
retType<T> adjacentIterator(T& v) {
if (v.empty()) {
auto s = boost::iterators::make_zip_iterator(boost::make_tuple(v.end(), v.end()));
auto e = boost::iterators::make_zip_iterator(boost::make_tuple(v.end(), v.end()));
return boost::make_iterator_range(s, e);
}
else {
auto s = boost::iterators::make_zip_iterator(boost::make_tuple(v.begin(), std::next(v.begin())));
auto e = boost::iterators::make_zip_iterator(boost::make_tuple(std::prev(v.end()), v.end()));
return boost::make_iterator_range(s, e);
}
}
int main()
{
retType<std::vector<int>> x;
std::vector<int> v = { };
for (auto iter : adjacentIterator(v)) {
std::cout << iter.get<0>() << " " << iter.get<1>() << std::endl;
}
}
Still, it would be nicer to access the elements with first and second, but I have no idea to achieve this behavior.

Related

what is the time complexity and space complexity of this solution? Question- Top K Frequent Elements (Leetcode-Medium)

vector<int> topKFrequent(vector<int>& nums, int k) {
if(k==nums.size())
return nums;
map<int,int> mp;
for(int i=0;i<nums.size();i++)
mp[nums[i]]++;
multimap<int,int> m;
for(auto& it:mp){
m.insert({it.second,it.first});
}
vector<int> ans;
for (auto itr = m.crbegin(); itr != m.crend(); ++itr){
ans.push_back(itr->second);
if(ans.size()==k)
break;
}
return ans;
}
I am using multimap to sort the map by values.I don't understand if I use priority queue which time complexity is better ? using priority_queue or using multimap? Can anyone explain?
In my opinion you have not the optimal solution.
You use a std::map instead of a std::unordered_map. That will have a higher complexity in most cases. std::maphas logarithmic complexity, std::unordered_map has on average constant-time complexity.
The std::multimap is not needed at all. It will add unneccessary space and time complexity (Logarithmic). A std::priority_queuehas constant time lookup, but logarithmic insertion. So, could be better than the std::multimapin your case.
The most efficient solution would be to use a std::unordered_map and then std::partial_sort_copy. The complexity for this is O(N·log(min(D,N)), where N = std::distance(first, last), D = std::distance(d_first, d_last) applications of cmp. (Taken from CPPReference).
A somehow generic C++17 example solution could be the below:
#include <iostream>
#include <utility>
#include <unordered_map>
#include <algorithm>
#include <vector>
#include <iterator>
#include <type_traits>
// Helper for type trait We want to identify an iterable container ----------------------------------------------------
template <typename Container>
auto isIterableHelper(int) -> decltype (
std::begin(std::declval<Container&>()) != std::end(std::declval<Container&>()), // begin/end and operator !=
++std::declval<decltype(std::begin(std::declval<Container&>()))&>(), // operator ++
void(*std::begin(std::declval<Container&>())), // operator*
void(), // Handle potential operator ,
std::true_type{});
template <typename T>
std::false_type isIterableHelper(...);
// The type trait -----------------------------------------------------------------------------------------------------
template <typename Container>
using is_iterable = decltype(isIterableHelper<Container>(0));
// Some Alias names for later easier reading --------------------------------------------------------------------------
template <typename Container>
using ValueType = std::decay_t<decltype(*std::begin(std::declval<Container&>()))>;
template <typename Container>
using Pair = std::pair<ValueType<Container>, size_t>;
template <typename Container>
using Counter = std::unordered_map<ValueType<Container>, size_t>;
// Function to get the k most frequent elements used in any Container ------------------------------------------------
template <class Container>
auto topKFrequent(const Container& data, size_t k) {
if constexpr (is_iterable<Container>::value) {
// Count all occurences of data
Counter<Container> counter{};
for (const auto& d : data) counter[d]++;
// For storing the top k
std::vector<Pair<Container>> top(k);
// Get top k
std::partial_sort_copy(counter.begin(), counter.end(), top.begin(), top.end(),
[](const Pair<Container>& p1, const Pair<Container>& p2) { return p1.second > p2.second; });
return top;
}
else
return data;
}
int main() {
std::vector testVector{ 1,2,2,3,3,3,4,4,4,4,5,5,5,5,6,6,6,6,6,7 };
for (const auto& p : topKFrequent(testVector, 2)) std::cout << "Value: " << p.first << " \t Count: " << p.second << '\n';
std::cout << '\n';
double cStyleArray[] = { 1.1, 2.2, 2.2, 3.3, 3.3, 3.3 };
for (const auto& p : topKFrequent(cStyleArray, 2)) std::cout << "Value: " << p.first << " \t Count: " << p.second << '\n';
std::cout << '\n';
std::string s{ "abbcccddddeeeeeffffffggggggg" };
for (const auto& p : topKFrequent(s, 2)) std::cout << "Value: " << p.first << " \t Count: " << p.second << '\n';
std::cout << '\n';
double value = 12.34;
std::cout << topKFrequent(value, 2) << "\n";
}

Python's enumerate for C++ [duplicate]

This question already has answers here:
How to find the index of current object in range-based for loop?
(12 answers)
Closed 4 years ago.
In Python there is enumerate which takes a sequence/iterator and yields pairs of an integer index and the value itself. In C++ I occasionally find myself writing
for (size_t i = 0; i != vector.size(); ++i) {
auto const &elem = vector[i];
// ...
Similar to Python I would like to write
for (auto const &it : enumerate(vector)) {
// it.first is the index (size_t)
// it.second is the element (T const&)
Does such an enumerate exist in either the STL or a common library like Boost?
Yes, this is what Boost's adapators::indexed does.
Their example (which also uses the now-redundant Boost.Assign for terse container initialisation) follows:
#include <boost/range/adaptor/indexed.hpp>
#include <boost/assign.hpp>
#include <iterator>
#include <iostream>
#include <vector>
int main(int argc, const char* argv[])
{
using namespace boost::assign;
using namespace boost::adaptors;
std::vector<int> input;
input += 10,20,30,40,50,60,70,80,90;
for (const auto& element : input | indexed(0))
{
std::cout << "Element = " << element.value()
<< " Index = " << element.index()
<< std::endl;
}
return 0;
}
Nothing in the standard library, though it's not hard to write.
Here is an example using range-v3. A bit more verbose than a handcrafted solution, but it's nice IMHO how you can assemble such a range from existing views.
#include <range/v3/view/indices.hpp>
#include <range/v3/view/zip.hpp>
using namespace ranges;
std::vector<int> vec{42, 43, 44};
for (const auto& idxAndValue : view::zip(view::indices, vec))
std::cout << ideAndValue.first << " : " << idxAndValue.second << "\n";;
Another way that only works:
with references to elements, and
array-based containers, and
elements do not overload operator&
for(auto const &it : vector) {
size_t index = &it - vector.data();
}
Here's a version using an higher-order function. I like it because it's simple to implement and doesn't require you to know the nuances of structured bindings. It also doesn't require any extra dependency.
template <typename Container, typename F>
void enumerate(Container&& c, F&& f)
{
std::size_t i = 0;
for(auto&& x : std::forward<Container>(c))
{
f(i++, forward_like<Container>(x));
}
}
(Where forward_like moves x if Container is an rvalue.)
Usage:
enumerate(std::vector{'a', 'b', 'c'}, [](auto index, auto x)
{
std::cout << index << ": " << x << '\n';
});
Prints:
0: 'a'
1: 'b'
2: 'c'
live example on wandbox.org
C++11 compliant version: live example on wandbox.org

std::list<std::shared_ptr>::erase got an SIGSEGV

Consider following code:
#include <iostream>
#include <list>
#include <memory>
class Foo;
class Foo {
public:
Foo(int i): id(i) {}
typename std::list<std::shared_ptr<Foo>>::iterator i2;
int id;
};
int main() {
std::list<std::shared_ptr<Foo>> l;
auto f1 = std::make_shared<Foo>(1);
f1->i2 = l.end();
l.insert(f1->i2, f1);
std::cout << f1->id << std::endl;
std::cout << l.size() << std::endl;
for (auto i: l) {
std::cout << i->id << std::endl;
}
auto t = f1->i2;
l.erase(t);
std::cout << l.size() << std::endl;
}
Executing these code will get an SIGSEGV at l.erase(t),seems ListNode were destroyed before shared_ptr decrease its ref_count. Why?How to fix it?
After insert your f1->i2 left l.end(). You try to erase l.end(), that is not allowed.
Fix is simple. Change the line where insert called:
f1->i2 = l.insert(f1->i2, f1);
Iterator,initialized before insert/remove operation, may be in an indeterminate state after the operation and should be updated again. Also you are trying to delete a node in the list through an iterator which itself is pointing to list.end(). For deleting the last element of a list, you can rather use std::list.pop_back();
auto t = f1->i2;
l.erase(--t); // Change this in your code - decrease the iterator

I want to reverse the values of map and print it using range based for loop.

I have done the programming but it is not reversing. I have used a different map to put the values in reverse order,but it still shows the same. My main question was to traverse backward and print the values using range based loop.
#include "stdafx.h"
#include <iostream>
#include<conio.h>
#include <stdio.h>
#include<vector>
#include<map>
#include<utility>
#include<set>
map<int, int>m1;
for (int i = 1; i <= 100; ++i)
{
m1.insert({ i,i });
}
for (const auto &y :m1)
{
cout <<"("<< y.first << " "<<y.second << ")" <<" " ;
}
cout << endl << endl;
map<int, int>m2;
map<int, int>::reverse_iterator iter;
for (auto iter = m1.rbegin(); iter != m1.rend(); ++iter)
{
m2.insert({ iter->first,iter->second });
}
for (const auto &y : m2)
{
cout << "(" << y.first << " " << y.second << ")" << " ";
}
As Some Programmer Dude pointed out, but for the completeness of my answer, a std::map is sorted on the key, no matter what order you insert the elements. One option would be to create a new map with the opposite sorting, but that doesn't seem to be what you really want.
It seems you know how about reverse iterators, but not how to get at them when using range-based for. Since it operates on a range, i.e. some type that provides begin and end iterators, you need to create some wrapper around your map that provides this.
Here's a general one I just put together than works in C++11. It won't cover every possible case, and can be made a bit neater in C++14, but it will work for you.
#include <iostream>
#include <iterator>
// The wrapper type that does reversal
template <typename Range>
class Reverser {
Range& r_;
public:
using iterator_type = std::reverse_iterator<decltype(std::begin(r_))>;
Reverser(Range& r) : r_(r) {}
iterator_type begin() { return iterator_type(std::end(r_)); }
iterator_type end() { return iterator_type(std::begin(r_)); }
};
// Helper creation function
template <typename Range>
Reverser<Range> reverse(Range& r)
{
return Reverser<Range>(r);
}
int main()
{
int vals[] = {1, 2, 3, 4, 5};
for (auto i : reverse(vals))
std::cout << i << '\n';
}
This outputs:
$ ./reverse
5
4
3
2
1
(You may also find libraries that provide a similar adapter; Eric Niebler is working on a ranges library for The Standard.)
Also, please reconsider your use of what are often considered bad practices: using namespace std; and endl (those are links to explanations).
Here's an example of iterating backward through a std::map:
#include <iostream>
#include <map>
#include <string>
int main() {
std::map<int, int> m;
m[1] = 1;
m[2] = 2;
m[3] = 3;
for (auto iter = m.rbegin(); iter != m.rend(); ++iter) {
std::cout << iter->first << ": " << iter->second << std::endl;
}
}
If you are pre-C++11, you'll just need to spell out auto, which is:
std::map<int, int>::reverse_iterator
If you're using boost, you can use a range-based for loop with a reverse adapter:
#include <boost/range/adaptor/reversed.hpp>
for (auto& iter : boost::adaptors::reverse(m)) {
std::cout << iter.first << ": " << iter.second << std::endl;
}
If you only need to print the elements in the map in reverse order,you don't need another map for it,you can do this:
std::map<int, int>::reverse_iterator iter;
for (iter = m1.rbegin(); iter != m1.rend(); ++iter)
{
std::cout << "(" << iter->first << " " << iter->second << ")" << " ";
}

Checking if a sequence container is contiguous in memory

Is there a way to check if a sequence container is contiguous in memory? Something like:
#include <iostream>
#include <vector>
#include <deque>
#include <array>
int main()
{
std::cout << std::boolalpha;
std::cout << is_contiguous<std::vector<int>>::value << '\n' // true
std::cout << is_contiguous<std::deque<int>>::value << '\n'; // false
std::cout << is_contiguous<std::array<int, 3>>::value << '\n'; // true
}
Clarification
This question is referring to type traits, rather than the properties of a specific instance of a type.
No, there is not compiletime trait for this.
The draft C++1z Standard defines contiguity as a runtime property of an iterator range. Note there is no compiletime std::contiguous_iterator_tag corresponding to this iterator category.
24.2 Iterator requirements [iterator.requirements]
24.2.1 In general [iterator.requirements.general]
5 Iterators that further satisfy the requirement that, for integral
values n and dereferenceable iterator values a and (a + n), *(a + n)
is equivalent to *(addressof(*a) + n), are called contiguous
iterators. [ Note: For example, the type “pointer to int” is a
contiguous iterator, but reverse_iterator<int *> is not. For a valid
iterator range [a,b) with dereferenceable a, the corresponding range
denoted by pointers is [addressof(*a),addressof(*a) + (b - a)); b
might not be dereferenceable. — end note ]
One way to test for this at runtime would be
#include <array>
#include <deque>
#include <list>
#include <iostream>
#include <iterator>
#include <map>
#include <memory>
#include <string>
#include <unordered_set>
#include <vector>
template<class I>
auto is_contiguous(I first, I last)
{
auto test = true;
auto const n = std::distance(first, last);
for (auto i = 0; i < n && test; ++i) {
test &= *(std::next(first, i)) == *(std::next(std::addressof(*first), i));
}
return test;
}
int main()
{
auto l = std::list<int> { 1, 2, 3 };
auto m = std::map<int, int> { {1, 1}, {2,2}, {3,3} };
auto u = std::unordered_multiset<int> { 1, 1, 1 };
auto d = std::deque<int>(4000);
int c[] = { 1, 2, 3 };
auto a = std::array<int, 3> {{ 1, 2, 3 }};
auto s = std::string {"Hello world!"};
auto v = std::vector<int> { 1, 2, 3, };
std::cout << std::boolalpha << is_contiguous(l.begin(), l.end()) << "\n";
std::cout << std::boolalpha << is_contiguous(m.begin(), m.end()) << "\n";
std::cout << std::boolalpha << is_contiguous(u.begin(), u.end()) << "\n";
std::cout << std::boolalpha << is_contiguous(d.begin(), d.end()) << "\n";
std::cout << std::boolalpha << is_contiguous(d.begin(), d.begin() + 1000) << "\n";
std::cout << std::boolalpha << is_contiguous(std::begin(c), std::end(c)) << "\n";
std::cout << std::boolalpha << is_contiguous(a.begin(), a.end()) << "\n";
std::cout << std::boolalpha << is_contiguous(s.begin(), s.end()) << "\n";
std::cout << std::boolalpha << is_contiguous(v.begin(), v.end()) << "\n";
std::cout << std::boolalpha << is_contiguous(v.rbegin(), v.rend()) << "\n";
}
Live Example. This prints false for the list, map and unordered_multimap, and true for the C-array, and the std::array, string and vector. It prints true for small subranges within a deque and false for large subranges. It also prints false for an iterator range consisting of reverse iterators.
UPDATE: as commented by #T.C. the original N3884 proposal did have a
struct contiguous_iterator_tag : random_access_iterator_tag {};
so that tag-dispatching on iterator categories would not break. However, this would have broken non-idiomatic code with class template specializations on random_access_iterator_tag. The current draft hence does not contain a new iterator category tag.
No. The C++ Standard guarantees there are no false negatives. (i.e., std::vector, std::string, std::array, and basic arrays are promised to be stored contiguously).
However, the C++ Standard doesn't guarantee there are no false positives.
int main() {
std::unique_ptr<Node> n1(new Node);
std::unique_ptr<Node> n2(new Node);
n1->next = n2; // n1 and n2 might be contiguous, but might not be
}
Thus, your type trait could be wrong some of the time. If it's wrong some of the time, it's not a type trait; rather, it's an instance trait.
No.​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​