I want to search in a given interval (not a whole vector) of a vector container to see whether a user-specified integer is present or not. But I couldn't make it work. Thank you very much.
#include <iostream>
#include <algorithm>
#include <vector>
using namespace std;
int main ()
{
int myints[] = { 10, 20, 30 ,40 };
vector<int> myvector (myints,myints+4);
vector<int>::iterator it, itLower, itUpper;
itLower = myvector.begin();
itUpper = myvector.begin();
advance(itLower, 1);
advance(itUpper, 2);
// iterator to vector element:
it = find (itLower, itUpper, 50);
if (it != myvector.end())
{
// Found
cout << "Found it";
}
else
{
// Not fount
cout << "Not found it";
}
return 0;
}
You may just replace the line
if (it != myvector.end()) ...
by
if (it != itUpper) ...
If find does not find the item it returns the last element (which is in your case the end of your range and not of the complete vector). Note that the range is defined with itUpper exclusive.
Related
UPD:-
Value Instances
2 3
3 2
5 1
I want to limit the count to 1 for all the instances present in the multiset.
#include<bits/stdc++.h>
using namespace std;
int main() {
multiset<int> p1;
p1.insert(5);
p1.insert(2);
p1.insert(3);
p1.insert(3);
p1.insert(2);
p1.insert(2);
for(auto itr : p1) {
if(p1.count(itr) > 1)
p1.erase(itr);
cout << itr;
}
}
How to fix this ?
My comment:
In that case, you should use a std::set<int> because that is actually what matches your requirement. You could use also a std::map<int, int> to map the key to the number of occurrences if you like.
OPs reply:
Can you add this to a full-fledged answer so that I can accept it for this question?
Here we go:
Just filtering duplicates:
#include <iostream>
#include <set>
int main()
{
int sample[] = { 5, 2, 3, 3, 2, 2 };
// add all values at most once
using Table = std::set<int>;
Table table;
for (int value : sample) table.insert(value);
// output the result
for (const Table::value_type& entry : table) {
std::cout << "Value " << entry << "\n";
}
}
Output:
Value 2
Value 3
Value 5
Demo on coliru
Counting the number of occurrences:
#include <iostream>
#include <map>
int main()
{
int sample[] = { 5, 2, 3, 3, 2, 2 };
// add all values at most once but count the number of occurrences
using Table = std::map<int, unsigned>;
Table table;
for (int value : sample) ++table[value];
// output the result
for (const Table::value_type& entry : table) {
std::cout << "Value " << entry.first << " (" << entry.second << " times)\n";
}
}
Output:
Value 2 (3 times)
Value 3 (2 times)
Value 5 (1 times)
Demo on coliru
The trick:
The std::map::operator[] inserts an element if the key is not yet there. This element (in this case std::pair<const int, unsigned>) is default initialized which grants that it starts as { key, 0 }.
So, there are two cases:
The key is not yet there:
The element is created as { key, 0 } and the value (.second of the element) is incremented immediately which results in { key, 1 }.
The key is already there:
The value (.second of the element) is incremented again.
A variation on filtering duplicates:
This keeps the original input order but removes repetitions (by book-keeping in a separate std::set).
#include <iostream>
#include <set>
#include <vector>
int main()
{
using Sample = std::vector<int>;
Sample sample = { 5, 2, 3, 3, 2, 2 };
// remove duplicates
using Table = std::set<int>;
Table table;
Sample::iterator iterRead = sample.begin();
Sample::iterator iterWrite = sample.begin();
for (; iterRead != sample.end(); ++iterRead) {
if (table.insert(*iterRead).second) *iterWrite++ = *iterRead;
}
sample.erase(iterWrite, sample.end());
// output the result
for (const Sample::value_type& entry : sample) {
std::cout << "Value " << entry << "\n";
}
}
Output:
Value 5
Value 2
Value 3
Demo on coliru
The trick:
std::set::insert() returns a pair of iterator and bool.
The iterator points to the key in the set (inserted or already been there).
The bool denotes if the key was inserted (true) or was already there (false).
The other trick:
Just erasing every found duplicate from the std::vector would result in the worse complexity O(n²).
Hence, two iterators are used, one for reading and one for writing. Thereby, every input value which is not yet in the bookkeeping table (and hence occurs the first time) is written back, otherwise not.
So, every value which occurred the first time is shifted towards the beginning and appended to the previous values which occurred the first time each. Additionally, the iterWrite points past the last written element after the loop and can be used to erase the rest (which contains left input values which are all duplicates).
The complexity of this algorithm is O(n) – much better than the naive approach.
Btw. the standard algorithms std::remove(), std::remove_if() does it the same way.
Thus, the same algorithm could be achieved with std::remove_if():
#include <algorithm>
#include <iostream>
#include <set>
#include <vector>
int main()
{
using Sample = std::vector<int>;
Sample sample = { 5, 2, 3, 3, 2, 2 };
// remove duplicates
using Table = std::set<int>;
Table table;
Sample::iterator last
= std::remove_if(sample.begin(), sample.end(),
[&](int value) { return !table.insert(value).second; });
sample.erase(last, sample.end());
// output the result
for (const Sample::value_type& entry : sample) {
std::cout << "Value " << entry << "\n";
}
}
Output:
like above
Demo on coliru
#include <iostream>
#include <set>
using namespace std;
int main()
{
multiset<int> p1;
p1.insert(5);
p1.insert(2);
p1.insert(3);
p1.insert(4);
p1.insert(2);
p1.insert(2);
for (auto iter = p1.begin(); iter != p1.end();)
{
p1.count(*iter) > 1 ? iter = p1.erase(iter) : iter++;
}
for (auto & iter : p1)
{
cout << iter << ", ";
}
return 0;
}
I am trying to reorder the map in a descending way depending on the values, I have been trying to create a new map and insert the one which has the biggest value first but it keeps ordering the map by the keys.
I have also tried to reorder it by the value changing the form of the map into the other way but I will loose some data because I have more than one key which has the same value.
#include <iostream>
#include "SymbolFreq.h"
#include <string>
#include <fstream>
#include <streambuf>
#include <map>
using namespace std;
int main()
{
map <char, int> mymap;
map <char, int> realmap;
ifstream infile{ "ToCompress.txt" };
std::string str((std::istreambuf_iterator<char>(infile)),
std::istreambuf_iterator<char>());
std::map<char, int>::iterator itera;
for (auto it = str.begin(); it != str.end(); ++it)
{
itera = mymap.find(*it);
if (itera != mymap.end())
{
itera->second++;
}
else
{
mymap.insert({ *it, 1 });
}
}
int max = 0;
char provisionalChar;
int provisionalInt;
while (mymap.empty() == false)
{
for (auto it = mymap.cbegin(); it != mymap.cend(); ++it)
{
if (it->second > max)
{
max = it->second;
provisionalChar = it->first;
provisionalInt = it->second;
}
//cout << it->first << "\t" << it->second << "\n";
}
mymap.erase(provisionalChar);
realmap.insert({ provisionalChar, provisionalInt });
max = 0;
}
for (auto it = realmap.cbegin(); it != realmap.cend(); ++it)
{
cout << it->first << "\t" << it->second << "\n";
}
return 0;
}
If I understand the question properly, you'd like to count how many times each char appears in the file and then produce a map sorted with the char that appeared most time first.
Here's one idea:
#include <algorithm>
#include <cstdint>
#include <fstream>
#include <functional>
#include <iostream>
#include <iterator>
#include <map>
#include <string>
#include <unordered_map>
int main() {
std::ifstream infile{"ToCompress.txt"};
// "mymap" is only used for counting how many times each char appears.
std::unordered_map<char, std::uintmax_t> mymap;
// Loop directly over the file. No vector needed:
std::for_each(std::istreambuf_iterator<char>(infile),
std::istreambuf_iterator<char>(), [&mymap](char ch) {
// No need to find first - operator[] inserts an element
// for the key ("ch") if it's missing.
++mymap[ch];
});
// Transform the unordered_map into a multimap where the count is the key
// and in which we use a descending sort order (std::greater):
std::multimap<std::uintmax_t, char, std::greater<std::uintmax_t>> realmap;
std::transform(mymap.begin(), mymap.end(),
std::inserter(realmap, realmap.end()),
[](const auto& ch_co) -> std::pair<std::uintmax_t, char> {
// return a pair with key and value swapped
return {ch_co.second, ch_co.first};
});
// Print the result
for(auto& [count, ch] : realmap) {
std::cout << count << '\t' << ch << '\n';
}
}
Possible output:
537479
120204 t
113285 e
80681
80670 i
79862 n
77984 r
77464 s
69994 o
67377 a
...
Apparently, <space>, t, e and \n are tne most common characters in my C++ programs (which is what I used as input)
Your question may be ill-posed; take a step back and state what you are really trying to accomplish.
That said, I'll attempt an answer based on what you've written.
It looks like you're trying to sort an std::map by value, in which case your question is a duplicate of either this or this question.
Regarding your initial attempt:
Take a look at this table. Only sequence containers allow you to directly influence order. As with priority queue you have limited control over the order of associative containers and almost zero control for unordered containers.
I am new to C++. I am trying to find the index of the element if there is a subset in the vector.
I have my code below.. Please help me with the solution.
#include <iostream>
#include <vector>
#include <algorithm>
int main()
{
std::vector<uint8_t> v = { 1,2,3,4,0,6,7,8,4,5,6 };
int key = 4;
std::vector<uint8_t>::iterator itr = std::find(v.begin(), v.end(), key);
if (itr != v.cend()) {
uint8_t index = std::distance(v.begin(), itr);
if ((++index == 5) && (++index == 6))
std::cout << "Element present at index " << index-2;
else
continue;
}
else {
std::cout << "Element not found";
}
return 0;
}
In the above code, I want to print the index of the element '4' if 4,5,6 are consecutive elements.
Output : 8
You must replace your first if by a while with the same test, replace both of your ++index by *(++itr), not subtract 2 to index before printing it, and replace your last else by if(itr == v.cend())to get the output you want.
Note that this code doesn’t work anymore if you change the expected elements to find from {4,5,6} to {4,4,6} for example, so I would suggest you to change the general approach of your problem if you want to generalize it.
This question already has answers here:
Can I convert a reverse iterator to a forward iterator?
(5 answers)
Closed 4 years ago.
I want to iterate through some std::vectors in a for loop but depending on some conditions, the vectors shall be iterated either forward or backward. I thought, I could easily do it by using either normal iterators or reverse iterators like this:
#include <iostream>
#include <vector>
using namespace std;
int main() {
vector<int> vec{0, 1, 2, 3, 5, 6, 7};
bool reverse = true;
std::iterator<random_access_iterator_tag, int> it, end_it;
if (reverse) {
it = vec.rbegin();
end_it = vec.rend();
} else {
it = vec.begin();
end_it = vec.end();
}
for (; it != end_it; it++) {
cout << *it << ", ";
}
return 0;
}
But unfortunately vector::begin() and vector::rbegin() don't seem to be using the same parent class. Is there another way to do what I want without having two different loops in an if-else-structure? Of course I could create a function/lambda for the loop body or use some index arithmetic but is there a more elegant way?
The compiler complains about the assignment it = vec.begin() as they are different types. gcc and VC++ output different errors and seem to use different types for the return values of vector::begin.
Not sure if better and you will accept solution without std::iterator, but I consider this slightly more elegant:
#include <iostream>
#include <vector>
using namespace std;
int main() {
vector<int> vec{0, 1, 2, 3, 4, 5, 6};
bool reverse = true;
for(int i: vec){
if(reverse)
cout << vec[vec.size()-i] << endl;
else
cout << vec[i] << endl;
}
}
Not very efficient tho, as you have to check if in every loop.
map<int, string>::reverse_iterator& it = temp.rbegin();
it -> points to garbage key value
it++ -> points to the correct key value
map<int, string>::iterator& it = temp.begin();
it-> points to the correct key value from beginning.
Please assist.
Your statements are incorrect. If temp is not empty, then *temp.rbegin() is indeed the last value in the map, and *temp.begin() is the first value.
(However, the underlying iterator of the reverse begin is the ordinary end iterator - but you don't see that unless you call base() on the reverse iterator.)
You must have an error in your code that's filling the map. You can verify this by testing a trivial example such as
#include <algorithm>
#include <map>
#include <iostream>
using namespace std;
int main()
{
map<int, char> coll;
// insert elements from 1 to 9
for (int i=1; i<=9; ++i) {
coll[i] = static_cast<char>(i+'a'-1); // because adding 96 is less obvious that we're indexing based at letter a
}
// print all element in reverse order
for_each (coll.rbegin(), coll.rend(),
[]( pair<int, char> mapinfo ) { cout << mapinfo.second << " "; } );
cout << endl;
}