c++ - Getting range of numbers from a (sorted) list of numbers -
i came across following problem: consider having ascending list of numbers (e.g. 1,2,3,7,8,10), gather ranges (of consecutive numbers) , print them in compact form (with numbers given above):
1->3 7->8 10
in particular, solution should work "degenerated cases" list of 1 element, or list -2,1.
i came solution, tried separate numbers different vectors, looks quite cumbersome. so, know if there better alternative approach problem.
here approach:
vector< vector<int> > result(numbers.size()*numbers.size(), vector<int>()); int last_range; vector<int> range; vector<string> result_string; //1,2,3,7,8,10 if(numbers.size() == 1) { stringstream ss; ss << numbers[0]; result_string.push_back(ss.to_string()); return result_string; } (int = 1; < numbers.size(); i++ ) { if( numbers[i] - numbers[i-1] == 1 ) { range.push_back(numbers[i]); } if ( == numbers.size()-1 ) { last_range = numbers[i]; range.push_back(last_range); } result[i-1].push_back(range); } if( result.size() < 1 ) { range.push_back(numbers[0]); result[0].push_back(range); stringstream ss; ss << result[0][0]; result_string.push_back(ss.to_string()); return result_string; } //result[0] - > array of numbers 1,2,3 // result [1] - > array of numbers (int = 0; < result.size(); i++ ) { int start_index = result[i][0]; int last_index = result[i][result.size()-1]; stringstream ss_startindex; stringstream ss_endindex; ss_startindex << result[i][0]; ss_endindex << result[i][result.size()-1]; string result = ss_startindex.to_string() + "->" + ss_endindex.to_string(); result_string.push_back(result); } return result_string; }
what need object carries context ('next integer part of range?') across, while iterate on sequence. kind of problem best solved function object used unary function std::for_each algorithm.
a working example be:
#include <algorithm> #include <limits> #include <utility> #include <vector> #include <iostream> using intcollection = std::vector<int>; intcollection = {1,2,3,7,8,10}, is2 = {-2,1}, is3 = {20}; using range = std::pair<int,int>; class intrangeprinter { public: void operator() (int i) { if (r.first == inval) r.first = i; else if (r.second == inval && r.first + 1 == i) r.second = i; else if (r.second + 1 == i) r.second = i; else { print_range_or_value(); // reset after printing reset(); // , re-init range current value r.first = i; } } // there might "pending" data printed void flush() { print_range_or_value(); std::cout << std::endl; reset(); } private: static int inval; // value not expected in intcollection void print_range_or_value() { if (r.first != inval && r.second != inval) std::cout << ' ' << r.first << "->" << r.second; else // if (r.second == inval) std::cout << ' ' << r.first; } void reset () { r.first = inval; r.second = inval; } range r = {inval,inval}; }; int intrangeprinter::inval = std::numeric_limits<int>::max(); int main () { intrangeprinter p; p = std::for_each(is.begin(), is.end(), std::move(p)); p.flush(); p = std::for_each(is2.begin(), is2.end(), std::move(p)); p.flush(); p = std::for_each(is3.begin(), is3.end(), std::move(p)); p.flush(); return 0; }
Comments
Post a Comment