Skip to main content
added 4056 characters in body
Source Link

EDIT: bugfix - (O3N) time with zero check:

#include <numeric>
#include <array>
#include <vector>
#include <iostream>

namespace notstd {

    template<class T>
    auto to_vector(std::initializer_list<T> il) {
        return std::vector<T>(il);
    }
}

static constexpr struct {
    template<class Iter>
    void operator()(Iter first, Iter last) const {
        if (first != last) {
            auto zeros = std::count(first, last, 0);
            switch (zeros) {
                case 0: {
                    auto accum = std::accumulate(std::next(first), last,
                                                 *first, std::multiplies<>());
                    std::transform(first, last,
                                   first,
                                   [accum](auto &&v) {
                                       return accum / v;
                                   });
                }
                    break;

                case 1: {
                    auto maybe_multiply = [](auto &&x, auto &&y) { return y == 0 ? x : x * y; };
                    auto accum = std::accumulate(first, last,
                                                 1, maybe_multiply);
                    std::transform(first, last,
                                   first,
                                   [accum](auto &&v) {
                                       if (v == 0)
                                           return accum;
                                       else
                                           return 0;
                                   });
                }
                    break;

                default: {
                    std::fill(first, last, 0);
                } break;
            }

        }
    }
} other_products {};

template<class Container, class Algo>
auto mutate_copy(Container c, Algo algo) {
    algo(std::begin(c), std::end(c));
    return c;
};

template<class T, class Algo>
auto mutate_copy(std::initializer_list<T> il, Algo &&algo) {
    return mutate_copy(notstd::to_vector(il),
                       std::forward<Algo>(algo));
};

template<class T, std::size_t N, class Algo>
auto mutate_copy(std::array<T, N> const &a, Algo &&algo) {
    return mutate_copy(std::vector<T>(a.begin(), a.end()),
                       std::forward<Algo>(algo));
};

template<class Container, class Algo>
auto &mutate_inplace(Container &c, Algo algo) {
    algo(std::begin(c), std::end(c));
    return c;
};

template<class Container>
std::ostream &emit(std::ostream &os, Container &&c) {
    auto impl = [&os](auto first, auto last) {
        using value_type = typename std::iterator_traits<decltype(first)>::value_type;
        std::copy(first, last,
                  std::ostream_iterator<value_type>(os, ", "));
    };
    impl(std::begin(c), std::end(c));
    return os;
}


int main() {

    emit(std::cout, mutate_copy({1, 2, 0, 4, 5}, other_products)) << std::endl;
    emit(std::cout, mutate_copy({2, 3, 4, 5, 6}, other_products)) << std::endl;
    emit(std::cout, mutate_copy({6, 5, 4, 3, 2}, other_products)) << std::endl;

    std::array<int, 5> ar{10, 20, 30, 40, 50};
    emit(std::cout, mutate_copy(ar, other_products)) << std::endl;
    emit(std::cout, mutate_inplace(ar, other_products)) << std::endl;


    auto in = std::vector<int> {10, 11, 12, 13, 14};
    emit(std::cout, mutate_copy(in, other_products)) << std::endl;

    std::vector<int> foo{};
    emit(std::cout, mutate_inplace(foo, other_products)) << std::endl;
}

previous code:

EDIT: bugfix - (O3N) time with zero check:

#include <numeric>
#include <array>
#include <vector>
#include <iostream>

namespace notstd {

    template<class T>
    auto to_vector(std::initializer_list<T> il) {
        return std::vector<T>(il);
    }
}

static constexpr struct {
    template<class Iter>
    void operator()(Iter first, Iter last) const {
        if (first != last) {
            auto zeros = std::count(first, last, 0);
            switch (zeros) {
                case 0: {
                    auto accum = std::accumulate(std::next(first), last,
                                                 *first, std::multiplies<>());
                    std::transform(first, last,
                                   first,
                                   [accum](auto &&v) {
                                       return accum / v;
                                   });
                }
                    break;

                case 1: {
                    auto maybe_multiply = [](auto &&x, auto &&y) { return y == 0 ? x : x * y; };
                    auto accum = std::accumulate(first, last,
                                                 1, maybe_multiply);
                    std::transform(first, last,
                                   first,
                                   [accum](auto &&v) {
                                       if (v == 0)
                                           return accum;
                                       else
                                           return 0;
                                   });
                }
                    break;

                default: {
                    std::fill(first, last, 0);
                } break;
            }

        }
    }
} other_products {};

