Can std::transform be used in a nested way? Tried to do this:
{
return std::transform(asciivec(inner.front()).begin(), asciivec(inner.front()).end(), asciivec(inner.back()).begin(), asciivec(inner.back()).end(),out.begin(), std::minus<float>{});
}
);
Error:
stl_algo.h||In instantiation of '_OIter std::transform(_IIter, _IIter, _OIter, _UnaryOperation) [with _IIter = __gnu_cxx::__normal_iterator<const std::vector<std::__cxx11::basic_string<char> >*, std::vector<std::vector<std::__cxx11::basic_string<char> > > >; _OIter = __gnu_cxx::__normal_iterator<double*, std::vector<double> >; _UnaryOperation = main()::<lambda(const auto:1&)>]':|
error: no matching function for call to 'transform(std::vector<double>::iterator, std::vector<double>::iterator, std::vector<double>::iterator, std::vector<double>::iterator, std::vector<double>::iterator, std::minus<float>)'|
You were on the right track, but you missed a few things.
For binary operations, std::transform only takes both begin and end iterators for the first input range; it takes a begin iterator for the second range, and assumes the second range is at least as large as the first (such that for any element in the range [first1, last1), there's a matching element in the range starting at first2).
Assuming that asciivec() returns a temporary object (and not a reference to a cached object), the iterators asciivec(inner.front()).begin() and asciivec(inner.front()).end() will actually refer to two different ranges; this will cause runtime errors. You'll need to cache the results of your asciivec() calls inside the lambda, to give them enough permanence to finish the operation.
std::minus evaluates its operands as lhs - rhs, and thus will return -1 for std::minus<float>{}('a', 'b'). As your example results are positive, I have assumed you want absolute values, and have expanded & commentated my code thusly.
So, considering that, we can make a few slight alterations...
// Renamed "inner" to "in" for convenience here.
std::transform (inp.cbegin(), inp.cend(), out.begin(), [&](const auto& in)
{
// Tying element type to asciivec() for convenience.
using Container = decltype(asciivec(in.front()));
using Elem = typename Container::value_type;
//using Elem = typename decltype(asciivec(in.front()))::value_type;
// Create non-temporary vectors first, to guarantee expected results.
std::vector<Container> inner = { asciivec(in.front()), asciivec(in.back()) };
// Use either...
// static Container ret;
// ret.clear(); ret.resize(inner.front().size());
// Or...
Container ret(inner.front().size());
std::transform(inner.front().begin(), // InputIt first1
inner.front().end(), // InputIt last1
inner.back().begin(), // InputIt first2
//asciivec(inner.back()).end(), // Omit
ret.begin(), // OutputIt d_first
std::minus<float>{}); // BinaryOperation binary_op
// I'm positive you want absolute values. ;3
// Lambda provides nice, clean overload resolution, compared to a function pointer or similar.
std::transform(ret.begin(), ret.end(), ret.begin(), [=](const Elem& e) { return std::fabs(e); });
return ret;
}
);
If signedness is, in fact, desired, we can comment out the second transform() call.
See it in action here.
Edited to increase genericity, it should be fine to just drop in regardless of your data's actual types.
Related
How can we remove elements from a set like below which has iterator as part of its key? .erase() throws error saying no matching member function for call to 'erase'. Just like emplace() can be used for inserting tuples, what can be used for erasing a tuple from a set instead of directly providing iterator?
list<int> v;
static constexpr auto cmp = [](pair<int, list<int>::iterator > a, pair<int, list<int>::iterator > b)
{
return a.first < b.first;
};
set< pair<int, list<int>::iterator >, decltype(cmp) > Set{cmp};
v.push_back(1);
Set.emplace( 1, v.rbegin() ); // Works
Set.erase( make_pair(1, v.rbegin() ) ); // Throws error
Error
Line 23: Char 13: error: no matching member function for call to 'erase' Set.erase( make_pair(val, v.rbegin() ) ); ~~~~^~~~~ /usr/bin/../lib/gcc/x86_64-linux-gnu/9/../../../../include/c++/9/bits/stl_set.h:654:7: note: candidate function not viable: no known conversion from 'pair<typename __decay_and_strip<int &>::__type, typename __decay_and_strip<reverse_iterator<_List_iterator<int>>>::__type>' (aka 'pair<int, std::reverse_iterator<std::_List_iterator<int>>>') to 'std::set<std::pair<int, std::_List_iterator<int>>, const MaxStack::(lambda at prog_joined.cpp:10:33), std::allocator<std::pair<int, std::_List_iterator<int>>>>::const_iterator' (aka '_Rb_tree_const_iterator<std::pair<int, std::_List_iterator<int>>>') for 1st argument erase(const_iterator __position) ^ /usr/bin/../lib/gcc/x86_64-linux-gnu/9/../../../../include/c++/9/bits/stl_set.h:684:7: note: candidate function not viable: no known conversion from 'pair<[...], typename __decay_and_strip<reverse_iterator<_List_iterator<int>>>::__type>' to 'const pair<[...], std::_List_iterator<int>>' for 1st argument erase(const key_type& __x) ^ /usr/bin/../lib/gcc/x86_64-linux-gnu/9/../../../../include/c++/9/bits/stl_set.h:706:7: note: candidate function not viable: requires 2 arguments, but 1 was provided erase(const_iterator __first, const_iterator __last) ^
Context :
I am trying to create a datastructure where I receive a stream of elements and I need to store the order of the stream as well as be able to retrieve or erase the maximum element at any point.
The problem with this code is that your pair uses list::iterator but you try initializing it with rbegin() which returns objects of type reverse_iterator. Here is the consistent version that compiles.
Having said that, I suggest adding some context to the question and maybe we can suggest a simpler solution that will not require navigating through template complexities.
In this assignment, I'm making an application where a user inputs a phone number whether it be letters or not.
I've tried using the const on maps or vector to see if it fixes the problem, but I think it just created more errors.
Here's the code that I think that causes some problems
std::vector<int> mappednums;
for (char& achar : word) {
auto itr = std::find_if(lookupmap.begin(), lookupmap.end(), [&](std::pair<int, std::vector<char>>& aPair)->bool
{
auto itr = std::find_if(aPair.second.begin(), aPair.second.end(), [&](char& ch) {
return ch == achar;
});
if (itr != aPair.second.end()) {
return true;
}
});
if (itr != lookupmap.end()) {
mappednums.push_back(itr->first);
}
I expected this to find a pair, but it gives me an error saying it cannot convert argument 1 from the code above. Here's the error:
'bool main::<lambda_06927067034dcc4076cc2514a7e290fe>::operator ()(std::pair<int,std::vector<char,std::allocator<char>>> &) const': cannot convert argument 1 from 'std::pair<const _Kty,_Ty>' to 'std::pair<int,std::vector<char,std::allocator<char>>> &'
Short answer:
Add const before int in first lambda's parameter:
[&](std::pair<const int, std::vector<char>>& aPair)->bool
Long answer:
According to the std::map reference map<K, V>::iterator is an iterator to a map<K, V>::value_type, and map<K, V>::value_type is pair<const K, V> (is your case is pair<const int, vector<char>>).
The problem is that you try to bind pair<int, vector<char>> & reference to the values of type pair<const int, vector<char>>. If you could do so, you would be able to mutate the keys in a map, completely destroying map's internal structure. So you are not allowed to mutate them, and it is denoted as const in pair<const int, vector<char>>.
You haven't declared the parameter correctly for your lambda. It should be
[&](std::pair<const int, std::vector<char>>& aPair)
Note the const int as the first type of the pair. The value type of a map (and what you get when you dereference a map iterator) has the first member of the pair constant, since changing the key value once it is the map can potentially break the sorting in the tree structure used to hold the map.
One way to avoid problems like this is to use
[&](LookupMapType::value_type &aPair)
(where 'LookupMapType' is the type of lookupmap).
If your compiler supports C++14 or later (and you enable it, if needed), you can simplify that some more to
[&](auto &aPair)
I am trying to implement the solution to the problem found at Link.
Here is my snippet of code
bool compareVec(vector<int> a, vector<int> b) {
return std::equal(a.begin(), a.end(), b.begin());
}
vector<vector<int> > ans;
ans.erase(std::remove_if(ans.begin(), ans.end(), compareVec), ans.end());
I am getting the following errors
/usr/include/c++/4.8/bits/stl_algo.h: In instantiation of
'_RandomAccessIterator std::__find_if(_RandomAccessIterator,
_RandomAccessIterator, _Predicate, std::random_access_iterator_tag) [with
_RandomAccessIterator = __gnu_cxx::__normal_iterator<std::vector<int>*,
std::vector<std::vector<int> > >; _Predicate = bool (*)(std::vector<int>,
std::vector<int>)]':
/usr/include/c++/4.8/bits/stl_algo.h:4465:41: required from '_IIter
std::find_if(_IIter, _IIter, _Predicate) [with _IIter =
__gnu_cxx::__normal_iterator<std::vector<int>*, std::vector<std::vector<int>
> >; _Predicate = bool (*)(std::vector<int>, std::vector<int>)]'
/usr/include/c++/4.8/bits/stl_algo.h:1144:64: required from '_FIter
std::remove_if(_FIter, _FIter, _Predicate) [with _FIter =
__gnu_cxx::__normal_iterator<std::vector<int>*, std::vector<std::vector<int>
> >; _Predicate = bool (*)(std::vector<int>, std::vector<int>)]'
solution.cpp:40:64: required from here
/usr/include/c++/4.8/bits/stl_algo.h:214:23: error: too few arguments to
function
if (__pred(*__first))
^
/usr/include/c++/4.8/bits/stl_algo.h:218:23: error: too few arguments to
function
if (__pred(*__first))
^
/usr/include/c++/4.8/bits/stl_algo.h:222:23: error: too few arguments to
function
if (__pred(*__first))
^
Can anyone help me out in debugging this?
Thanks in advance
EDIT
The elements of vector are sorted and all these vectors are also sorted.
Unique also gives an error. I am unable to figure out why?
Why is the example given in the link I provided, not helpful here?
std::remove_if requires a unary predicate. You pass a binary predicate, which causes your errors (/usr/include/c++/4.8/bits/stl_algo.h:222:23: error: too few arguments to function → your function takes two arguments, not one).
Further, std::remove_if does its removals with no consideration of other elements (which is why it accepts a unary predicate), so it isn't actually what you're looking for.
What you want to use is std::unique, which does require the compareVec you've implemented. However, std::vector already provides the operator== overload, so that implementation is actually redundant! Also, you say that you get an error when using std::unique. Try passing your parameters as const&.
Thus, when your outer vector and inner vectors are already sorted, the solution is as it'd be for any other vector of sorted elements:
outer.erase(std::unique(outer.begin(), outer.end()), outer.end());
Okay, since this is not marked with C++11, I will use a functor instead of a lambda.
The first problem you have is that remove_if takes a UnaryPredicate, which means it should only accept a single argument.
The second issue is also related to your understanding of remove_if. After you fix compareVec to only accept one argument, you're left wondering how you could possibly compare all elements against each other.
You could approach this one of two ways:
Sort your vector of vectors (< operator is defined lexicographically for vector) and then use std::unique (Examples) (More examples).
In the link you provided (same as the one I just linked to), notice that they sort first, and you do not.
Or, if there's no clear definition of < for your elements, only ==, you could perform an O(N2) lookup/erase on each subsequent item (shown below):
Comparison functor (could make as a lambda in C++11 and greater)
struct CompareVec
{
CompareVec(const std::vector<int>& _in) : compare_against(_in){}
bool operator()(const std::vector<int>& rhs) const
{
return compare_against == rhs;
};
const std::vector<int>& compare_against;
};
To be used like so:
for (size_t i = 0; i < ans.size(); ++i)
{
CompareVec comparator(ans[i]);
ans.erase(std::remove_if(ans.begin()+i+1, ans.end(), comparator), ans.end());
}
Live Demo (Compiled in C++11 for want of initializing test vectors with initializer lists)
Edit
In C++11 we can get rid of the CompareVec functor and replace it with a lambda:
for (size_t i = 0; i < ans.size(); ++i)
{
ans.erase(std::remove_if(ans.begin()+i+1, ans.end(),
[&ans, &i](const std::vector<int>& _rhs)
{
return ans[i] == _rhs;
}) , ans.end());
}
Demo2
I have a map defined like this
std::map<int,int> myMap;
After processing this map I want to treat it as a heap (based on the second value). I decided to use std::make_heap function.. which is defined like this...
template< class RandomIt, class Compare > void make_heap( RandomIt first, RandomIt last, Compare comp );
As this function requires a comparison function to be defined... I did it like this
bool compare(const std::pair<int,int> &frst, const std::pair<int,int> &scnd)
Now with this setup I call make_heap like this
std::make_heap(myMap.begin(), myMap.end(),compare);
But this gives me compilation error...
/usr/lib/gcc/i386-redhat-linux/4.1.2/../../../../include/c++/4.1.2/bits/stl_heap.h: In function ‘void std::make_heap(_RandomAccessIterator, _RandomAccessIterator) [with _RandomAccessIterator = std::_Rb_tree_iterator<std::pair<const int, int> >]’:
maxRepeatingNumber.cc:48: instantiated from here /usr/lib/gcc/i386-redhat-linux/4.1.2/../../../../include/c++/4.1.2/bits/stl_heap.h:357: error: no match for ‘operator-’ in ‘__last - __first’
/usr/lib/gcc/i386-redhat-linux/4.1.2/../../../../include e/c++/4.1.2/bits/stl_bvector.h:182: note: candidates are: ptrdiff_t std::operator-(const std::_Bit_iterator_base&, const std::_Bit_iterator_base&)
/usr/lib/gcc/i386-redhat-linux/4.1.2/../../../../include/ c++/4.1.2/bits/stl_heap.h:360: error: no match for ‘operator-’ in ‘__last - __first’
/usr/lib/gcc/i386-redhat-linux/4.1.2/../../../../include/c++/4.1.2/bits/stl_bvector.h:182: note: candidates are: ptrdiff_t std::operator-(const std::_Bit_iterator_base&, const std::_Bit_iterator_base&)
/usr/lib/gcc/i386-redhat-linux/4.1.2/../../../../include/c++/4.1.2/bits/stl_heap.h:364: error: no match for ‘operator+’ in ‘__first + __parent’
/usr/lib/gcc/i386-redhat-linux/4.1.2/../../../../include/c++/4.1.2/bits/stl_bvector.h:267: note: candidates are: std::_Bit_iterator std::operator+(ptrdiff_t, const std::_Bit_iterator&)
Compilation error gives me a hint that they may be because of make_heap requires random_access_iterator... but I am not sure on that.
Should I move to Function Objects (from plain function pointer)?
Any help?
You cannot make a heap directly on a map. Map is sorted already by a key and you need a different partial sorting. You can copy all map values to a vector and make a heap from it.
Edit:
If you need to modify your map and maintain the heap, you can implement something like multi-index container when one of indexes would be actually heap-powered.
Agreed with #Andy. Map is already sorted by key so you can't make heap directly on it. To solve similar problem i created a vector of pair with map value as first element and key as second element and then make heap. It won't require any compactor parameter for max heap.
For example: For map "map m" create vector using below code and then make heap.
for(it=m.begin(); it != m.end(); it++)
v.push_back(make_pair(it->second,it->first));
make_heap(v.begin(),v.end(),sort_v());
This will work and top element would be returned at any point of time.
I have a nested set of ints but I cannot insert elements into the nested sets.
std::set<std::set<int> > centre_as_set = bitset_to_set(centre->second->bit_partitions);
std::set<std::set<int> >::iterator set_itr;
for ( set_itr = centre_as_set.begin(); set_itr != centre_as_set.end(); ++set_itr ) {
set_itr->insert(4);
std::set<int>::iterator node_itr;
for ( node_itr = set_itr->begin(); node_itr != set_itr->end(); ++node_itr ) {
std::cout << *node_itr;
}
}
}
The error is
Partition_standalone.cpp:612: error:
passing ‘const std::set, std::allocator >’
as ‘this’ argument of
‘std::pair, _Compare,
typename
_Alloc::rebind<_Key>::other>::const_iterator,
bool> std::set<_Key, _Compare,
_Alloc>::insert(const _Key&) [with _Key = int, _Compare = std::less, _Alloc =
std::allocator]’ discards
qualifiers
I can't quite decipher that template error, any help appreciated.
The elements in a set are not mutable and you are trying to use the non-const member function insert() on a const instance of std::set<int>. There is the following nice comment if you follow the iterator symbol to its declaration in stl_set.h:
// _GLIBCXX_RESOLVE_LIB_DEFECTS
// DR 103. set::iterator is required to be modifiable,
// but this allows modification of keys.
typedef typename _Rep_type::const_iterator iterator;
C++98 and C++03 allowed modification, but this is a defect and already fixed in non-ancient GCC versions and VC10. The mentioned defect report can be found here and will be incorporated into the next standard.
Use e.g. something like the following instead to add the value 4:
// Readability:
typedef std::set<int> IntSet;
typedef std::set<IntSet> IntSetSet;
// Helper:
IntSetSet add_value_to_sets(const IntSetSet& in, int i) {
IntSetSet ss;
IntSetSet::iterator set_itr;
for ( set_itr = in.begin(); set_itr != in.end(); ++set_itr ) {
IntSet s = *set_itr;
s.insert(4);
ss.insert(s);
}
return ss;
}
// ...
IntSetSet centre_as_set =
add_value_to_sets(bitset_to_set(centre->second->bit_partitions), 4);
Edit: This answer is wrong as per the comment of georg.
I dont have a compiler here, but the full declaration of std::set is:
template < class Key, class Compare = less<Key>,
class Allocator = allocator<Key> > class set;
The "Key" of the outermost set is "std::set". The Comparator is "std::less>", or short "operator<(set, set)" which is undefined. The compiler warns about this only on the first use/instantiation of the comparator.
I dont think there is a useful ordering/comparator for std::set's. You are better off using std::vector which doesnt order the elements and doesnt need a comparator.
Oh, and it is not allowed to change (at runtime) the set keys if this would affect the ordering. But that would be a runtime error, not a compile error.