How to limit boost::combine to the minimum of two ranges - c++

Finding the following as the source of a segfault just cost me about 4h of work:
#include <boost/range/combine.hpp>
#include <boost/foreach.hpp>
#include <iostream>
#include <vector>
#include <list>
int main(int, const char*[])
{
std::vector<int> v;
std::list<char> l;
for (int i = 0; i < 5; ++i)
{
v.push_back(i);
l.push_back(static_cast<char>(i) + 'a');
}
v.push_back(5);
int ti;
char tc;
BOOST_FOREACH(boost::tie(ti, tc), boost::combine(v, l))
{
std::cout << '(' << ti << ',' << tc << ')' << '\n';
}
return 0;
}
If you execute this example, you will note that combine happily iterates as long as the longer range has values. I do not see this in the documentation.
Is there a way to limit the iteration to the shorter of the two ranges?

Related

How to get frequency of std:vectors in C++?

I have 5 vectors. I want to check how many times these vectors exist. I used the following code to compare if 2 vectors are equal, but now I have more than 2 vectors. I want to compare all these 5 vectors together and count how many times each vector exists.
How can I do it?
The output should be:
(0,0,1,2,3,0,0,0) = 2 time(s)
(0,0,1,2,3,4,0,0) = 1 time(s)
(0,0,2,4,3,0,0,0) = 1 time(s)
(0,0,6,2,3,5,6,0) = 1 time(s)
Here is my code:
#include <stdio.h>
#include <iostream>
#include <vector>
using namespace std;
void checkVec(vector<int> v){
vector<int> v0;
if(v0 == v){
cout << "Equal\n";
}
else{
cout << "Not Equal\n";
}
}
int main(){
vector<int> v1={0,0,1,2,3,0,0,0};
vector<int> v2={0,0,1,2,3,4,0,0};
vector<int> v3={0,0,2,4,3,0,0,0};
vector<int> v4={0,0,1,2,3,0,0,0};
vector<int> v5={0,0,6,2,3,5,6,0};
checkVec(v1);
return 0;
}
You can use std::map counting the number of occurences of each vector:
#include <map>
#include <vector>
#include <iostream>
using vec = std::vector<int>;
int main(){
vec v1={0,0,1,2,3,0,0,0};
vec v2={0,0,1,2,3,4,0,0};
vec v3={0,0,2,4,3,0,0,0};
vec v4={0,0,1,2,3,0,0,0};
vec v5={0,0,6,2,3,5,6,0};
std::map<vec,std::size_t> counter;
// Initializer list creates copies by default
// But you should not create vX variables anyway.
for(const auto& v: {v1,v2,v3,v4,v5}){
++counter[v];
}
std::cout<<"V1 is present " <<counter[v1]<<" times.\n";
return 0;
}
V1 is present 2 times.
Well, this is a contribution for Quimby answer, but if you know how many vectors you will get at compile time, use std::array to contain all that vector. If you know it at runtime instead, use std::vector as shown below
#include <map>
#include <vector>
#include <iostream>
#include <cstddef>
int main(){
std::vector<std::vector<int>> allVector
{
std::vector<int>{0,0,1,2,3,0,0,0},
std::vector<int>{0,0,1,2,3,4,0,0},
std::vector<int>{0,0,2,4,3,0,0,0},
std::vector<int>{0,0,1,2,3,0,0,0},
std::vector<int>{0,0,6,2,3,5,6,0},
};
std::map<std::vector<int>, std::size_t> counter;
for(const auto& v : allVector)
{
++counter[v];
}
// print out the array and it's frequency
for(const auto& pr : counter)
{
std::cout << '(';
for(std::size_t i {0}; i < pr.first.size(); ++i)
{
std::cout << pr.first[i];
if(i != pr.first.size() - 1)
std::cout << ' ';
}
std::cout << ") = " << pr.second << ", ";
}
return 0;
}

Show me a way to sort a char vector in c++

