looping over set inside map in cpp - c++

I am getting error in for loop ,compiler saying that 's' must have a pointer type (in s->second.begin()).I just want to iterate over set below.
vector<vector<int>> verticalTraversal(TreeNode* root) {
map<int, map<int, set<int>>> mep;
solve(root, 0, 0, mep);
vector<vector<int>> result;
for (auto p : mep) {
vector<int> temp;
map<int,set<int>> s = p.second;
for (auto ity = s->second.begin(); ity != s->second.end(); ity++) {
//getting error here in s->second.begin()
}
//reverse(temp.begin(), temp.end());
result.push_back(temp);
}
return result;
}

So here's some code that iterates through each set (and prints out all the integers).
vector<vector<int>> verticalTraversal() {
map<int, map<int, set<int>>> mep;
solve(root, 0, 0, mep);
vector<vector<int>> result;
for (map<int, map<int, set<int>>>::iterator i = mep.begin(); i != mep.end(); ++i) {
for (map<int, set<int>>::iterator j = i->second.begin(); j != i->second.end(); ++j) {
for (set<int>::iterator k = j->second.begin(); k != j->second.end(); ++k) {
cout << *k << '\n';
}
}
}
return result;
}
First thing you should notice is that there are three loops not two, since you have a set inside a map inside a map you have three levels to iterate though (not two as in your code).
Second thing is I removed all auto and all range based loops and been completely explicit about the types involved. Hopefully that makes the code easier to understand.
Once you've understood it you can put the auto back in if you like, or even replace the loops with range based loops.

The best thing to do is to write a small program, and then get an idea/experiment with the smaller program to understand the basic concepts.
Here is an example:
#include <map>
#include <set>
#include <iostream>
int main()
{
std::map<int, std::map<int, std::set<int>>> mep;
mep.insert({0, {{0, {0,1,2,3}}}}); // populate the map
mep.insert({1, {{1, {1,2,3,4,5}}}}); // populate the map
// traverse each set in the mep map
for (auto p : mep)
{
std::map<int, std::set<int>> s = p.second;
for (auto ity = s.begin(); ity != s.end(); ity++)
{
std::set<int>& theSet = ity->second;
for (auto& setV : theSet )
std::cout << setV << " ";
std::cout << "\n";
}
}
}
Output:
0 1 2 3
1 2 3 4 5
Also note that you really should be using references to the data within the map instead of copying them by value. Things like this:
for (auto p : mep)
and
std::map<int, std::set<int>> s = p.second;
incurs a copy. Rather, you should do this:
for (auto& p : mep)
...
std::map<int, std::set<int>>& s = p.second;

Related

C++ Loop through first K elements of unordered_map

I have an unordered_map that stores counts of integers. I want to loop through the map, but instead of fetching all the entries, I only wish to get the first K.It is guaranteed that map has more than K entries.
I'm running into issues when I do the following:
unordered_map<int, int> u_map;
// Logic to populate the map
for(auto it=u_map.begin(); it!=u_map.begin()+2; it++)
cout<<it->first<<" "<<it->second<<endl;
The expression u_map.begin()+2 is causing the issue.
So is it possible to get only the first K entries of a map using for_each loop in C++?
If you can use C++20, then views::take would be a choice.
#include <unordered_map>
#include <ranges>
#include <iostream>
int main() {
std::unordered_map<int, int> u_map;
for (auto [key, value] : u_map | std::views::take(2))
std::cout << key << " " << value << "\n";
}
Alternative for pre-C++20, using std::next:
std::unordered_map<int, int> u_map;
auto end = std::next(u_map.begin(), 2);
for (auto it = u_map.begin(); it != end; ++it)
std::cout << it->first << " " << it->second << "\n";
I only wish to get the first K
Note from std::unordered_map documentation
an unordered_map object makes no guarantees on which specific element is considered its first element.
This essentially means that there is no guarantee that you will iterate over the elements in the inserted order.
For iterating over the elements of the map you can use:
int count = 0;
for (auto& it: u_map) {
/* some code here like you can keep a count variable that will check if it
reaches the number K and then break the loop. But remember that it is
**not** guaranteed that the elements you will get will be in inserted order.*/
if(count < K)
{
cout<<it.first<<" "<<it.second<<endl;
}
else
{
break;
}
++count;
}
Working example
#include <iostream>
#include <unordered_map>
using namespace std;
int main()
{
std::unordered_map<std::string, std::string> u_map = {
{"RED","#FF0000"},
{"GREEN","#00FF00"},
{"BLUE","#0000FF"},{"PURPLE","#0F00FF"},{"WHITE","#0000RF"},{"ORANGE","#F000FF"}
};
int K = 3;
int count = 0;
for (auto& it: u_map)
{
if(count < K)
{
cout<<it.first<<" "<<it.second<<endl;
}
else
{
break;
}
++count;
}
return 0;
}

