Initialize multiple dimension array - c++

How can I initialize array with variables like int x[row][col];
int myArray[7][4] = { {1,2,3,4}, {5,6,7,8}, {5,6,7,8}, {5,6,7,8}, {5,6,7,8}, {5,6,7,8}, {5,6,7,8} };
i want to initialize array as this =
int myarray({2,3,4},{12,4,5},{2,2,2})

The exact answer is you cannot initialize an array like that, i.e., without providing both row and col at compile time, though std::vector can do the job for you.
You can use some code like this:
#include <iostream>
#include <vector>
void print_vector(std::vector<int> &v) {
std::cout << "{ ";
for (auto &&i : v) {
std::cout << i;
if (&i != &v.back()) {
std::cout << ",";
}
}
std::cout << " }";
}
void print_matrix(std::vector<std::vector<int>> &v) {
std::cout << "{ ";
for (auto &&i : v) {
print_vector(i);
if (&i != &v.back()) {
std::cout << ", ";
}
}
std::cout << " }" << std::endl;
}
int main() {
std::vector<std::vector<int>> v = {{1, 2, 3, 4}, {5, 6, 7, 8}, {9, 10, 11, 12}};
// same as std::vector<std::vector<int>> v({{1, 2, 3, 4}, {5, 6, 7, 8}, {9, 10, 11, 12}});
print_matrix(v);
// prints { { 1,2,3,4 }, { 5,6,7,8 }, { 9,10,11,12 } } on stdout
}
I have included print_vector and print_matrix since the OP asked about them in the comments, though without thinking much about them. You can get better implementations on this thread.

Related

Sorting template array using std::sort

#include <algorithm>
#include <array>
#include <iostream>
int main() {
std::array<int, 10> s{5, 7, 4, 2, 8, 6, 1, 9, 0, 3};
struct {
bool operator()(int a, int b) const
{
return a < b;
}
} customLess;
std::sort(s.begin(), s.end(), customLess);
for (auto a : s) {
std::cout << a << " ";
}
std::cout << '\n';
return 0;
}
I want to sort the array using std : : sort. The code above works fine, but when I try with template array in my main task (GArr<int, 5> arr{5, 2, 3, 4, 1};) the compiler gives the following
error: no match for 'operator-' (operand types are 'Iterator' and
'Iterator')|
How can I fix it?

C++ STL alogrithm like 'comm' utility