I'm doing this exercise from DCoder, and I'm trying to solve it in C++. But I need a little help. Although I know this should be simple, I just seem to miss something.
I'm given 2 inputs, the first one is the number of letters that will follow, and the second input is these letters. I need to write a code that will give an output of the letter array in alphabetically sorted order.
Example input:
5
Z k a P b
Expected output:
a b k P Z
Can any of you guys show me what the simplest way is to solve my problem?
I tried the std::sort() function in many ways, but it's not helping me much.
Is the std::sort() function even a good way to sort something like this?
#include <iostream>
#include <string>
#include <algorithm>
#include <vector>
using namespace std;
//Compiler version g++ 6.3.0
int main() {
int n;
cin >> n;
char s;
vector<char> vec;
while (cin >> s){
vec.push_back(s);
}
sort(vec.begin(), vec.end());
for (int i = 0; i <= vec.size(); i++){
cout << vec[i] << " " ;
}
}
My code is supposed to output a c D M, but it's giving D M a c instead.
std::sort() will work fine, but note that it orders values in ascending order by default, and in ASCII uppercase letters appear before lowercase letters. To get around that, you can give std::sort() a custom comparator that performs a case-insensitive comparison, eg:
#include <iostream>
#include <string>
#include <algorithm>
#include <vector>
#include <cctype>
int main() {
int n;
char c;
std::vector<char> vec;
std::cin >> n;
for (int i = 0; (i < n) && (std::cin >> c); ++i) {
vec.push_back(c);
}
/* alternatively:
std::copy_n(std::istream_iterator<char>(std::cin), n, std::back_inserter(vec));
*/
std::sort(vec.begin(), vec.end(),
[](unsigned char c1, unsigned char c2){ return std::tolower(c1) < std::tolower(c2); }
);
for (size_t i = 0; i < vec.size(); ++i){
std::cout << vec[i] << " ";
}
/* alternatively:
for (char c : vec){
std::cout << c << " ";
}
*/
}
Live Demo
This is the code that worked for me:
#include <iostream>
#include <string>
#include <algorithm>
#include <vector>
#include <cctype>
using namespace std;
//Compiler version g++ 6.3.0
char my_tolower(char ch)
{
return static_cast<char>(tolower(static_cast<unsigned char>(ch)));
}
int main() {
int n;
cin >> n;
char c;
vector<char> vec;
for (int i = 0; (i < n) && (cin >> c); ++i){
vec.push_back(c);
}
sort(vec.begin(), vec.end(),
[](char c1, char c2){ return my_tolower(c1) < my_tolower(c2); }
);
for (auto &&c : vec){
cout << c << " ";
}
}

create a word series with defined hamming distance among elements

I want to obtain all words of specific length/alphabet which have a minimal hamming distance among themselves.
I'm not a mathematician so I try to show an example to make it clear what I need.
Word Length L = 4
Word Alphabet A = {0,1}
Word Alphabet Size |A| = 2
Word Min. Hamming Dist. H = 2
The first word is
w0 = {0,0,0,0}
Now the other words could be:
w1 = {0,0,1,1}
w2 = {1,1,0,0}
And hamming distances are
Hamming(w0,w1) = 2 >= H
Hamming(w0,w2) = 2 >= H
Hamming(w1,w2) = 4 >= H
As you see, all hamming distances are equal or greater H.
For my purpose I would need L=512 and A={0,1} and |A|=2 and H=70.
How can I calculate this all without brute force / try and error?
Below is some ugly quick hack code which is ultimately slow. How to get this lightning fast?
// std header(s)
#include <array>
#include <algorithm>
#include <iostream>
#include <cmath>
#include <iterator>
#include <random>
#include <chrono>
#include <boost/iterator/zip_iterator.hpp>
#include <boost/tuple/tuple.hpp>
#include <boost/tuple/tuple_comparison.hpp>
#include <bitset>
#include <fstream>
#include <iostream>
class Hamming {
public:
Hamming(int & _distance) : distance_(_distance) {};
void operator() ( boost::tuple<int, int> const & words) {
if(boost::get<0>(words)!=boost::get<1>(words)) {
std::bitset<4> n=boost::get<0>(words);
std::bitset<4> m=boost::get<1>(words);
distance_+=(n ^ m).count();
}
}
private:
int & distance_;
};
int main(int argc,char** argv) {
const int arraysize=61;
std::array<int,arraysize> a;
int distance=0;
int num;
std::cout << "Input number of bag_words"<<std::endl;;
std::cin>>num;
std::vector<std::array<int, arraysize>> bag;
Hamming myobject(distance);
////
std::mt19937 mt(std::chrono::high_resolution_clock::now().time_since_epoch().count());
std::uniform_int_distribution<int> d(0, 255);
std::generate(a.begin(),a.end(),[&]{return d(mt);});
bag.push_back(a);
int counter=1;
while (counter<num) {
std::generate(a.begin(),a.end(),[&]{return d(mt);});
int test=0;
distance=0;
for (int i=0 ; i<counter ; i++) {
std::for_each(
boost::make_zip_iterator(
boost::make_tuple(a.begin(), bag[i].begin())
),
boost::make_zip_iterator(
boost::make_tuple(a.end(), bag[i].end())
),
Hamming(distance)
);
if(distance>10) {
++test;
}
else break;
}
if (test==counter) {
bag.push_back(a);
++counter;
}
}
std::cout << std::endl;
std::ofstream myfile ("example.txt");
if (myfile.is_open()) {
for(int i = 0; i < counter; i ++) {
for (int j=0 ; j<arraysize ; j++) {
myfile << bag[i][j] << " " ;
}
myfile << "\n";
}
myfile.close();
}
else std::cout << "Unable to open file";
}