Need to iterate over entire object except for first two elements. Is there a design pattern?

I have a std::vector that I would like to iterate over each object except the first two. A foreach loop would be perfect if I didn't want two . i.e. for(const auto i : items)
Possible solutions I've thought of are erasing the first two and re-adding at the end
const auto firstEle = myVec[0];
const auto secEle = myVec[1];
myVec.erase(myVec.begin());
myVec.erase(myVec.begin());
for(const auto i : items)
{
//do stuff with i
}
myVec.insert(myVec.begin(), secEle);
myVec.insert(myVec.begin(), firstEle);
or have some sort of flag
unsigned int i = 0;
for(const auto j : items)
{
if(i < 2)
{
i++;
continue;
}
//do stuff with j
}
or use a while loop
unsigned int i = 2;
while(i < myVec.size())
{
const auto j = myVec[i];
//do stuff with j
i++;
}
All these seem more complicated than they need to be. Any better solutions that are simpler?
I usually go with a conventional loop for these things:
// verify myVec.size() > 2
for(auto it = myVec.begin()+2; it != myVec.end(); ++it) {
// work
}
If you want C++11 lambda magic, then
std::for_each(v.begin()+2, v.end(), [](auto& element) {
// do stuff
});
will do it.
In C++20, you can use std::views::drop. Taken directly from the example at cppreference.com:
#include <ranges>
#include <vector>
#include <iostream>
int main()
{
std::vector<int> nums = { 1, 2, 3, 4, 5, 6, 7, 8, 9 };
for (int i : nums | std::views::drop(2))
{
std::cout << i << ' ';
}
std::cout << '\n';
return 0;
}
Output:
3 4 5 6 7 8 9
The easiest way to approach this kind of problems is to simply fall back to an indexed loop:
for(int i = 2; i < myVec.size(); i++) {
//do stuff with `myVec[i]`
}
For std::vector<>, this is just as efficient as the iterator based loop, and the loop control says exactly what it does on the lid. Most importantly, because you are comparing integers for < instead of iterators for !=, you do not run any risk to trigger undefined behavior when the vector is too short.

Keep the duplicated values only - Vectors C++