template<class Container, class Algo>
auto mutate_copy(Container c, Algo algo) {
    algo(std::begin(c), std::end(c));
    return c;
};

template<class T, class Algo>
auto mutate_copy(std::initializer_list<T> il, Algo &&algo) {
    return mutate_copy(notstd::to_vector(il),
                       std::forward<Algo>(algo));
};

template<class T, std::size_t N, class Algo>
auto mutate_copy(std::array<T, N> const &a, Algo &&algo) {
    return mutate_copy(std::vector<T>(a.begin(), a.end()),
                       std::forward<Algo>(algo));
};

template<class Container, class Algo>
auto &mutate_inplace(Container &c, Algo algo) {
    algo(std::begin(c), std::end(c));
    return c;
};

template<class Container>
std::ostream &emit(std::ostream &os, Container &&c) {
    auto impl = [&os](auto first, auto last) {
        using value_type = typename std::iterator_traits<decltype(first)>::value_type;
        std::copy(first, last,
                  std::ostream_iterator<value_type>(os, ", "));
    };
    impl(std::begin(c), std::end(c));
    return os;
}


int main() {

    emit(std::cout, mutate_copy({1, 2, 0, 4, 5}, other_products)) << std::endl;
    emit(std::cout, mutate_copy({2, 3, 4, 5, 6}, other_products)) << std::endl;
    emit(std::cout, mutate_copy({6, 5, 4, 3, 2}, other_products)) << std::endl;

    std::array<int, 5> ar{10, 20, 30, 40, 50};
    emit(std::cout, mutate_copy(ar, other_products)) << std::endl;
    emit(std::cout, mutate_inplace(ar, other_products)) << std::endl;


    auto in = std::vector<int> {10, 11, 12, 13, 14};
    emit(std::cout, mutate_copy(in, other_products)) << std::endl;

    std::vector<int> foo{};
    emit(std::cout, mutate_inplace(foo, other_products)) << std::endl;
}

previous code:

added 3102 characters in body
Source Link

As a further refinement, I had a go are separating the concerns of 'in-place' or 'copy' operations from the actual mutating algorithm.

See what you think:

#include <numeric>
#include <array>
#include <vector>
#include <iostream>
#include <algorithm>
#include <functional>
#include <iterator>
#include <initializer_list>

namespace notstd {

    template<class T>
    auto to_vector(std::initializer_list<T> il)
    {
        return std::vector<T>(il);
    }
}

static constexpr struct
{
    template<class Iter>
    void operator()(Iter first, Iter last) const
    {
        if (first != last) {
            auto accum = std::accumulate(std::next(first), last,
                                         *first, std::multiplies<>());
            std::transform(first, last,
                           first,
                           [accum](auto&& v)
                           {
                               return accum / v;
                           });
        }
    }
} other_products {};

template<class Container, class Algo>
auto mutate_copy(Container c, Algo algo)
{
    algo(std::begin(c), std::end(c));
    return c;
};

template<class T, class Algo>
auto mutate_copy(std::initializer_list<T> il, Algo&& algo)
{
    return mutate_copy(notstd::to_vector(il),
                       std::forward<Algo>(algo));
};

template<class T, std::size_t N, class Algo>
auto mutate_copy(std::array<T, N> const& a, Algo&& algo)
{
    return mutate_copy(std::vector<T>(a.begin(), a.end()),
                       std::forward<Algo>(algo));
};

template<class Container, class Algo>
auto& mutate_inplace(Container& c, Algo algo)
{
    algo(std::begin(c), std::end(c));
    return c;
};

template<class Container>
std::ostream& emit(std::ostream& os, Container&& c)
{
    auto impl = [&os](auto first, auto last)
    {
        using value_type = typename std::iterator_traits<decltype(first)>::value_type;
        std::copy(first, last,
                  std::ostream_iterator<value_type>(os, ", "));
    };
    impl(std::begin(c), std::end(c));
    return os;
}