boost zip_iterator and std::sort

I have two arrays values and keys both of the same length.
I want to sort-by-key the values array using the keys array as keys.
I have been told the boost's zip iterator is just the right tool for locking two arrays together and doing stuff to them at the same time.
Here is my attempt at using the boost::zip_iterator to solve sorting problem which fails to compile with gcc. Can someone help me fix this code?
The problem lies in the line
std::sort ( boost::make_zip_iterator( keys, values ), boost::make_zip_iterator( keys+N , values+N ));
#include <iostream>
#include <iomanip>
#include <cstdlib>
#include <ctime>
#include <vector>
#include <algorithm>
#include <boost/iterator/zip_iterator.hpp>
#include <boost/tuple/tuple.hpp>
#include <boost/tuple/tuple_comparison.hpp>
int main(int argc, char *argv[])
{
int N=10;
int keys[N];
double values[N];
int M=100;
//Create the vectors.
for (int i = 0; i < N; ++i)
{
keys[i] = rand()%M;
values[i] = 1.0*rand()/RAND_MAX;
}
//Now we use the boost zip iterator to zip the two vectors and sort them "simulatneously"
//I want to sort-by-key the keys and values arrays
std::sort ( boost::make_zip_iterator( keys, values ),
boost::make_zip_iterator( keys+N , values+N )
);
//The values array and the corresponding keys in ascending order.
for (int i = 0; i < N; ++i)
{
std::cout << keys[i] << "\t" << values[i] << std::endl;
}
return 0;
}
NOTE:Error message on compilation
g++ -g -Wall boost_test.cpp
boost_test.cpp: In function ‘int main(int, char**)’:
boost_test.cpp:37:56: error: no matching function for call to ‘make_zip_iterator(int [(((unsigned int)(((int)N) + -0x00000000000000001)) + 1)], double [(((unsigned int)(((int)N) + -0x00000000000000001)) + 1)])’
boost_test.cpp:38:64: error: no matching function for call to ‘make_zip_iterator(int*, double*)’
You can't sort a pair of zip_iterators.
Firstly, make_zip_iterator takes a tuple of iterators as input, so you could call:
boost::make_zip_iterator(boost::make_tuple( ... ))
but that won't compile either, because keys and keys+N doesn't have the same type. We need to force keys to become a pointer:
std::sort(boost::make_zip_iterator(boost::make_tuple(+keys, +values)),
boost::make_zip_iterator(boost::make_tuple(keys+N, values+N)));
this will compile, but the sorted result is still wrong, because a zip_iterator only models a Readable iterator, but std::sort also needs the input to be Writable as described here, so you can't sort using zip_iterator.
A very good discussion of this problem can be found here: https://web.archive.org/web/20120422174751/http://www.stanford.edu/~dgleich/notebook/2006/03/sorting_two_arrays_simultaneou.html
Here's a possible duplicate of this question: Sorting zipped (locked) containers in C++ using boost or the STL
The approach in the link above uses std::sort, and no extra space. It doesn't employ boost::zip_iterator, just boost tuples and the boost iterator facade. Std::tuples should also work if you have an up to date compiler.
If you are happy to have one extra vector (of size_t elements), then the following approach will work in ~ o(n log n) time average case. It's fairly simple, but there will be better approaches out there if you search for them.
#include <vector>
#include <iostream>
#include <algorithm>
#include <iterator>
using namespace std;
template <typename T1, typename T2>
void sortByPerm(vector<T1>& list1, vector<T2>& list2) {
const auto len = list1.size();
if (!len || len != list2.size()) throw;
// create permutation vector
vector<size_t> perms;
for (size_t i = 0; i < len; i++) perms.push_back(i);
sort(perms.begin(), perms.end(), [&](T1 a, T1 b){ return list1[a] < list1[b]; });
// order input vectors by permutation
for (size_t i = 0; i < len - 1; i++) {
swap(list1[i], list1[perms[i]]);
swap(list2[i], list2[perms[i]]);
// adjust permutation vector if required
if (i < perms[i]) {
auto d = distance(perms.begin(), find(perms.begin() + i, perms.end(), i));
swap(perms[i], perms[d]);
}
}
}
int main() {
vector<int> ints = {32, 12, 40, 8, 9, 15};
vector<double> doubles = {55.1, 33.3, 66.1, 11.1, 22.1, 44.1};
sortByPerm(ints, doubles);
copy(ints.begin(), ints.end(), ostream_iterator<int>(cout, " ")); cout << endl;
copy(doubles.begin(), doubles.end(), ostream_iterator<double>(cout, " ")); cout << endl;
}
After seeing another of your comments in another answer.
I though I would enlighten you to the std::map. This is a key value container, that preserves key order. (it is basically a binary tree, usually red black tree, but that isn't important).
size_t elements=10;
std::map<int, double> map_;
for (size_t i = 0; i < 10; ++i)
{
map_[rand()%M]=1.0*rand()/RAND_MAX;
}
//for every element in map, if you have C++11 this can be much cleaner
for (std::map<int,double>::const_iterator it=map_.begin();
it!=map_.end(); ++it)
{
std::cout << it->first << "\t" << it->second << std::endl;
}
untested, but any error should be simple syntax errors
boost::make_zip_iterator take a boost::tuple.
#include <boost/iterator/zip_iterator.hpp>
#include <boost/tuple/tuple.hpp>
#include <boost/tuple/tuple_comparison.hpp>
#include <iostream>
#include <iomanip>
#include <cstdlib>
#include <ctime>
#include <vector>
#include <algorithm>
int main(int argc, char *argv[])
{
std::vector<int> keys(10); //lets not waste time with arrays
std::vector<double> values(10);
const int M=100;
//Create the vectors.
for (size_t i = 0; i < values.size(); ++i)
{
keys[i] = rand()%M;
values[i] = 1.0*rand()/RAND_MAX;
}
//Now we use the boost zip iterator to zip the two vectors and sort them "simulatneously"
//I want to sort-by-key the keys and values arrays
std::sort ( boost::make_zip_iterator(
boost::make_tuple(keys.begin(), values.begin())),
boost::make_zip_iterator(
boost::make_tuple(keys.end(), values.end()))
);
//The values array and the corresponding keys in ascending order.
for (size_t i = 0; i < values.size(); ++i)
{
std::cout << keys[i] << "\t" << values[i] << std::endl;
}
return 0;
}

Performance penalty using 'auto' keyword in Visual Studio 2010

Using the new auto keyword has degraded my code execution times. I narrowed the problem to the following simple code snippet:
#include <iostream>
#include <map>
#include <vector>
#include <deque>
#include <time.h>
using namespace std;
void func1(map<int, vector<deque<float>>>& m)
{
vector<deque<float>>& v = m[1];
}
void func2(map<int, vector<deque<float>>>& m)
{
auto v = m[1];
}
void main () {
map<int, vector<deque<float>>> m;
m[1].push_back(deque<float>(1000,1));
clock_t begin=clock();
for(int i = 0; i < 100000; ++i) func1(m);
cout << "100000 x func1: " << (((double)(clock() - begin))/CLOCKS_PER_SEC) << " sec." << endl;
begin=clock();
for(int i = 0; i < 100000; ++i) func2(m);
cout << "100000 x func2: " << (((double)(clock() - begin))/CLOCKS_PER_SEC) << " sec." << endl;
}
The output I get on my i7 / Win7 machine (Release mode; VS2010) is:
100000 x func1: 0.001 sec.
100000 x func2: 3.484 sec.
Can anyone explain why using auto results in such a different execution times?
Obviously, there is a simple workaround, i.e., stop using auto altogether, but I hope there is a better way to overcome this issue.
You are copying the vector to v.
Try this instead to create a reference
auto& v = ...
As Bo said, you have to use auto& instead of auto (Note, that there is also auto* for other cases). Here is an updated version of your code:
#include <functional>
#include <iostream>
#include <map>
#include <vector>
#include <deque>
#include <time.h>
using namespace std;
typedef map<int, vector<deque<float>>> FooType; // this should have a meaningful name
void func1(FooType& m)
{
vector<deque<float>>& v = m[1];
}
void func2(FooType& m)
{
auto v = m[1];
}
void func3(FooType& m)
{
auto& v = m[1];
}
void measure_time(std::function<void(FooType&)> func, FooType& m)
{
clock_t begin=clock();
for(int i = 0; i < 100000; ++i) func(m);
cout << "100000 x func: " << (((double)(clock() - begin))/CLOCKS_PER_SEC) << " sec." << endl;
}
void main()
{
FooType m;
m[1].push_back(deque<float>(1000,1));
measure_time(func1, m);
measure_time(func2, m);
measure_time(func3, m);
}
On my computer, it gives the following output:
100000 x func: 0 sec.
100000 x func: 3.136 sec.
100000 x func: 0 sec.