c++ operator doesn't match operand error - c++

I am new to c++. I am getting an error when I try to output the result of a string vector. I was hoping someone can why? the code for GenerateCombinations function is from https://www.programmingalgorithms.com/algorithm/unique-combinations. I wrote the main() function. I am using VS community 2015.
#include "stdafx.h"
#include <iostream>
#include <Vector>
#include <string>
using namespace std;
//*****Please include following header files***** /
// string
// vector
/***********************************************/
/*****Please use following namespaces*****/
// std
/*****************************************/
static vector<vector<string>> GenerateCombinations(vector<string> arr)
{
vector<vector<string>> combinations;
int length = arr.size();
for (int i = 0; i < (1 << length); ++i)
{
vector<string> combination;
int count = 0;
for (count = 0; count < length; ++count)
{
if ((i & 1 << count) > 0)
combination.push_back(arr[count]);
}
if (count > 0 && combination.size() > 0) {
combinations.push_back(combination);
}
}
return combinations;
}
int main() {
vector<string> arr = { "How", "Are", "You" };
vector<vector<string>> combinations = GenerateCombinations(arr);
vector <string> ::iterator itr;
for (itr = combinations.begin(); itr < combinations.end(); itr++)
{
cout << *itr << endl;
}

As #Sam has pointed out in the comments, you are attempting to assign a std::vector<std::vector<std::string>>::iterator from combinations.begin() to std::vector<std::string>::iterator, hence the mismatch.
The easiest way to solve your problem is to worry less about actual types, and use auto:
for (auto itr = combinations.begin(); itr < combinations.end(); ++itr)
Or more simply:
for (auto combination : combinations)
Here combination is a std::vector<std::string>, so you can't just print that, you need to iterate through that as well:
for (auto combination : combinations)
{
for (auto c : combination)
{
std::cout << c << ' ';
}
std::cout << "\n";
}

Related

How to group consecutive integers in an array?

How to split integer list into sublist and then return a std::map<int, string> to map the int to the string joined by sublist?
It is necessary to ensure that each sublist is monotonically increasing with consecutive values
Example
input:
{1,2,3, 6,7,8,9, 12, 14,15}
output:
1 -> "1-2-3"
2 -> "1-2-3"
3 -> "1-2-3"
6 -> "6-7-8-9"
7 -> "6-7-8-9"
8 -> "6-7-8-9"
9 -> "6-7-8-9"
12 -> "12"
14 -> "14-15"
15 -> "14-15"
I tried this code and make it right, thank everyone providing idea
#include <stdio.h>
#include <iostream>
#include <sstream>
#include <map>
using namespace std;
void split(int* lis, int num, map<int, string> &dict)
{
int start = 0, end = 0;
while (true)
{
string str = to_string(lis[start]);
for (int j = start + 1; j < num; j++)
{
if (lis[j] - 1 == lis[j - 1])
{
end = j;
str = str + "-" + to_string(lis[j]);
}
else
break;
}
for (int j = start; j <= end; j++)
dict[lis[j]] = str;
start = end = end + 1;
if (end == num)
return;
}
}
int main(void)
{
int lis[10] = { 1,3,5,6,7,8,11,12,13,19 };
map<int, string> dict;
split(lis, 10, dict);
for (int i = 0; i < 10; i++)
cout << lis[i] << "\t" << dict[lis[i]] << '\n';
return 0;
}
This is a nice example for the usage of STL containers and algorithms.
So, we could start with a std::vector of any values. This, we can sort and remove the duplicates by putting it into a std::set.
Then we iterate over this data and use std::adjacent_find to look for a value that is not equal to the previous value + 1. This we can do in a loop until we reach the end of the original data.
Everytime, when we found the end of such a sequence, we will build the resulting specified string and store it, together with the source data in a std::map.
We set the start iterator to the current end iterator and continue to search.
At the end, we show the result to the user.
Of course there are many possible solutions. Please see one example below:
#include <iostream>
#include <sstream>
#include <vector>
#include <set>
#include <iterator>
#include <algorithm>
#include <string>
#include <map>
#include <iomanip>
int main() {
// Some test data. Not sorted, with duplicates
std::vector testData{ 15,14,12,14,3,3,12,1,7,8,7,8,9,2,1,1,6,6,9,15 };
// Sort and remove duplicates. Maybe you wanna do this or not. Up to you. If not, eliminate that line and work with original data
std::set data(testData.begin(), testData.end());
// Here we will store the result
std::map<int, std::string> result{};
// We will start the evaluation at the beginning of our data
auto startOfSequence = data.begin();
// Find all sequences
while (startOfSequence != data.end()) {
// FInd first value that is not greate than one
auto endOfSequence = std::adjacent_find(startOfSequence, data.end(), [](const auto& v1, const auto& v2) {return v2 != v1 + 1; });
if (endOfSequence != data.end()) std::advance(endOfSequence, 1);
// Build resulting string
std::ostringstream oss{};
bool writeDash = false;
for (auto it = startOfSequence; it != endOfSequence; ++it) {
oss << (writeDash ? "-" : "") << std::to_string(*it);
writeDash = true;
}
// Copy result to map
for (auto it = startOfSequence; it != endOfSequence; ++it)
result[*it] = oss.str();
// Continue to search for the next sequence
startOfSequence = endOfSequence;
}
// Show result on the screen. Or use the map in whichever way you want.
for (const auto& [value, text] : result) std::cout << std::left << std::setw(2) << value << " -> """ << text << """\n";
return 0;
}
I am using CTAD, so you have to compile with C++17 enabled.
Developed, compiled and tested with Microsoft Visual Studio Community 2019, Version 16.8.2
Additionally compiled and tested with gcc10.2 and clang 11.0.1
EDIT
Meanwhile OP posted own code. I adapted my function to that style.
But in C++ we should never use C-Style arrays and especially not using namespace std;
Anyway. Please see solution below.
#include <map>
#include <string>
#include <sstream>
#include <algorithm>
#include <iostream>
void split(int* lis, int num, std::map<int, std::string>& dict) {
// We will start the evaluation at the beginning of our data
auto startOfSequence = lis;
auto endOfList = lis + num;
// Find all sequences
while (startOfSequence != endOfList) {
// FInd first value that is not greate than one
auto endOfSequence = std::adjacent_find(startOfSequence, endOfList,
[](const auto& v1, const auto& v2) {return v2 != v1 + 1; });
if (endOfSequence != endOfList) std::advance(endOfSequence, 1);
// Build resulting string
std::ostringstream oss{};
bool writeDash = false;
for (auto it = startOfSequence; it != endOfSequence; ++it) {
oss << (writeDash ? "-" : "") << std::to_string(*it);
writeDash = true;
}
// Copy result to map
for (auto it = startOfSequence; it != endOfSequence; ++it)
dict[*it] = oss.str();
// Continue to search for the next sequence
startOfSequence = endOfSequence;
}
}
int main() {
int lis[10] = { 1,3,5,6,7,8,11,12,13,19 };
std::map<int, std::string> dict;
split(lis, 10, dict);
for (int i = 0; i < 10; i++)
std::cout << lis[i] << "\t" << dict[lis[i]] << '\n';
return 0;
}
I want to add another solution for this problem, which will give the same results but with a better performance for large input data.
for example , imagine your input array is an array of size 100000 integers inside which are all consecutive i.e [1 , 2 , 3 , ... , 100000]
So by the method you need to store your data by you will have a string of around 200000 characters stored 1e5 times in the map this with no doubt will crash during runtime (O(n^2) memory complexity)
So instead of making the value of the array element to be the key of the map , you can before that make a key for each array value depending on the sequence it's located at , then you can retrieve the sequence by sequenceOf[keyOfValue[arrayValue]] which will result in O(n) memory complexity where n is the size of the array.
Code example:
#include<iostream>
#include<map>
#include<string>
#include<vector>
#include<algorithm>
#include<sstream>
using namespace std;
string convert_to_string(vector<int> sequence){
string ret = "" ;
for(int i = 0 ; i < sequence.size() ; i++){
ret += to_string(sequence[i]) ;
ret += "-";
}
ret.pop_back() ;
return ret ;
}
int main(){
int a[] = {1,2,3, 6,7,8,9, 12, 14,15};
int size = sizeof(a) / sizeof(a[0]) ;
map<int , string>mp ;
map<int , int>keyOfValue;
vector<int>sequence;
int key = 0 ;
for(int i = 0 ; i < size ; i++){
if(sequence.empty() || sequence.back() + 1 == a[i]){
sequence.push_back(a[i]);
if(i != size - 1)
continue ;
}
for(int j = 0 ; j < sequence.size(); j++){
// store all sequence element keys to be the same
keyOfValue[sequence[j]] = key ;
}
// store the sequence only once.
string value = convert_to_string(sequence);
mp[key++] = value ;
sequence.clear();
if(i != size - 1)
i--;
}
// How to retrieve the value
for(int i = 0 ; i < size; i++) {
cout << mp[keyOfValue[a[i]]] << endl ;
}
}
Also instead of using std::map to store the sequence you can use a std::vector<string> to also reduce the retrieving of the array time from logarithmic to O(1) time, however I have use map as this was the goal of the question.

why does it give me bigger than 4 always?

I am trying to get the numbers bigger than 4 after I loop in every other number, but the problem is that it keeps giving me bigger than 4 even tho the number isn't bigger than 4. thank you!
#include <iostream>
#include <vector>
#include <string>
using namespace std;
bool isvalidcc(const string& s)
{
vector<char> v (s.begin(), s.end());
for(auto i=0 ; i<v.size();i+=2)
{
if (v.at(i)>'4')
{
cout<<v.at(i)<<"bigger than 4"<<endl;
}
else
{
cout<<v.at(i)<<"smaller than 4"<<endl;
}
}
return false;
}
int main()
{
vector<string> cardnumbers = {
"371449635398431"
};
int i;
vector<string>::iterator itr;
for (i = 1, itr = cardnumbers.begin(); itr != cardnumbers.end(); ++itr, i++) {
// cout << i << " "
// << *itr
((isvalidcc(*itr)));
}
return 0;
}
I figured it out
Because v.at(i) is a char instead of an int it converts it into ascii code.
this means u have to convert the char in to an int the right way.
if (v.at(i) - '0' >4)
the - '0' will convert it to an int the right way otherwise it will return the wrong values, u can check this by making a new int variable and cout <<
int n = v.at(i);
cout << n;

Displaying all prefixes of a word in C++

I am trying to do is display all the suffixes of a word as such:
word: house
print:
h
ho
hou
hous
house
What I did is:
#include <iostream>
#include <string.h>
using namespace std;
int main()
{
char cuvant[100];
int i,k;
cin>>cuvant;
for(i=0;i<strlen(cuvant);i++)
{
for(k=0;k<i;k++)
{
if(k==0)
{
cout<<cuvant[k]<<endl;
}else
{
for(k=1;k<=i;k++){
if(k==i) cout<<endl;
cout<<cuvant[k];
}
}
}
}
}
What am I doing wrong?
You're over-complicating it. Here's a simpler way:
#include <iostream>
#include <string>
#include <string_view>
int main() {
std::string s;
std::cin >> s;
for (std::string::size_type i = 0, size = s.size(); i != size; ++i)
std::cout << std::string_view{s.c_str(), i + 1} << '\n';
}
If you don't have access to a C++17 compiler, you can use this one:
#include <algorithm>
#include <iostream>
#include <iterator>
#include <string>
int main() {
std::string s;
std::cin >> s;
for (auto const& ch : s) {
std::copy(s.c_str(), (&ch + 1),
std::ostream_iterator<decltype(ch)>(std::cout));
std::cout << '\n';
}
}
Even so, I think it would be better for your learning progress to use a debugger to finger out the problem yourself. Here the problems with your code:
For the i=0 (the first iteration of your outer loop) the for(k=0;k<i;k++) will not be executed at all, as k<0 evaluates to false.
And having a running variable (k) that you change in two for loops that are nested, is most of the time also an indication that something is wrong.
So what you want to do: You want to create each possible prefix, so you want to create n strings with the length of 1 to n. So your first idea with the outer loop is correct. But you overcomplicate the inner part.
For the inner part, you want to print all chars from the index 0 up to i.
int main() {
char cuvant[100];
std::cin >> cuvant;
// loop over the length of the string
for (int i = 0, size = strlen(cuvant); i < size; i++) {
// print all chars from 0 upto to i (k<=0)
for (int k = 0; k <= i; k++) {
std::cout << cuvant[k];
}
// print a new line after that
std::cout << std::endl;
}
}
But instead of reinventing the wheel I would use the functions the std provides:
int main() {
std::string s;
std::cin >> s;
for (std::size_t i = 0, size = s.size(); i < size; i++) {
std::cout << s.substr(0, i + 1) << std::endl;
}
}
For this very simple string suffix task you can just use:
void main()
{
std::string s = "house";
std::string s2;
for(char c : s)
{
s2 += c;
cout << s2 << endl;
}
}
For more complicated problems you may be interested to read about Suffix Tree
Your code is wrong, the following code can fulfill your requirements
#include <iostream>
using namespace std;
int main()
{
char cuvant[100];
int i,k;
cin>>cuvant;
for(i=0;i<strlen(cuvant);i++)
{
for (k = 0; k <= i; ++k)
{
cout<<cuvant[k];
}
cout<<endl;
}
}

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;
}

How to print frequency of each letter in a string in descending order c++?

#include <iostream>
#include <string>
using namespace std;
int main () {
int cnt[26] {};
char alpha[26];
string s = "abcdefffggghiii";
for (int i = 0; i < s.length(); i++) {
cnt[s[i] - 'a']++;
}
for (int i = 'a'; i <= 'z'; i++) {
alpha[i - 'a'] = i;
}
for (int i = 0; i < 26; i++) {
if (cnt[i]) {
cout << alpha[i] << " " << cnt[i] << endl;
}
}
return 0;
}
I wanted to print the frequencies of each letter in the string in descending order. I've thought to sort the cnt array and print from 25 to 0 but it will only print the frequencies with wrong letter. How can I fix it to print for example i 3 and so on in descending order?
#include <iostream>
#include <string>
#include <vector>
#include <algorithm>
using namespace std;
int main() {
// Create result container
auto x = vector<pair<char, int>>();
std::string s = "abcdefffggghiii";
for (auto& l : s) {
// Find the item that corresponds to letter
auto pLetter =
find_if(x.begin(), x.end(), [&l](pair<char, int> &arg) {
return arg.first == l;
});
if (pLetter != x.end())
pLetter->second++; // If item corresponding to letter is found, increment count
else {
x.push_back(make_pair(l, 1)); // Otherwise, create a new result entry
}
}
// Sort results by count in descending order
std::sort(x.begin(), x.end(),
[](auto &left, auto &right) { return left.second > right.second; });
for (auto i = x.begin(); i != x.end(); ++i)
std::cout << i->first << ':' << i->second << '\n';
}
Produces
f:3
g:3
i:3
a:1
b:1
c:1
d:1
e:1
h:1
You can run it here. This uses C++14 lambdas for the find_if and sort predicates. This solution is very similar to #Retired Ninja's, except that the result vector contains items only for those letters that have non-zero counts. This means that it is extendable to wstrings without the need for a large result vector.
Here's how I might do it. You just need to keep the letter and the count together.
#include <iostream>
#include <vector>
#include <string>
#include <algorithm>
struct LetterFreq
{
char letter;
int freq;
};
int main()
{
std::vector<LetterFreq> cnt(26);
for (size_t i = 0; i < cnt.size(); ++i)
{
cnt[i].freq = 0;
cnt[i].letter = static_cast<char>(i) + 'a';
}
std::string s = "abcdefffggghiii";
for (auto& l : s)
{
cnt[l - 'a'].freq++;
}
std::sort(cnt.begin(), cnt.end(), [](const LetterFreq& lhs, const LetterFreq& rhs)
{
return lhs.freq > rhs.freq;
});
for (auto& item : cnt)
{
if (item.freq == 0)
{
break;
}
std::cout << item.letter << " : " << item.freq << "\n";
}
return 0;
}
This is simple if all you have it lowercase ASCII letters. For more complicated input you can use the same idea of the letter and count in a struct, but you'd either want to increase the size of the vector to 256 to keep track of all possibilities, or use something like an unordered map to only store used symbols and then copy them out into a container you can sort to display them. You could also use parallel arrays and while sorting swap the letter positions at the same time you're swapping the counts. There are many ways to handle this.
You could use pairs, but it looks like you're doing this with more basic types. In that case you might have to use nested loops. Keep finding the highest frequency character, print it, and then set its frequency to -1 to indicate that you've processed it already.