int main()
{

    emit(std::cout, mutate_copy({1, 2, 3, 4, 5}, other_products)) << std::endl;
    emit(std::cout, mutate_copy({2, 3, 4, 5, 6}, other_products)) << std::endl;
    emit(std::cout, mutate_copy({6, 5, 4, 3, 2}, other_products)) << std::endl;

    std::array<int, 5> ar { 10, 20, 30 , 40, 50 };
    emit(std::cout, mutate_copy(ar, other_products)) << std::endl;
    emit(std::cout, mutate_inplace(ar, other_products)) << std::endl;


    auto in = std::vector<int> {10, 11, 12, 13, 14};
    emit(std::cout, mutate_copy(in, other_products)) << std::endl;
}

As a further refinement, I had a go are separating the concerns of 'in-place' or 'copy' operations from the actual mutating algorithm.

See what you think:

#include <numeric>
#include <array>
#include <vector>
#include <iostream>
#include <algorithm>
#include <functional>
#include <iterator>
#include <initializer_list>

namespace notstd {

    template<class T>
    auto to_vector(std::initializer_list<T> il)
    {
        return std::vector<T>(il);
    }
}

static constexpr struct
{
    template<class Iter>
    void operator()(Iter first, Iter last) const
    {
        if (first != last) {
            auto accum = std::accumulate(std::next(first), last,
                                         *first, std::multiplies<>());
            std::transform(first, last,
                           first,
                           [accum](auto&& v)
                           {
                               return accum / v;
                           });
        }
    }
} other_products {};

template<class Container, class Algo>
auto mutate_copy(Container c, Algo algo)
{
    algo(std::begin(c), std::end(c));
    return c;
};

template<class T, class Algo>
auto mutate_copy(std::initializer_list<T> il, Algo&& algo)
{
    return mutate_copy(notstd::to_vector(il),
                       std::forward<Algo>(algo));
};

template<class T, std::size_t N, class Algo>
auto mutate_copy(std::array<T, N> const& a, Algo&& algo)
{
    return mutate_copy(std::vector<T>(a.begin(), a.end()),
                       std::forward<Algo>(algo));
};

template<class Container, class Algo>
auto& mutate_inplace(Container& c, Algo algo)
{
    algo(std::begin(c), std::end(c));
    return c;
};

template<class Container>
std::ostream& emit(std::ostream& os, Container&& c)
{
    auto impl = [&os](auto first, auto last)
    {
        using value_type = typename std::iterator_traits<decltype(first)>::value_type;
        std::copy(first, last,
                  std::ostream_iterator<value_type>(os, ", "));
    };
    impl(std::begin(c), std::end(c));
    return os;
}


int main()
{

    emit(std::cout, mutate_copy({1, 2, 3, 4, 5}, other_products)) << std::endl;
    emit(std::cout, mutate_copy({2, 3, 4, 5, 6}, other_products)) << std::endl;
    emit(std::cout, mutate_copy({6, 5, 4, 3, 2}, other_products)) << std::endl;

    std::array<int, 5> ar { 10, 20, 30 , 40, 50 };
    emit(std::cout, mutate_copy(ar, other_products)) << std::endl;
    emit(std::cout, mutate_inplace(ar, other_products)) << std::endl;


    auto in = std::vector<int> {10, 11, 12, 13, 14};
    emit(std::cout, mutate_copy(in, other_products)) << std::endl;
}
bugfix: universal reference on templat container version to remove un-necessary copy
Source Link
#include <numeric>
#include <vector>
#include <iostream>
#include <algorithm>
#include <functional>
#include <iterator>

template<class Iter>
auto other_products(Iter first, Iter last)
{
    using type = typename std::iterator_traits<Iter>::value_type;
    auto mega_product = std::accumulate(first, last, 
                                        type(1), std::multiplies<>());

    std::vector<type> result;
    result.reserve(std::distance(first, last));
    std::transform(first, last,
                   std::back_inserter(result),
                   [mega_product](auto&& v)
                   {
                       return mega_product / v;
                   });
    return result;
}

//
// convenience specialisation for any container
//
template<class Container>
auto other_products(ContainerContainer&& c)
{
    return other_products(std::begin(c), std::end(c));
}