Assume I have a vector with the following elements {1, 1, 2, 3, 3, 4}
I want to write a program with c++ code to remove the unique values and keep only the duplicated once. So the end result will be something like this {1,3}.
So far this is what I've done, but it takes a lot of time,
Is there any way this can be more efficient,
vector <int> g1 = {1,1,2,3,3,4}
vector <int> g2;
for(int i = 0; i < g1.size(); i++)
{
if(count(g1.begin(), g1.end(), g1[i]) > 1)
g2.push_back(g1[i]);
}
v.erase(std::unique(g2.begin(), g2.end()), g2.end());
for(int i = 0; i < g2.size(); i++)
{
cout << g2[i];
}
My approach is to create an <algorithm>-style template, and use an unordered_map to do the counting. This means you only iterate over the input list once, and the time complexity is O(n). It does use O(n) extra memory though, and isn't particularly cache-friendly. Also this does assume that the type in the input is hashable.
#include <algorithm>
#include <iostream>
#include <iterator>
#include <unordered_map>
template <typename InputIt, typename OutputIt>
OutputIt copy_duplicates(
InputIt first,
InputIt last,
OutputIt d_first)
{
std::unordered_map<typename std::iterator_traits<InputIt>::value_type,
std::size_t> seen;
for ( ; first != last; ++first) {
if ( 2 == ++seen[*first] ) {
// only output on the second time of seeing a value
*d_first = *first;
++d_first;
}
}
return d_first;
}
int main()
{
int i[] = {1, 2, 3, 1, 1, 3, 5}; // print 1, 3,
// ^ ^
copy_duplicates(std::begin(i), std::end(i),
std::ostream_iterator<int>(std::cout, ", "));
}
This can output to any kind of iterator. There are special iterators you can use that when written to will insert the value into a container.
Here's a way that's a little more cache friendly than unordered_map answer, but is O(n log n) instead of O(n), though it does not use any extra memory and does no allocations. Additionally, the overall multiplier is probably higher, in spite of it's cache friendliness.
#include <vector>
#include <algorithm>
void only_distinct_duplicates(::std::vector<int> &v)
{
::std::sort(v.begin(), v.end());
auto output = v.begin();
auto test = v.begin();
auto run_start = v.begin();
auto const end = v.end();
for (auto test = v.begin(); test != end; ++test) {
if (*test == *run_start) {
if ((test - run_start) == 1) {
*output = *run_start;
++output;
}
} else {
run_start = test;
}
}
v.erase(output, end);
}
I've tested this, and it works. If you want a generic version that should work on any type that vector can store:
template <typename T>
void only_distinct_duplicates(::std::vector<T> &v)
{
::std::sort(v.begin(), v.end());
auto output = v.begin();
auto test = v.begin();
auto run_start = v.begin();
auto const end = v.end();
for (auto test = v.begin(); test != end; ++test) {
if (*test != *run_start) {
if ((test - run_start) > 1) {
::std::swap(*output, *run_start);
++output;
}
run_start = test;
}
}
if ((end - run_start) > 1) {
::std::swap(*output, *run_start);
++output;
}
v.erase(output, end);
}
Assuming the input vector is not sorted, the following will work and is generalized to support any vector with element type T. It will be more efficient than the other solutions proposed so far.
#include <algorithm>
#include <iostream>
#include <vector>
template<typename T>
void erase_unique_and_duplicates(std::vector<T>& v)
{
auto first{v.begin()};
std::sort(first, v.end());
while (first != v.end()) {
auto last{std::find_if(first, v.end(), [&](int i) { return i != *first; })};
if (last - first > 1) {
first = v.erase(first + 1, last);
}
else {
first = v.erase(first);
}
}
}
int main(int argc, char** argv)
{
std::vector<int> v{1, 2, 3, 4, 5, 2, 3, 4};
erase_unique_and_duplicates(v);
// The following will print '2 3 4'.
for (int i : v) {
std::cout << i << ' ';
}
std::cout << '\n';
return 0;
}
I have 2 improvements for you:
You can change your count to start at g1.begin() + i, everything before was handled by the previous iterations of the loop.
You can change the if to == 2 instead of > 1, so it will add numbers only once, independent of the occurences. If a number is 5 times in the vector, the first 3 will be ignored, the 4th will make it into the new vector and the 5th will be ignored again. So you can remove the erase of the duplicates
Example:
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
int main() {
vector <int> g1 = {1,1,2,3,3,1,4};
vector <int> g2;
for(int i = 0; i < g1.size(); i++)
{
if(count(g1.begin() + i, g1.end(), g1[i]) == 2)
g2.push_back(g1[i]);
}
for(int i = 0; i < g2.size(); i++)
{
cout << g2[i] << " ";
}
cout << endl;
return 0;
}
I'll borrow a principal from Python which is excellent for such operations -
You can use a dictionary where the dictionary-key is the item in the vector and the dictionary-value is the count (start with 1 and increase by one every time you encounter a value that is already in the dictionary).
afterward, create a new vector (or clear the original) with only the dictionary keys that are larger than 1.
Look up in google - std::map
Hope this helps.
In general, that task got complexity about O(n*n), that's why it appears slow. Does it have to be a vector? Is that a restriction? Must it be ordered? If not, it better to actually store values as std::map, which eliminates doubles when populated, or as a std::multimap if presence of doubles matters.

