How to group consecutive integers in an array? - c++

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.

Related

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.

How can you keep the positions of an array the same while sorting?

I am writing a Caesar cipher decoding program that sorts the frequency of letters of a message in descending order. My issue is when I print out the results the positions of the frequencies in the array no longer match the letters I have set up. How do I fix this? I have other code that removes punctuation and capitals, all characters besides spaces and lowercase letters from the message being decoded.
I have trimmed down the code to just what is being questioned.
#include<iostream>
#include<string>
#include<fstream>
using namespace std;
void sortArray(int*, int);
int main()
{
string fileContent = "a coded message which is several hundreds of characters long is being passed into the program";
int count[26];
// This code is skipping over spaces and other characters
for(int f = 0; f < fileContent.length(); f++)
{
if(fileContent[f] == 32)
{
continue;
}
if(fileContent[f] >= 48 && fileContent[f] <= 57)
{
continue;
}
count[(fileContent[f]-'a')%26]++;
}
// Here is where my issue begins. In sortArray, the position of the characters are being changed.
cout << "Letter frequency: Most common to least common" << endl;
sortArray(count, 26);
for(int p = 0; p < 26; p++)
{
cout << char(p + 97) << ": " << count[p] << endl;
}
return 0;
}
void sortArray(int* srcArray, int numElements)
{
for(int x = 0; x < numElements; x++)
{
int max = srcArray[x];
int maxIndex = x;
int hold;
for(int y = x + 1; y < numElements; y++)
{
if(srcArray[y] > max)
{
max = srcArray[y];
maxIndex = y;
}
}
hold = srcArray[x];
srcArray[x] = max;
srcArray[maxIndex] = hold;
hold = 0;
}
}
Please kindly let me know how I can solve this issue, I've been theorizing but I cannot seem to figure out a viable solution.
After you compute the frequency in count array.
std::array<std::pair<char, int>, 26> pairArray;
for (int i = 0; i < 26; ++i)
{
pairArray[i] = std::make_pair('a' + i, count[i]);
}
std::sort(pairArray.begin(), pairArray.end(), myCompare);
for (int i = 0; i < 26; ++i)
std::cout << pairArray[i].first << ": " << pairArray[i].second << std::endl;
For myCompare,
bool myCompare(const std::pair<char, int>& p1, const std::pair<char, int>& p2)
{
return p1.second > p2.second;
}
This should sort the array in descending order.
The problem you are facing is because you have frequencies in the array but the frequencies are not mapped to corresponding character. When the frequencies are sorted,the array is rearranged but your printing of the frequencies is not character dependent,you are printing characters from a-z and assigning frequencies as they are in sorted array.
What you can do is map the frequencies with corresponding character. One solution can be using an unordered map,char being key. An unordered map because it won't internally sort the map on character value,so u can maintain frequency ordering as well.
You can also use vector with pair as #lamandy suggested.
vector< pair <char, int> > vect;
for (int i = 0; i < 26; i++)
{
vect.push_back(make_pair(char(i + 97), count[i]));
}
sort(vect.begin(), vect.end(), sortbysecVal);
// Printing the sorted vector(after using sort())
cout << "The vector after sort operation is:\n";
for (int i = 0; i<26; i++)
{
// "first" and "second" are used to access
// 1st and 2nd element of pair respectively
cout << vect[i].first << " "
<< vect[i].second << endl;
}
sort by second value of pair
bool sortbysecVal(const pair<int, int> &a, const pair<int, int> &b)
return (a.second > b.second);
Once after you have calculated frequencies,you can use this,this will solve your purpose and you wont need your sort function.
P.S : One more thing,you must initialize your (array)count to 0,like int count[26] = {0},because initially it contains garbage if uninitialized and adding up 1 ( count[(fileContent[f]-'a')%26]++;) to a garbage will not produce result(frequency) u expect
The answer is probably a three-liner for a standard library guru, which I am not quite yet. I hate the standard library. It makes programming so easy that anyone can do it.
Here are two versions that I hacked out. This is fun.
#include <map>
#include <string_view>
#include <vector>
#include <algorithm>
using counted = std::pair<char, unsigned>;
std::vector<counted>
counted_chars(const std::string_view input) {
// Return a vector of <char, count> pairs, where char is an uppercase
// letter, and count is the number of occurrences of the letter (upper or lower).
// It is sorted from highest count to lowest.
using namespace std;
map<char, unsigned> count;
// Count them.
for(char next: input) {if (isalpha(next)) {count[toupper(next)] += 1;}}
// Sort them
vector<counted> sorted(count.size());
copy(count.cbegin(), count.cend(), sorted.begin());
sort(sorted.begin(), sorted.end(), [](counted c1, counted c2)
{ return c1.second > c2.second; });
return sorted;
}
int main() {
std::string str = "a coDed; MESSage which_is several hundreds of characters long is being passed into the program";
auto result = counted_chars(str);
return 0;
}
Another one that doesn't use std::map.
#include <map>
#include <vector>
#include <algorithm>
using counted = std::pair<char, unsigned>;
std::vector<counted> counted_chars(std::string input) {
using namespace std;
input.resize(remove_if(input.begin(), input.end(), [](char ch) { return !isalpha(ch); })-input.begin());
for(char &ch: input) { ch = toupper(ch); }
sort(input.begin(), input.end());
string present {input};
present.resize(unique(present.begin(), present.end())-present.begin());
std::vector<counted> sorted;
for (char ch:present) {sorted.push_back(make_pair(ch, count(input.begin(), input.end(), ch)));}
sort(sorted.begin(), sorted.end(), [](counted c1, counted c2) { return c1.second > c2.second; });
return sorted;
}
int main() {
std::string str = " -- I have always wished for my computer to be as easy to use as my telephone; My wish has come true because I can no longer figure out how to use my telephone.";
auto result = counted_chars(std::move(str));
return 0;
}