template<class Value>
auto other_products(std::initializer_list<Value> c)
{
    return other_products(std::begin(c), std::end(c));
}

template<class Container>
std::ostream& emit(std::ostream& os, Container&& c)
{
    auto impl = [&os](auto first, auto last)
    {
        using value_type = typename std::iterator_traits<decltype(first)>::value_type;
        std::copy(first, last, 
                  std::ostream_iterator<value_type>(os, ", "));
    };
    impl(std::begin(c), std::end(c));
    return os;
}

int main()
{

    emit(std::cout, other_products({1, 2, 3, 4, 5})) << std::endl;
    emit(std::cout, other_products({2, 3, 4, 5, 6})) << std::endl;
    emit(std::cout, other_products({6, 5, 4, 3, 2})) << std::endl;

    auto in = std::vector<int> { 10, 11, 12, 13, 14 };
    emit(std::cout, other_products(in)) << std::endl;

}
#include <numeric>
#include <vector>
#include <iostream>
#include <algorithm>
#include <functional>
#include <iterator>

template<class Iter>
auto other_products(Iter first, Iter last)
{
    using type = typename std::iterator_traits<Iter>::value_type;
    auto mega_product = std::accumulate(first, last, 
                                        type(1), std::multiplies<>());

    std::vector<type> result;
    result.reserve(std::distance(first, last));
    std::transform(first, last,
                   std::back_inserter(result),
                   [mega_product](auto&& v)
                   {
                       return mega_product / v;
                   });
    return result;
}

//
// convenience specialisation for any container
//
template<class Container>
auto other_products(Container c)
{
    return other_products(std::begin(c), std::end(c));
}

template<class Value>
auto other_products(std::initializer_list<Value> c)
{
    return other_products(std::begin(c), std::end(c));
}

template<class Container>
std::ostream& emit(std::ostream& os, Container&& c)
{
    auto impl = [&os](auto first, auto last)
    {
        using value_type = typename std::iterator_traits<decltype(first)>::value_type;
        std::copy(first, last, 
                  std::ostream_iterator<value_type>(os, ", "));
    };
    impl(std::begin(c), std::end(c));
    return os;
}

int main()
{

    emit(std::cout, other_products({1, 2, 3, 4, 5})) << std::endl;
    emit(std::cout, other_products({2, 3, 4, 5, 6})) << std::endl;
    emit(std::cout, other_products({6, 5, 4, 3, 2})) << std::endl;

    auto in = std::vector<int> { 10, 11, 12, 13, 14 };
    emit(std::cout, other_products(in)) << std::endl;

}
#include <numeric>
#include <vector>
#include <iostream>
#include <algorithm>
#include <functional>
#include <iterator>

template<class Iter>
auto other_products(Iter first, Iter last)
{
    using type = typename std::iterator_traits<Iter>::value_type;
    auto mega_product = std::accumulate(first, last, 
                                        type(1), std::multiplies<>());

    std::vector<type> result;
    result.reserve(std::distance(first, last));
    std::transform(first, last,
                   std::back_inserter(result),
                   [mega_product](auto&& v)
                   {
                       return mega_product / v;
                   });
    return result;
}

//
// convenience specialisation for any container
//
template<class Container>
auto other_products(Container&& c)
{
    return other_products(std::begin(c), std::end(c));
}

template<class Value>
auto other_products(std::initializer_list<Value> c)
{
    return other_products(std::begin(c), std::end(c));
}

template<class Container>
std::ostream& emit(std::ostream& os, Container&& c)
{
    auto impl = [&os](auto first, auto last)
    {
        using value_type = typename std::iterator_traits<decltype(first)>::value_type;
        std::copy(first, last, 
                  std::ostream_iterator<value_type>(os, ", "));
    };
    impl(std::begin(c), std::end(c));
    return os;
}

int main()
{

    emit(std::cout, other_products({1, 2, 3, 4, 5})) << std::endl;
    emit(std::cout, other_products({2, 3, 4, 5, 6})) << std::endl;
    emit(std::cout, other_products({6, 5, 4, 3, 2})) << std::endl;

    auto in = std::vector<int> { 10, 11, 12, 13, 14 };
    emit(std::cout, other_products(in)) << std::endl;

}
Source Link
Loading