Can someone point me, please, if where is some algorithms within STL to compute difference and intersection per one call in manner of unix comm utility?
int main()
{
//For example we have two sets on input
std::set<int>a = { 1 2 3 4 5 };
std::set<int>b = { 3 4 5 6 7 };
std::call_some_func(a, b, ... );
//So as result we need obtain 3 sets
//x1 = {1, 2} // present in a, but absent in b (difference)
//x2 = {3, 4, 5} // present on both sets (intersection)
//x3 = {6, 7} // present in b, but absent in a
}
My current implementation uses 2 calls of 'std::set_difference' and one call of 'std::set_intersection'.
I think this is probably a reasonably efficient implementation:
Features:
a) operates in linear time.
b) works with all ordered container types for input and all iterator types for output.
c) only requires operator< to be defined on the contained type, as per stl algorithms on sorted ranges.
template<class I1, class I2, class I3, class I4, class ITarget1, class ITarget2, class ITarget3>
auto comm(I1 lfirst, I2 llast, I3 rfirst, I4 rlast, ITarget1 lonly, ITarget2 both, ITarget3 ronly)
{
while (lfirst != llast and rfirst != rlast)
{
auto&& l = *lfirst;
auto&& r = *rfirst;
if (l < r) *lonly++ = *lfirst++;
else if (r < l) *ronly++ = *rfirst++;
else *both++ = (++lfirst, *rfirst++);
}
while (lfirst != llast)
*lonly++ = *lfirst++;
while (rfirst != rlast)
*ronly++ = *rfirst++;
}
example:
#include <tuple>
#include <set>
#include <vector>
#include <unordered_set>
#include <iterator>
#include <iostream>
/// #pre l and r are ordered
template<class I1, class I2, class I3, class I4, class ITarget1, class ITarget2, class ITarget3>
auto comm(I1 lfirst, I2 llast, I3 rfirst, I4 rlast, ITarget1 lonly, ITarget2 both, ITarget3 ronly)
{
while (lfirst != llast and rfirst != rlast)
{
auto&& l = *lfirst;
auto&& r = *rfirst;
if (l < r) *lonly++ = *lfirst++;
else if (r < l) *ronly++ = *rfirst++;
else *both++ = (++lfirst, *rfirst++);
}
while (lfirst != llast)
*lonly++ = *lfirst++;
while (rfirst != rlast)
*ronly++ = *rfirst++;
}
int main()
{
//For example we have two sets on input
std::set<int>a = { 1, 2, 3, 4, 5 };
std::set<int>b = { 3, 4, 5, 6, 7 };
std::vector<int> left;
std::set<int> right;
std::unordered_set<int> both;
comm(begin(a), end(a),
begin(b), end(b),
back_inserter(left),
inserter(both, both.end()),
inserter(right, right.end()));
//So as result we need obtain 3 sets
//x1 = {1, 2} // present in a, but absent in b (difference)
//x2 = {3, 4, 5} // present on both sets (intersection)
//x3 = {6, 7} // present in b, but absent in a
std::copy(begin(left), end(left), std::ostream_iterator<int>(std::cout, ", "));
std::cout << std::endl;
std::copy(begin(both), end(both), std::ostream_iterator<int>(std::cout, ", "));
std::cout << std::endl;
std::copy(begin(right), end(right), std::ostream_iterator<int>(std::cout, ", "));
std::cout << std::endl;
}
example output (note that the 'both' target is an unordered set):
1, 2,
5, 3, 4,
6, 7,
There is no single function to do that, you'd have to call the three functions you mentioned, or write something yourself. That being said, here's my attempt, though I'm not sure it's going to be any faster than the three step method you've already described
#include <algorithm>
#include <iostream>
#include <iterator>
#include <set>
template <typename T>
void partition_sets(std::set<T> const& a,
std::set<T> const& b,
std::set<T>& difference_a,
std::set<T>& difference_b,
std::set<T>& intersection)
{
std::set_intersection(begin(a), end(a),
begin(b), end(b),
std::inserter(intersection, intersection.begin()));
std::copy_if(begin(a), end(a), std::inserter(difference_a, difference_a.begin()), [&intersection](int i)
{
return intersection.find(i) == intersection.end();
});
std::copy_if(begin(b), end(b), std::inserter(difference_b, difference_b.begin()), [&intersection](int i)
{
return intersection.find(i) == intersection.end();
});
}
Running your example
int main()
{
//For example we have two sets on input
std::set<int> a = { 1, 2, 3, 4, 5 };
std::set<int> b = { 3, 4, 5, 6, 7 };
std::set<int> x1;
std::set<int> x2;
std::set<int> x3;
partition_sets(a, b, x1, x2, x3);
std::cout << "a - b\n\t";
for (int i : x1)
{
std::cout << i << " ";
}
std::cout << "\n";
std::cout << "b - a\n\t";
for (int i : x2)
{
std::cout << i << " ";
}
std::cout << "\n";
std::cout << "intersection\n\t";
for (int i : x3)
{
std::cout << i << " ";
}
}
produces the output
a - b
1 2
b - a
6 7
intersection
3 4 5
Just write a wrapper for the three calls of the algorithms.
For example
#include <iostream>
#include<tuple>
#include <set>
#include <iterator>
#include <algorithm>
template <class T>
auto comm(const std::set<T> &first, const std::set<T> &second)
{
std::tuple<std::set<T>, std::set<T>, std::set<T>> t;
std::set_difference(first.begin(), first.end(),
second.begin(), second.end(),
std::inserter(std::get<0>(t), std::get<0>(t).begin()));
std::set_intersection(first.begin(), first.end(),
second.begin(), second.end(),
std::inserter(std::get<1>(t), std::get<1>(t).begin()));
std::set_difference(second.begin(), second.end(),
first.begin(), first.end(),
std::inserter(std::get<2>(t), std::get<2>(t).begin()));
return t;
}
int main()
{
std::set<int> a = { 1, 2, 3, 4, 5 };
std::set<int> b = { 3, 4, 5, 6, 7 };
auto t = comm(a, b);
for (auto x : std::get<0>(t)) std::cout << x << ' ';
std::cout << std::endl;
for (auto x : std::get<1>(t)) std::cout << x << ' ';
std::cout << std::endl;
for (auto x : std::get<2>(t)) std::cout << x << ' ';
std::cout << std::endl;
return 0;
}
The program output is
1 2
3 4 5
6 7

Passing two arrays as arguments in a gtest