What's the most efficient way to print all elements of vector in ascending order till it's empty without duplicates?

I'm supposed to:
Print vector elements sorted without repetition.
Delete the elements that are printed from vector.
Repeat the the previous steps until vector is empty.
But it seems that my code takes more time so, I seek for optimisation. I've tried to do this task with std::vector and std::set.
Here is my approach:
#include <iostream>
#include <algorithm>
#include <vector>
#include <set>
using namespace std;
int main () {
int n;
cin >> n;
vector<int> v(n);
set<int> st;
for (int i = 0; i < n; i++) {
cin >> v[i];
}
while (!v.empty()) {
for (int i = 0; i < v.size(); i++)
st.insert(v[i]);
for (auto x : st) {
cout << x << ' ';
auto it = find(v.begin(), v.end(), x);
if (it != v.end())
v.erase(it);
}
st.clear();
cout << "\n";
}
return 0;
}
For example input is like:
7
1 2 3 3 2 4 3
Output gonna be like this:
1 2 3 4
2 3
3
You might use std::map instead of std::vector/std::set to keep track of numbers:
#include <iostream>
#include <map>
int main () {
map<int, int> m;
int size;
std::cin >> size;
for (int i = 0; i != size; i++) {
int number;
std::cin >> number;
++m[number];
}
while (!m.empty()) {
for (auto it = m.begin(); it != m.end(); /*Empty*/) {
const auto number = it->first;
auto& count = it->second;
std::cout << number << ' ';
if (--count == 0) {
it = m.erase(it);
} else {
++it;
}
}
std::cout << "\n";
}
}
Complexity is now O(n log(n)) instead of O(n²) (with lot of internal allocations).
Due to it overwriting the elements expected to be deleted, std::unique won't be much use for this problem. My solution:
std::sort(v.begin(), v.end());
while (!v.empty())
{
int last = v.front();
std::cout << last << " ";
v.erase(v.begin());
for (auto it = v.begin(); it != v.end(); /* no-op */)
{
if (*it == last)
{
++it;
}
else
{
last = *it;
std::cout << last << " ";
it = v.erase(it);
}
}
std::cout << std::endl;
}
You could probably improve performance further by reversing the sorting of the vector, and then iterating through backwards (since it's cheaper to delete from closer to the back of the vector), but that would complicate the code further, so I'll say "left as an exercise for the reader".
You can use std::map
auto n = 0;
std::cin >> n;
std::map<int, int> mp;
while (--n >= 0) {
auto i = 0;
std::cin >> i;
mp[i] += 1;
}
while (!mp.empty()) {
for (auto& it: mp) {
std::cout << it.first << " ";
it.second--;
}
for (auto it = mp.begin(); it != mp.end(); ++it) {
if (it->second == 0) mp.erase(it);
}
std::cout << "\n";
}
without any erase
auto n = 0;
std::cin >> n;
std::map<int, int> mp;
while (--n >= 0) {
auto i = 0;
std::cin >> i;
mp[i] += 1;
}
auto isDone = false;
while (!isDone) {
isDone = true;
for (auto& it: mp) {
if (it.second > 0) std::cout << it.first << " ";
if (--it.second > 0) isDone = false;
}
std::cout << "\n";
}
Here is a solution using sort and vector. It uses a second vector to hold the unique items and print them.
#include <iostream>
#include <vector>
#include <algorithm>
#include <iterator>
int main()
{
std::vector<int> v{1,2,3,3,2,4,3};
std::sort(v.begin(), v.end());
std::vector<int>::iterator vit;
while(!v.empty()){
std::vector<int> printer;
std::vector<int>::iterator pit;
vit = v.begin();
while (vit != v.end()){
pit = find(printer.begin(), printer.end(), *vit);
if (pit == printer.end()){
printer.push_back(*vit);
vit = v.erase(vit);
} else {
++vit;
}
}
std::copy(printer.begin(), printer.end(), std::ostream_iterator<int>(std::cout, " "));
std::cout << '\n';
}
}
Output:
1 2 3 4
2 3
3
It's not clear (at least to me) exactly what you're talking about when you mention "efficiency". Some people use it to refer solely to computational complexity. Others think primarily in terms of programmer's time, while still others think of overall execution speed, regardless of whether that's obtained via changes in computational complexity, or (for one example) improved locality of reference leading to better cache utilization.
So, with that warning, I'm not sure whether this really improves what you care about or not, but it's how I think I'd do the job anyway:
#include <iostream>
#include <vector>
#include <algorithm>
#include <iterator>
// preconditions: input range is sorted
template <class BidiIt>
BidiIt partition_unique(BidiIt begin, BidiIt end) {
auto pivot = end;
for (auto pos = begin; pos != pivot; ++pos) {
auto mid = std::next(pos);
for ( ; mid < pivot && *mid == *pos; ++mid, --pivot)
;
std::rotate(std::next(pos), mid, end);
}
return pivot;
}
template <class It>
void show(It b, It e, std::ostream &os) {
while (b != e) {
os << *b << ' ';
++b;
}
os << '\n';
}
int main() {
std::vector<int> input{ 1, 2, 3, 3, 2, 4, 3 };
std::sort(input.begin(), input.end());
auto begin = input.begin();
auto pos = begin;
while ((pos = partition_unique(begin, input.end())) != input.end()) {
show(begin, pos, std::cout);
begin = pos;
}
show(begin, input.end(), std::cout);
}
I'm not really sure it's possible to improve the computational complexity much over what this does (but it might be--I haven't thought about it enough to be sure one way or the other). Compared to some versions I see posted already, there's a decent chance this will improve overall speed (e.g., since it just moves things around inside the same vector, it's likely to get better locality than those that copy data from one vector to another.
The code is in java but the idea remains the same.
At first, I sort the array. Now, the idea is to create buckets.
This means that each line of sorted elements is like a bucket. So, find the count of each element. Now, put that element into each bucket, count number of times. If it so happens that bucket size is less, create a new bucket and add the current element to it.
In the end, print all buckets.
Time Complexity is O(nlog(n)) for sorting and O(n) for the buckets since you have to visit each and every element to print it. So, it's O(nlog(n)) + O(n) = O(nlog(n)) asymptotically.
Code:
import java.util.*;
public class GFG {
public static void main(String[] args){
int[] arr1 = {1,2,3,3,2,4,3};
int[] arr2 = {45,98,65,32,65,74865};
int[] arr3 = {100,100,100,100,100};
int[] arr4 = {100,200,300,400,500};
printSeries(compute(arr1,arr1.length));
printSeries(compute(arr2,arr2.length));
printSeries(compute(arr3,arr3.length));
printSeries(compute(arr4,arr4.length));
}
private static void printSeries(List<List<Integer>> res){
int size = res.size();
for(int i=0;i<size;++i){
System.out.println(res.get(i).toString());
}
}
private static List<List<Integer>> compute(int[] arr,int N){
List<List<Integer>> buckets = new ArrayList<List<Integer>>();
Arrays.sort(arr);
int bucket_size = 0;
for(int i=0;i<N;++i){
int last_index = i;
if(bucket_size > 0){
buckets.get(0).add(arr[i]);
}else{
buckets.add(newBucket(arr[i]));
bucket_size++;
}
for(int j=i+1;j<N;++j){
if(arr[i] != arr[j]) break;
if(j-i < bucket_size){
buckets.get(j-i).add(arr[i]);
}else{
buckets.add(newBucket(arr[i]));
bucket_size++;
}
last_index = j;
}
i = last_index;
}
return buckets;
}
private static List<Integer> newBucket(int value){
List<Integer> new_bucket = new ArrayList<>();
new_bucket.add(value);
return new_bucket;
}
}
OUTPUT
[1, 2, 3, 4]
[2, 3]
[3]
[32, 45, 65, 98, 74865]
[65]
[100]
[100]
[100]
[100]
[100]
[100, 200, 300, 400, 500]
This is what i came up with:
http://coliru.stacked-crooked.com/a/b3f06693a74193e5
The key idea:
sort vector
print by iterating. just print a value if it differs from last printed
remove unique elements. i have done this with what i called inverse_unique. the std library comes with an algorithm called unique, which will remove all duplicates. i inverted this so that it will just keep all dublicates.
so we have no memory allocation at all. i cant see how one could make the algorithm more efficient. we are just doing the bare minimum and its exactly done the way a human thinks about.
i tested it with several combinations. hope its bug free ;-P
code:
#include <iostream>
#include <algorithm>
#include <vector>
template<class ForwardIt>
ForwardIt inverse_unique(ForwardIt first, ForwardIt last)
{
if (first == last)
return last;
auto one_ahead = first+1;
auto dst = first;
while(one_ahead != last)
{
if(*first == *one_ahead)
{
*dst = std::move(*first);
++dst;
}
++first;
++one_ahead;
}
return dst;
}
void print_unique(std::vector<int> const& v)
{
if(v.empty()) return;
// print first
std::cout << v[0] << ' ';
auto last_printed = v.cbegin();
// print others
for(auto it = std::next(std::cbegin(v)); it != std::cend(v); ++it)
{
if(*it != *last_printed)
{
std::cout << *it << ' ';
last_printed = it;
}
}
std::cout << "\n";
}
void remove_uniques(std::vector<int> & v)
{
auto new_end = inverse_unique(std::begin(v), std::end(v));
v.erase(new_end, v.end());
}
int main ()
{
std::vector<int> v = {1, 2, 3, 3, 2, 4, 3};
std::sort(std::begin(v), std::end(v));
while (!v.empty())
{
print_unique(v);
remove_uniques(v);
}
return 0;
}
Edit: updated inverse_unique function. should be easy to understand now.
Half baked at http://coliru.stacked-crooked.com/a/c45df1591d967075
Slightly modified counting sort.
#include <iostream>
#include <vector>
#include <algorithm>
#include <iterator>
#include <map>
int main() {
std::vector<int> v{1,2,3,3,2,4,3};
std::map<int, int> map;
for (auto x : v)
++map[x];
while(map.size()) {
for(auto pair = map.begin(); pair != map.end(); ) {
std::cout << pair->first << ' ';
if (!--pair->second)
pair = map.erase(pair);
else
++pair;
}
std::cout << "\n";
}
return 0;
}

Print C++ Map by iteration

Is there an easier way to go about this or is there something I'm doing horribly wrong? I think that the core of my problem is in the code,
vector<int> &v = miss_words[*i];
but maybe I'm just getting the whole concept wrong. Any suggestions?
CODE:
void print_map(map<string, vector<int> > miss_words) // Prints out dictionary set
{
map<string, vector<int> >::iterator it = miss_words.begin(); // Creates an iterator
while(it != miss_words.end()) // While hasn't reached the end
{
vector<int> &v = miss_words[*it]; // Accesses Vector in map
for(unsigned int g = 0; g <= v.size(); g++)
{
cout<<v.at(g)<<": ";
cout<<v.at(g)<<" "<<endl; // Print out data at i
}
it++; // Increment iterator
}
}
The compiler puts says that there is "no match for 'operator[]' in miss_words.
You want to say vector<int> &v = it->second;
The iterator's value type is the value type of the map, i.e. pair<string, vector<int>>.
In fact, in modern C++ you could write this more simply, and less error-prone, like so:
for (auto const & p : miss_words)
{
for (auto const & x : p.second)
{
cout << x << ": " << x << " \n";
}
}
That way, you don't even need to worry about the size of your vector.