c++ operator doesn't match operand error

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

run time error with function convert from string to int

I have a string contains numbers but also contains spaces between them, i need to convert the string to int and store them in an int array .
Th following function produces a run time error
void fun(string m)
{
string temp;
int j = 0;
int h = 0;
int d;
int arr[10];
for (int i = 0; i < m.length(); i++)
{
while (m[i] != ' ')
temp[j++] = m[i];
d = atoi(temp.c_str());
arr[h++] = d;
}
for (int i = 0; i < sizeof(arr); i++)
{
cout << arr[i];
}
}
I would suggest using a stringstream for this vs. rolling your own implementation.
#include <sstream>
#include <iterator>
#include <iostream>
int main()
{
std::stringstream ss("1 2 3 4 5 6 7");
auto head = std::istream_iterator<int>(ss);
auto tail = std::istream_iterator<int>();
while(head!=tail)
{
std::cout << *head << "\n";
++head;
}
return 0;
}
if you're receiving the string in a method you can easily adapt the function above to create an empty stringstream and then pass it the string.
#include <sstream>
#include <iterator>
#include <iostream>
int main()
{
std::string astring = "1 2 3 4 5 6";
std::stringstream ss;
ss << astring;
auto head = std::istream_iterator<int>(ss);
auto tail = std::istream_iterator<int>();
while(head!=tail)
{
std::cout << *head << "\n";
++head;
}
return 0;
}
You are making several mistakes in your code.
You have not initialized temp to contain anything, but you are trying to index into its characters. Instead of temp[j++] = m[i], you need to use temp += m[i]; or temp.push_back(m[i]); or temp.append(&m[i], 1);. Or consider using an std::ostringstream to gather the characters, and then call its str() method to extract the final std::string value.
you are not incrementing i in your while loop. As soon as the for loop reaches a non-whitespace character, your while loop will end up running endlessly, continuously (and unsuccessfully) trying to append the same character to temp.
you are not doing any bounds checking to make sure your for loop does not exceed arr's max capacity of 10 numbers.
you are misusing sizeof(). sizeof(arr) returns the number of bytes that arr occupies in memory (10 * sizeof(int), which is 20 or 40 bytes, depending on your compiler's implementation of int). It is not the number of elements in the array (10). So you will exceed the bounds of the array trying to display 20/40 numbers instead of 10 numbers.
Your code is more complicated than it needs to be. You can use a std::istringstream for parsing and let it ignore whitespace for you. Use std::vector or other dynamically-sized container to receive the parsed numbers.
#include <sstream>
#include <vector>
void fun(string m)
{
std::istreamstream iss(m);
std::vector<int> vec;
int num;
vec.reserve(10); // optional
while (iss >> num) {
vec.push_back(num);
}
for (int i = 0; i < vec.size(); ++i) {
std::cout << vec[i];
}
/*
alternatively:
for (std::vector<int>::iterator iter = vec.begin(); iter != vec.end(); ++iter) {
std::cout << *iter;
}
*/
/*
alternatively (C++11 and later):
for (auto i: vec) {
std::cout << i;
}
*/
/*
alternatively (C++11 and later):
std::for_each(vec.begin(), vec.end(), [](int &n){ std::cout << n; });
*/
}
You cannot do for (int i = 0; i < sizeof(arr); i++)
The sizeof() operator gives you the size of something in bytes, which for an array of 10 ints probably amounts to 40. You need to use something like this:
#define COUNTOF(x) ((x)/sizeof((x)[0]))
for (int i = 0; i < COUNTOF(arr); i++)
The problem is in your while loop, J is 0 the first iteration through the While loop and gets incremented the first time it's called while also trying to assign it to the next letter.
Despite this issue I'd suggest using a string stream for this problem like others have said.
Here's a good reference.