I need to write a unit test (gtest) which passes two values from arrays a[] and b[] respectively.
Example:
a[] = {40, 45, 50 ,55, 60}
b[] = {2, 3, 5, 8, 9, 11}
My test case will pass these arrays (a[],b[]) as arguments to a function.
Is there a way I can pass both the arrays into a test case ?
Expecting the arrays are static then you can pass them like the following example shows:
class ArrayTests : public UnitTest_SomeClass,
public testing::WithParamInterface<std::pair<int*, int*>>
{
};
TEST_P(ArrayTests, doSomething)
{
const auto pair = GetParam();
const auto a = pair.first;
const auto b = pair.second;
EXPECT_EQ(4, a[3]);
EXPECT_EQ(6, b[4]);
}
int a[]{ 1,2,3,4 };
int b[]{ 2,3,4,5,6 };
INSTANTIATE_TEST_CASE_P(UnitTest_SomeClass, ArrayTests, testing::Values(std::make_pair(a, b)));
You can now pass different arrays to the test:
int a0[]{ 1,2,3,4 };
int b0[]{ 2,3,4,5,6 };
int a1[]{ 7,8,9,10 };
int b1[]{ 2,3,4,5,6 };
INSTANTIATE_TEST_CASE_P(UnitTest_SomeClass, ArrayTests, testing::Values(std::make_pair(a0, b0), std::make_pair(a1, b1)));
I think it would be easier to use std::vector here for the int arrays, cause you got access to the number of elements. HTH
In case of more than 2 arrays are required.
#include "gtest/gtest.h"
using namespace std;
class MyTest : public testing::TestWithParam<tuple<vector<int>, vector<string>, vector<double>>> {
protected:
virtual void SetUp() {
cout << "{";
}
virtual void TearDown() {
cout << "}" << endl;
}
};
TEST_P(MyTest, TestP1) {
auto [p1, p2, p3] = GetParam();
for (auto v1: p1) cout << v1 << ",";
for (auto v2: p2) cout << v2 << ",";
for (auto v3: p3) cout << v3 << ",";
}
INSTANTIATE_TEST_SUITE_P(ParaGroupName,
MyTest,
testing::Values(
make_tuple(vector<int>{1, 2}, vector<string>{"a1", "b1"}, vector<double>{1., 2.}),
make_tuple(vector<int>{11, 12}, vector<string>{"a2", "b2"}, vector<double>{11., 12.})
)
);
// {1,2,a1,b1,1,2,}
// {11,12,a2,b2,11,12,}

Convert a time_period to a date_period

What's a good way to convert a time_period to a date_period, e.g. "2015-Apr-25 03:00:00/2015 Apr 27 05:00:00" -> "2015 Apr-25/2015 Apr 27"? I was hoping one could just use a constructor date_period(my_time_period_variable) but that does not work.
This works for me:
date_period to_date_period(time_period const& tp) {
return { tp.begin().date(), tp.end().date() };
}
Live On Coliru
#include <boost/date_time/gregorian/gregorian.hpp>
#include <boost/date_time/posix_time/time_period.hpp>
#include <boost/date_time/posix_time/posix_time_io.hpp>
using boost::posix_time::time_period;
using boost::gregorian::date_period;
date_period to_date_period(time_period const& tp) {
return { tp.begin().date(), tp.end().date() };
}
int main() {
time_period tp { { {2015, 1, 1}, {10, 13, 0} }, { {2015, 7, 13}, {23, 14, 0} } };
std::cout << tp << "\n";
std::cout << to_date_period(tp) << "\n";
}
Prints
[2015-Jan-01 10:13:00/2015-Jul-13 23:13:59.999999]
[2015-Jan-01/2015-Jul-12]

no matching function for call to ‘begin(int**&)’

I wrote a c++ program as fllow(3.43.cpp):
#include <iostream>
using std::cout;
using std::endl;
void version_1(int **arr) {
for (const int (&p)[4] : arr) {
for (int q : p) {
cout << q << " ";
}
cout << endl;
}
}
int main() {
int arr[3][4] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12};
version_1(arr);
return 0;
}
Then I compile it by using: gcc my.cpp -std=c++11, there is an error I can not deal with.
Info:
3.43.cpp:6:30: error: no matching function for call to ‘begin(int**&)’
for (const int (&p)[4] : arr) {
^
3.43.cpp:6:30: note: candidates are:
In file included from /usr/include/c++/4.8.2/bits/basic_string.h:42:0,
from /usr/include/c++/4.8.2/string:52,
from /usr/include/c++/4.8.2/bits/locale_classes.h:40,
from /usr/include/c++/4.8.2/bits/ios_base.h:41,
from /usr/include/c++/4.8.2/ios:42,
from /usr/include/c++/4.8.2/ostream:38,
from /usr/include/c++/4.8.2/iostream:39,
from 3.43.cpp:1:
/usr/include/c++/4.8.2/initializer_list:89:5: note: template<class _Tp> constexpr const _Tp* std::begin(std::initializer_list<_Tp>)
begin(initializer_list<_Tp> __ils) noexcept
I search it in google, but not find similar answer.
Since arr is just a pointer, there's no way to deduce how big it is. But, since you are actually passing in a real array, you can just template your function on its dimensions so you take the actual array by reference rather than having it decay to a pointer:
template <size_t X, size_t Y>
void foo(const int (&arr)[X][Y])
{
std::cout << "Dimensions are: " << X << "x" << Y << std::endl;
for (const int (&row)[Y] : arr) {
for (int val : row) {
std::cout << val << ' ';
}
std::cout << std::endl;
}
}
int main() {
int arr[3][4] = {{1, 2, 3, 4}, {5, 6, 7, 8}, {9, 10, 11, 12}};
foo(arr);
}
std::begin() and std::end() won't work for pointers. They only work for arrays. If you want to deduce the size of your array you'll need to pass it as a reference your function:
#include <cstddef>
template <std::size_t A, std::size_t B>
void version_1(int (&arr)[B][A]) {
for (const int (&p)[A] : arr) {
for (int q : p) {
cout << q << " ";
}
cout << '\n';
}
}
Pointers are not the same as arrays. To be able to use range based for, your container must support std::begin and std::end. Standard C arrays can be used, but not pointers.