In my program, set has elements of type pair<char, double>. I also implemented the logic so that set is sorted based on element's 2nd value, from smallest to largest:
using pair_item = std::pair<char, double>;
std::set<pair_item, decltype([](auto e1, auto e2){return e1.second < e2.second;})> pq;
Now, I want to delete an element from set, based on element's 1st value:
auto first_is_w = std::lower_bound(
pq.begin(), pq.end(), [w](const auto& p) {
return p.first == w;
}
);
if (first_is_w != pq.end() && first_is_w->first == w) {
pq.erase(first_is_w);
}
Unfortunately, I got error:
'const A_star(const std::vector<std::tuple<char, char, double> >&, std::unordered_map<char, double>&, char, char)::<lambda(const auto:13&)>' is not derived from 'const std::optional<_Tp>'
{ return *__it < __val; }
~~~~~~^~~~~~~
I'm wondering how should I modify my lambda function to run the search correctly?
Full codes attached below:
#include <iostream>
#include <set>
#include <utility>
using pair_item = std::pair<char, double>;
void printSet(const auto& pq) {
std::cout << "Current pq:" << std::endl;
for (const auto& ele : pq) {
std::cout << "(" << ele.first << ", " << ele.second << "), ";
}
std::cout << std::endl;
}
int main() {
char w = 'A';
std::set<pair_item, decltype([](auto e1, auto e2){return e1.second < e2.second;})> pq;
pq.emplace('A', 30);
pq.emplace('B', 20);
pq.emplace('C', 10);
printSet(pq);
auto first_is_w = std::lower_bound(
pq.begin(), pq.end(), [w](const auto& p) {
return p.first == w;
}
);
if (first_is_w != pq.end() && first_is_w->first == w) {
pq.erase(first_is_w);
}
return 0;
}
Your lambda is fine, but you're using the wrong algorithm. lower_bound requires a sorted range and strict weak ordering comparison, which you do not have for the value you're looking for.
You should use std::find_if, which is an O(N) linear search.
auto first_is_w = std::find_if(
pq.begin(), pq.end(), [w](const auto& p) {
return p.first == w;
}
);
if (first_is_w != pq.end()) {
pq.erase(first_is_w);
}
Related
I am trying to solve a question on leetcode which is finding the top k frequent elements. I think my code is correct but the output for a test case is failing.
Input: [ 4,1,-1,2,-1,2,3]
K=2
My answer comes out to be {1,-1} but the expected is {-1,2}. I am not sure where am i getting wrong.
struct myComp{
constexpr bool operator()(pair<int,int> & a,pair<int,int> &b)
const noexcept
{
if(a.second==b.second)
{
return a.first<b.first;
}
return a.second<b.second;
}
};
class Solution {
public:
vector<int> topKFrequent(vector<int>& nums, int k) {
unordered_map<int,int> mp;
for(int i=0;i<nums.size();i++)
{
mp[nums[i]]++;
}
priority_queue<pair<int,int>,vector<pair<int,int>>,myComp> minheap;
for(auto x:mp)
{
minheap.push(make_pair(x.second,x.first));
if(minheap.size()>k)
{
minheap.pop();
}
}
vector<int> x;
while(minheap.size()>0)
{
x.push_back(minheap.top().second);
minheap.pop();
}
return x;
link: https://leetcode.com/problems/top-k-frequent-elements
In the minheap, pairs of <frequency, element> are being pushed. Since we want to sort these pairs on basis of frequency, we need to compare on the basis of frequency only.
Let's say there are two pairs a and b. Then for normal sorting, the comparison would be :
a.first < b.first;
And for reverse sorting, the comparison would be :
a.first > b.first;
In case of min-heap, we need reverse sorting. Hence, the following comparator makes your code pass all the test cases :
struct myComp
{
constexpr bool operator()(pair<int,int> & a,pair<int,int> &b)
const noexcept
{
return a.first > b.first;
}
};
There are several issues with your code.
Obviously there is somewhere using namespace std; in your code. This should be avoided. You will find many posts here on SO explaining, why it this should not be done.
Then we need to qualify all elements from the std library with std::, which makes the scope very clear.
Next: You do not need your own sorting function. Since you insert the elements from the pair in swapped order into the std::priority_queue, the sorting criteria is valid for the counter part, not for the key value. So, your sorting function was anyway wrong, because it was sorting accodring to "second" and not to "first". But if we have a standard sorting, we do not need a special sorting algorithm. A std::pair has a less-than operator. So, the definition can be simply:
std::priority_queue<std::pair<int, int>> minheap;
Then, your if statement
if(minheap.size()>k)
{
minheap.pop();
}
is wrong. You will allow only k values to be inserted. And this are not necessarily the biggest ones. So, you need to insert all values from the std::unordered map. And then they are sorted.
With some cosmetic changes the code will look like the below:
#include <iostream>
#include <utility>
#include <unordered_map>
#include <vector>
#include <queue>
std::vector<int> topKFrequent(std::vector<int>& nums, size_t k) {
std::unordered_map<int, int> mp;
for (size_t i = 0; i < nums.size(); i++)
{
mp[nums[i]]++;
}
std::priority_queue<std::pair<int, int>> minheap;
for (auto x : mp)
{
minheap.push(std::make_pair(x.second, x.first));
}
std::vector<int> x;
for (size_t i{}; i< k; ++i)
{
x.push_back(minheap.top().second);
minheap.pop();
}
return x;
}
int main() {
std::vector data{ 4,1,-1,2,-1,2,3 };
std::vector result = topKFrequent(data, 2);
for (const int i : result) std::cout << i << ' '; std::cout << '\n';
return 0;
}
An additional solution
#include <iostream>
#include <vector>
#include <algorithm>
#include <unordered_map>
#include <utility>
auto topKFrequent(std::vector<int>& nums, size_t k) {
// Count occurences
std::unordered_map<int, size_t> counter{};
for (const int& i : nums) counter[i]++;
// For storing the top k
std::vector<std::pair<int, size_t>> top(k);
// Get top k
std::partial_sort_copy(counter.begin(), counter.end(), top.begin(), top.end(),
[](const std::pair<int, size_t >& p1, const std::pair<int, size_t>& p2) { return p1.second > p2.second; });
return top;
}
// Test code
int main() {
std::vector data{ 4,1,-1,2,-1,2,3 };
for (const auto& p : topKFrequent(data, 2))
std::cout << "Value: " << p.first << " \t Count: " << p.second << '\n';
return 0;
}
And of course, we do have also the universal solution for any kind of iterable container. Including the definition for type traits using SFINAE and checking for the correct template parameter.
#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 std::pair<int, size_t >& p1, const std::pair<int, size_t>& 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";
return 0;
}
Developed and tested with Microsoft Visual Studio Community 2019, Version 16.8.2.
Additionally compiled and tested with clang11.0 and gcc10.2
Language: C++17
I want to find the lower_bound for my target in a map(in a range).
I have known another solution:
int main() {
map<int,int> m;
auto it=m.lower_bound(10);
cout<<it->first<<" "<<it->second<<endl;
return 0;
}
BUT, I want to how to use std::lower_bound(m.begin(),m.end(),***).
int main() {
map<int,int> m;
auto it=std::lower_bound(m.begin(),m.end(),10);
cout<<it->first<<" "<<it->second<<endl;
return 0;
}
main.cpp:29:43: required from here
/usr/local/Cellar/gcc/7.3.0_1/include/c++/7.3.0/bits/predefined_ops.h:65:22: error: no match for 'operator<' (operand types are 'std::pair' and 'const int')
{ return *__it < __val; }
The value_type of a map is std::pair<const Key,Value>, so you'll need to supply such a pair as argument.
Given that you are interested only in the key part, it's better to use the overload of std::lower_bound() that accepts a function object:
auto const it = std::lower_bound(m.begin(), m.end(), std::make_pair(10, 0),
[](auto const& a, auto const& b){ return a.first < b.first; });
I believe, from reading the docs, but haven't confirmed, that we can use the map's comparer:
auto const it = std::lower_bound(m.begin(), m.end(), std::make_pair(10, 0),
m.value_comp());
It seems you mean the following
#include <iostream>
#include <map>
#include <iterator>
#include <algorithm>
int main()
{
std::map<int, int> m =
{
{ 2, 1 }, { 4, 2 }, { 6, 3 }, { 8, 4 }, { 10, -1 }, { 10, 0 }, { 12, 2 }
};
int key = 10;
auto it = m.lower_bound( key );
std::cout << "{ " << it->first << ", " << it->second << " }\n";
it = std::lower_bound( std::begin( m ), std::end( m ), key,
[&]( const auto &p, const auto &value ) { return p.first < value; } );
std::cout << "{ " << it->first << ", " << it->second << " }\n";
return 0;
}
The program output is
{ 10, -1 }
{ 10, -1 }
That is in the standard algorithm std::lower_bound you can use a lambda expression.
I want to check whether an element exists in the vector or not. I know the below piece of code will check it.
#include <algorithm>
if ( std::find(vector.begin(), vector.end(), item) != vector.end() )
std::cout << "found";
else
std::cout << "not found";
But I have the vector of any type. i.e. std::vector<std::any>
I am pushing elements into vector like this.
std::vector<std::any> temp;
temp.emplace_back(std::string("A"));
temp.emplace_back(10);
temp.emplace_back(3.14f);
So I need to find whether string "A" present in the vector or not. Can std::find help here?
As of now I am using below piece of code to do this
bool isItemPresentInAnyVector(std::vector<std::any> items, std::any item)
{
for (const auto& it : items)
{
if (it.type() == typeid(std::string) && item.type() == typeid(std::string))
{
std::string strVecItem = std::any_cast<std::string>(it);
std::string strItem = std::any_cast<std::string>(item);
if (strVecItem.compare(strItem) == 0)
return true;
}
else if (it.type() == typeid(int) && item.type() == typeid(int))
{
int iVecItem = std::any_cast<int>(it);
int iItem = std::any_cast<int>(item);
if (iVecItem == iItem)
return true;
}
else if (it.type() == typeid(float) && item.type() == typeid(float))
{
float fVecItem = std::any_cast<float>(it);
float fItem = std::any_cast<float>(item);
if (fVecItem == fItem)
return true;
}
}
return false;
}
This should work good I guess:
#include <vector>
#include <string>
#include <any>
#include <algorithm>
#include <iostream>
int main(){
std::vector<std::any> temp;
temp.emplace_back(std::string("A"));
temp.emplace_back(10);
temp.emplace_back(3.14f);
int i = 10;//you can use any type for i variable and it should work fine
//std::string i = "A";
auto found = std::find_if(temp.begin(), temp.end(), [i](const auto &a){
return typeid(i) == a.type() && std::any_cast<decltype(i)>(a) == i;
} );
std::cout << std::any_cast<decltype(i)>(*found);
}
Or to make the code a bit more generic and reusable:
#include <vector>
#include <string>
#include <any>
#include <algorithm>
#include <iostream>
auto any_compare = [](const auto &i){
return [i] (const auto &val){
return typeid(i) == val.type() && std::any_cast<decltype(i)>(val) == i;
};
};
int main(){
std::vector<std::any> temp;
temp.emplace_back(std::string("A"));
temp.emplace_back(10);
temp.emplace_back(3.14f);
//int i = 10;
std::string i = "A";
auto found = std::find_if(temp.begin(), temp.end(), any_compare(i));
std::cout << std::any_cast<decltype(i)>(*found);
}
Live demo
Important note: this is guaranteed to work only within single translation unit due to stadard requirements on std::any type (for example same types don't need to have same type identifier in different translation units)
Using an any for this kind of purpose is not a good use of any. The best way to go is just to use a variant - since you have a closed set of types:
struct Equals {
template <typename T>
constexpr bool operator()(T const& a, T const& b) const { return a == b; }
template <typename T, typename U>
constexpr bool operator()(T const& a, U const& b) const { return false; }
};
using V = std::variant<int, float, std::string>
bool isItemPresentInAnyVector(std::vector<V> const& items, V const& item)
{
auto it = std::find_if(items.begin(), items.end(), [&](V const& elem){
return std::visit(Equals{}, elem, item);
});
return it != items.end();
}
Actually it's even better, because as Kilian points out, variant's operator== already works exactly like this:
using V = std::variant<int, float, std::string>
bool isItemPresentInAnyVector(std::vector<V> const& items, V const& item)
{
return std::find(items.begin(), items.end(), item) != items.end();
}
Unfortunately if you want to find an std::any instance in a vector of std::any instances the answer is no.
std::any does need some "magic" for example to be able to handle the creation of unknown object types but this machinery is private and must only supports object creation and not equality comparison.
It would be possible to implement what you are looking for using the same approach, but not with standard std::any that doesn't publish the needed details. The "manager" template needs to enumerate all possible operations and, for example, in g++ implementation they're "access", "get_type_info", "clone", "destroy", "xfer".
variant is completely different, because explicitly lists all the allowed types and therefore in any place it's used can access all the methods.
Comparison with typeId() should be avoided since it's dependent from translation unit.
A much safer approach can be used with any_cast of pointers:
template<typename T>
std::optional<T> find(const std::vector<std::any>& v)
{
for(auto&& e : v){
if(auto ptr = std::any_cast<T>(&e)){
return *ptr;
}
}
return std::nullopt;
}
Find first element with the given type, or nullopt if it's not found.
If we want to find all element with a specific instead:
template<typename T>
std::vector<T> findAll(const std::vector<std::any>& v)
{
std::vector<T> out;
for(auto&& e : v){
if(auto ptr = std::any_cast<T>(&e)){
out.push_back(*ptr);
}
}
return out;
}
Usage:
int main()
{
std::vector<std::any> temp;
temp.emplace_back(std::string("A"));
temp.emplace_back(10);
temp.emplace_back(3.14f);
temp.emplace_back(12);
temp.emplace_back(std::string("B"));
auto outInt = findAll<int>(temp);
std::cout << "out int: " << outInt.size() << std::endl;
for(auto&& out : outInt)
std::cout << out << std::endl;
auto outString = findAll<std::string>(temp);
std::cout << "out string: " << outString.size() << std::endl;
for(auto&& out : outString)
std::cout << out << std::endl;
auto singleInt = find<int>(temp);
if(singleInt)
std::cout << "first int " << *singleInt << std::endl;
auto singleBool = find<bool>(temp);
if(!singleBool)
std::cout << "ok: bool not found" << std::endl;
}
LIVE DEMO
If the types are int, float and string (or a limited set of types), you can use a combination of std::variant and std::get_if to achieve what you want to do in a simple manner:
std::get_if is to determine which of the types is stored in the std::variant.
A minimal example:
#include <iostream>
#include <vector>
#include <string>
#include <variant>
int main(){
std::vector<std::variant<int, float, std::string>> temp;
temp.emplace_back(std::string("A"));
temp.emplace_back(10);
temp.emplace_back(3.14f);
for (const auto& var: temp) {
if(std::get_if<std::string>(&var)) {
if(std::get<std::string>(var) == "A") std::cout << "found string\n";
}
if(std::get_if<int>(&var)) {
if(std::get<int>(var) == 10) std::cout << "found int\n";
}
if(std::get_if<float>(&var)) {
if(std::get<float>(var) == 3.14f) std::cout << "found float\n";
}
}
}
Live Demo
I have two std::map<int,int> maps and wish to merge them into a third map like this:
if the same key is found in both maps, create a pair in the third map with the same key and a value which a sum of values from the first and second map, otherwise just copy a pair to the third map.
I suspect it can be done with std::accumulate, but I don't understand it well enough.
Here is an example how to do the task with using std::accumulate
#include <iostream>
#include <map>
#include <numeric>
int main()
{
std::map<int, int> m1 = { { 1, 1 }, { 2, 2 }, { 3, 3 }, { 4, 4 } };
std::map<int, int> m2 = { { 2, 5 }, { 3, 1 }, { 5, 5 } };
for ( const auto &p : m1 )
{
std::cout << "{ " << p.first << ", " << p.second << " } ";
}
std::cout << std::endl;
for ( const auto &p : m2 )
{
std::cout << "{ " << p.first << ", " << p.second << " } ";
}
std::cout << std::endl;
std::map<int, int> m3 = std::accumulate( m1.begin(), m1.end(), std::map<int, int>(),
[]( std::map<int, int> &m, const std::pair<const int, int> &p )
{
return ( m[p.first] +=p.second, m );
} );
m3 = std::accumulate( m2.begin(), m2.end(), m3,
[]( std::map<int, int> &m, const std::pair<const int, int> &p )
{
return ( m[p.first] +=p.second, m );
} );
for ( const auto &p : m3 )
{
std::cout << "{ " << p.first << ", " << p.second << " } ";
}
std::cout << std::endl;
return 0;
}
The output is
{ 1, 1 } { 2, 2 } { 3, 3 } { 4, 4 }
{ 2, 5 } { 3, 1 } { 5, 5 }
{ 1, 1 } { 2, 7 } { 3, 4 } { 4, 4 } { 5, 5 }
In fact only for the second map there is a need to use std::accumulate. The first map can be simply copied or assigned to m3.
For example
std::map<int, int> m3 = m1;
m3 = std::accumulate( m2.begin(), m2.end(), m3,
[]( std::map<int, int> &m, const std::pair<const int, int> &p )
{
return ( m[p.first] +=p.second, m );
} );
An overly generic solution inspired by std::set_union. Unlike the first suggested answer, this should run in O(n) instead of O(n log n).
Edit: it's still O(n log n) because of insertions into the final map.
#include <map>
#include <iostream>
#include <iterator>
#include <algorithm>
template<class InputIterT1, class InputIterT2, class OutputIterT, class Comparator, class Func>
OutputIterT merge_apply(
InputIterT1 first1, InputIterT1 last1,
InputIterT2 first2, InputIterT2 last2,
OutputIterT result, Comparator comp, Func func) {
while (true)
{
if (first1 == last1) return std::copy(first2, last2, result);
if (first2 == last2) return std::copy(first1, last1, result);
if (comp(*first1, *first2) < 0) {
*result = *first1;
++first1;
} else if (comp(*first1, *first2) > 0) {
*result = *first2;
++first2;
} else {
*result = func(*first1, *first2);
++first1;
++first2;
}
++result;
}
}
template<class T>
int compare_first(T a, T b) {
return a.first - b.first;
}
template<class T>
T sum_pairs(T a, T b) {
return std::make_pair(a.first, a.second + b.second);
}
using namespace std;
int main(int argc, char **argv) {
map<int,int> a,b,c;
a[1] = 10;
a[2] = 11;
b[2] = 100;
b[3] = 101;
merge_apply(a.begin(), a.end(), b.begin(), b.end(), inserter(c, c.begin()),
compare_first<pair<int, int> >, sum_pairs<pair<int, int> >);
for (auto item : c)
cout << item.first << " " << item.second << endl;
}
I don't think it will be easy (if not impossible) to find a suitable std::algorithm that serves the purpose.
The easiest way would be to first make a copy of map1 to map_result.
Then iterate through map2 and see if any key already exists in map_result then add the values, else add the key_value pair to map_result.
std::map<int,int> map_result( map1 );
for (auto it=map2.begin(); it!=map2.end(); ++it) {
if ( map_result[it->first] )
map_result[it->first] += it->second;
else
map_result[it->first] = it->second;
}
I'm trying to solve a issue where I'm inserting chars in to a map of type <char, int>. If the char already exists in the map I will increase the int by 1. I have created my own comparator for prioritizing the elements within the map. The priority doesn't work in the way I hope it would work since in the end the output doesn't follow the order.
#include <iostream>
#include <string>
#include <map>
#include <iterator>
using namespace std;
struct classcomp {
bool operator()(const int& a, const int& b) const {
return a < b;
}
};
bool isPresent(map<char,int,classcomp> mymap, char c){
return (mymap.find('b') != mymap.end());
}
int main(){
string input="dadbadddddddcabca";
map<char,int,classcomp> mymap;
char temp;
for(string::iterator it = input.begin(); it!=input.end(); ++it){
temp = *it;
if(!isPresent(mymap, temp))
mymap.insert(pair<char,int>(*it,1));
else
mymap[temp]++;
}
for (auto& x: mymap) {
cout << x.first << ": " << x.second << '\n';
}
return 0;
}
Gives the following output:
a: 4
b: 2
c: 2
d: 8
std::map is designed to be sorted by key, and providing comparator for type of value does not change anything. imagine you have std::map<char,char>, how would you think you can provide comparator for value (if it would be possible)?
So solution would be to use container that allows to sort by multiple keys like boost::multi_index or just create another map - reversed:
#include <iostream>
#include <string>
#include <map>
#include <iterator>
using namespace std;
int main(){
string input="dadbadddddddcabca";
map<char,int> mymap;
for(string::iterator it = input.begin(); it!=input.end(); ++it){
mymap[*it]++;
}
map<int,char> reversemap;
for (auto& x: mymap) {
reversemap.insert( make_pair( x.second, x.first ) );
}
for (auto& x: reversemap ) {
cout << x.first << ": " << x.second << '\n';
}
return 0;
}
Notice that your pre-check for element existance is completely redundant, std::map operator[] creates new element and initializes it, if it does not exists.
You may notice that in output you are missing some values now (though they are sorted), if that is not what you need, change reversemap type from map to multimap, which allows key duplicates.
The comparator is used to sort the chars and not the ints.
It is sorting the keys and seems to work just fine - a b c d.
map sorts its entries by key, not value. The char keys get silently cast to int in your classcomp::operator()
Why
mymap.find('b') != mymap.end());
and not
mymap.find(c) != mymap.end());
Maybe this is what you wanted
int main() {
std::string input="dadbadddddddcabca";
typedef std::map< char, int > map_t;
map_t mymap;
char temp;
for ( std::string::const_iterator it = input.begin(), e = input.end(); it != e; ++it ) {
temp = *it;
mymap[ temp ] = mymap[ temp ] + 1; // Hopufuly operator[] inserts zero initialized value, if can't find a key
}
typedef std::pair< typename map_t::key_type, typename map_t::mapped_type > pair_t;
std::vector< pair_t > sortedByValue;
sortedByValue.assign( mymap.begin(), mymap.end() );
std::sort( sortedByValue.begin(), sortedByValue.end(), []( const pair_t & left, const pair_t & right ) {
return left.second < right.second;
// change to
// return left.second > right.second;
// for descend order
} );
for ( const auto & x: sortedByValue ) {
std::cout << x.first << ": " << x.second << std::endl;
}
}
LWS link