ContainerOut adjacent_pairs(const Container& xs) { typedef typename Container::value_type T; static_assert(std::is_convertible< std::pair<T, T>, typename ContainerOut::value_type>::value, "ContainerOut can not store pairs of elements from ContainerIn."); ContainerOut result; if (size_of_cont(xs) < 2) return result; const std::size_t out_size = size_of_cont(xs) / 2; internal::prepare_container(result, out_size); auto itOut = internal::get_back_inserter(result); auto it1 = std::begin(xs); auto it2 = it1; internal::advance_iterator(it2, 1); const auto it_source_end = internal::add_to_iterator(std::begin(xs), out_size + out_size); for (;;) { *itOut = std::make_pair(*it1, *it2); internal::advance_iterator(it1, 2); if (it1 == it_source_end) break; internal::advance_iterator(it2, 2); } return result; }
Result median(const Container& xs) { assert(is_not_empty(xs)); if (size_of_cont(xs) == 1) return static_cast<Result>(xs.front()); // std::nth_element (instead of sorting) // would be faster for random-access containers // but not work at all on other containers like std::list. auto xsSorted = sort(xs); if (size_of_cont(xsSorted) % 2 == 1) { auto it = std::begin(xsSorted); internal::advance_iterator(it, size_of_cont(xsSorted) / 2); return static_cast<Result>(*it); } else { auto it1 = std::begin(xsSorted); internal::advance_iterator(it1, size_of_cont(xsSorted) / 2 - 1); auto it2 = it1; ++it2; return static_cast<Result>(*it1 + *it2) / static_cast<Result>(2); } }
auto zip_with_defaults(F f, const X& default_x, const Y& default_y, const ContainerIn1& xs, const ContainerIn2& ys) { internal::trigger_static_asserts<internal::zip_with_tag, F, X, Y>(); const auto size_xs = size_of_cont(xs); const auto size_ys = size_of_cont(ys); if (size_xs < size_ys) { const auto extended_xs = append( xs, replicate<X, ContainerIn1>(size_ys - size_xs, default_x)); return zip_with(f, extended_xs, ys); } else if (size_xs > size_ys) { const auto extended_ys = append( ys, replicate<Y, ContainerIn2>(size_xs - size_ys, default_y)); return zip_with(f, xs, extended_ys); } return zip_with(f, xs, ys); }
ContainerOut find_all_instances_of_token(const Container& token, const Container& xs) { if (size_of_cont(token) > size_of_cont(xs)) return ContainerOut(); auto itInBegin = std::begin(xs); auto itInEnd = itInBegin; internal::advance_iterator(itInEnd, size_of_cont(token)); std::size_t idx = 0; ContainerOut result; auto outIt = internal::get_back_inserter(result); std::size_t last_possible_idx = size_of_cont(xs) - size_of_cont(token); auto check_and_push = [&]() { if (std::equal(itInBegin, itInEnd, std::begin(token))) { *outIt = idx; } }; while (idx != last_possible_idx) { check_and_push(); ++itInBegin; ++itInEnd; ++idx; } check_and_push(); return result; }
maybe<std::size_t> find_first_instance_of_token (const Container& token, const Container& xs) { if (size_of_cont(token) > size_of_cont(xs)) return nothing<std::size_t>(); auto itInBegin = std::begin(xs); auto itInEnd = itInBegin; internal::advance_iterator(itInEnd, size_of_cont(token)); std::size_t idx = 0; std::size_t last_possible_idx = size_of_cont(xs) - size_of_cont(token); while (idx != last_possible_idx) { if (std::equal(itInBegin, itInEnd, std::begin(token))) { return just(idx); } ++itInBegin; ++itInEnd; ++idx; } if (std::equal(itInBegin, itInEnd, std::begin(token))) { return just(idx); } return nothing<std::size_t>(); }
bool all_unique_by_less(Compare comp, const Container& xs) { internal::check_compare_for_container<Compare, Container>(); if (size_of_cont(xs) < 2) return true; return size_of_cont(unique(sort_by(comp, xs))) == size_of_cont(xs); }
ContainerOut zip_with_3(F f, const ContainerIn1& xs, const ContainerIn2& ys, const ContainerIn3& zs) { internal::trigger_static_asserts<internal::zip_with_3_tag, F, X, Y, Z>(); static_assert(std::is_same< typename internal::same_cont_new_t<ContainerIn1, void>::type, typename internal::same_cont_new_t<ContainerIn2, void>::type>::value, "All three Containers must be of same outer type."); static_assert(std::is_same< typename internal::same_cont_new_t<ContainerIn2, void>::type, typename internal::same_cont_new_t<ContainerIn3, void>::type>::value, "All three Containers must be of same outer type."); ContainerOut result; std::size_t resultSize = std::min(size_of_cont(xs), size_of_cont(ys)); internal::prepare_container(result, resultSize); auto itResult = internal::get_back_inserter(result); auto itXs = std::begin(xs); auto itYs = std::begin(ys); auto itZs = std::begin(zs); for (std::size_t i = 0; i < resultSize; ++i) { *itResult = internal::invoke(f, *itXs, *itYs, *itZs); ++itXs; ++itYs; ++itZs; } return result; }
Z inner_product(const Z& value, const ContainerIn1& xs, const ContainerIn2& ys) { assert(size_of_cont(xs) == size_of_cont(ys)); return std::inner_product( std::begin(xs), std::end(xs), std::begin(ys), value); }
Container trim_token_left(const Container& token, const Container& xs) { auto result = xs; while (is_prefix_of(token, result)) { result = get_segment(size_of_cont(token), size_of_cont(result), result); } return result; }
auto inner_product_with(OP1 op1, OP2 op2, const Acc& value, const ContainerIn1& xs, const ContainerIn2& ys) { internal::trigger_static_asserts<internal::inner_product_with_tag, OP2, X, Y>(); internal::trigger_static_asserts<internal::inner_product_with_tag, OP1, Acc, OP2Out>(); assert(size_of_cont(xs) == size_of_cont(ys)); return std::inner_product( std::begin(xs), std::end(xs), std::begin(ys), value, op1, op2); }
std::pair<ContainerOutX, ContainerOutY> unzip(const ContainerIn& pairs) { ContainerOutX firsts; ContainerOutY seconds; internal::prepare_container(firsts, size_of_cont(pairs)); internal::prepare_container(seconds, size_of_cont(pairs)); auto itFirsts = internal::get_back_inserter(firsts); auto itSeconds = internal::get_back_inserter(seconds); for (const auto& pair : pairs) { *itFirsts = pair.first; *itSeconds = pair.second; } return std::make_pair(firsts, seconds); }
maybe<std::size_t> first_match_idx_by(F f, const ContainerIn1& xs, const ContainerIn2& ys) { auto itXs = std::begin(xs); auto itYs = std::begin(ys); std::size_t minSize = std::min(size_of_cont(xs), size_of_cont(ys)); for (std::size_t i = 0; i < minSize; ++i) { if (internal::invoke(f, *itXs, *itYs)) { return just(i); } ++itXs; ++itYs; } return nothing<std::size_t>(); }
ContainerOut zip_with(F f, const ContainerIn1& xs, const ContainerIn2& ys) { internal::trigger_static_asserts<internal::zip_with_tag, F, X, Y>(); ContainerOut result; std::size_t resultSize = std::min(size_of_cont(xs), size_of_cont(ys)); internal::prepare_container(result, resultSize); auto itResult = internal::get_back_inserter(result); auto itXs = std::begin(xs); auto itYs = std::begin(ys); for (std::size_t i = 0; i < resultSize; ++i) { *itResult = internal::invoke(f, *itXs, *itYs); ++itXs; ++itYs; } return result; }
ContainerOut infixes(std::size_t length, const ContainerIn& xs) { assert(length > 0); static_assert(std::is_convertible<ContainerIn, typename ContainerOut::value_type>::value, "ContainerOut can not take values of type ContainerIn as elements."); ContainerOut result; if (size_of_cont(xs) < length) return result; internal::prepare_container(result, size_of_cont(xs) - length); auto itOut = internal::get_back_inserter(result); for (std::size_t idx = 0; idx <= size_of_cont(xs) - length; ++idx) { *itOut = get_range(idx, idx + length, xs); } return result; }
ContainerOut adjacent_difference_by(F f, const ContainerIn& xs) { ContainerOut result; internal::prepare_container(result, size_of_cont(xs)); std::adjacent_difference(std::begin(xs), std::end(xs), back_inserter(result), f); return result; }
ContainerOut power_set(const ContainerIn& xs_in) { return concat( generate_by_idx<std::vector<ContainerOut>>( bind_1st_of_2( flip(combinations<ContainerIn, T, ContainerOut>), xs_in), size_of_cont(xs_in) + 1)); }
ContainerOut tails(const ContainerIn& xs) { ContainerOut result; std::size_t xs_size = size_of_cont(xs); internal::prepare_container(result, xs_size + 1); auto it_out = internal::get_back_inserter(result); for (std::size_t i = 0; i <= xs_size; ++i) *it_out = get_range(i, xs_size, xs); return result; }
T elem_at_idx_or_constant(const T& c, signed int idx, const Container& xs) { if (idx < 0 || idx >= static_cast<signed int>(size_of_cont(xs))) { return c; } auto it = std::begin(xs); internal::advance_iterator(it, static_cast<std::size_t>(idx)); return *it; }
bool is_subsequence_of(const Container& seq, const Container& xs) { if (is_empty(seq)) return true; if (size_of_cont(seq) > size_of_cont(xs)) return false; typedef typename Container::value_type T; auto remaining = convert_container_and_elems<std::list<T>>(seq); for (const auto& x : xs) { if (x == remaining.front()) { remaining.pop_front(); if (is_empty(remaining)) return true; } } return false; }
Result mean_using_doubles(const Container& xs) { auto size = size_of_cont(xs); assert(size != 0); auto xs_as_doubles = convert_elems<double>(xs); auto result_as_double = mean<double>(xs_as_doubles); if (!std::is_integral<Result>::value) return static_cast<Result>(result_as_double); else return round<double, Result>(result_as_double); }
maybe<std::size_t> find_last_idx_by (UnaryPredicate pred, const Container& xs) { internal::check_unary_predicate_for_container<UnaryPredicate, Container>(); auto calcRevIdx = [&](std::size_t idx) { return size_of_cont(xs) - (idx + 1); }; return lift_maybe(calcRevIdx) (find_first_idx_by(pred, reverse(xs))); }
T elem_at_idx_or_wrap(signed int idx, const Container& xs) { assert(is_not_empty(xs)); const signed int cont_size = static_cast<signed int>(size_of_cont(xs)); if (idx < 0) idx = cont_size - (std::abs(idx) % cont_size); else idx = idx % cont_size; auto it = std::begin(xs); internal::advance_iterator(it, static_cast<std::size_t>(idx)); return *it; }
ContainerOut overlapping_pairs(const Container& xs) { typedef typename Container::value_type T; static_assert(std::is_convertible< std::pair<T, T>, typename ContainerOut::value_type>::value, "ContainerOut can not store pairs of elements from ContainerIn."); ContainerOut result; if (size_of_cont(xs) < 2) return result; internal::prepare_container(result, size_of_cont(xs) - 1); auto itOut = internal::get_back_inserter(result); auto it1 = std::begin(xs); auto it2 = it1; internal::advance_iterator(it2, 1); for (; it2 != std::end(xs); ++it1, ++it2) { *itOut = std::make_pair(*it1, *it2); } return result; }
Container replace_if(UnaryPredicate p, const typename Container::value_type& dest, const Container& xs) { internal::check_unary_predicate_for_container<UnaryPredicate, Container>(); Container result; internal::prepare_container(result, size_of_cont(xs)); auto itOut = internal::get_back_inserter(result); for (const auto& x : xs) { *itOut = p(x) ? dest : x; } return result; }
Result median(const Container& xs) { assert(is_not_empty(xs)); if (size_of_cont(xs) == 1) return static_cast<Result>(xs.front()); auto xsSorted = sort(xs); if (size_of_cont(xsSorted) % 2 == 1) { auto it = std::begin(xsSorted); internal::advance_iterator(it, size_of_cont(xsSorted) / 2); return static_cast<Result>(*it); } else { auto it1 = std::begin(xsSorted); internal::advance_iterator(it1, size_of_cont(xsSorted) / 2 - 1); auto it2 = it1; ++it2; return static_cast<Result>(*it1 + *it2) / static_cast<Result>(2); } }
Container normalize_mean_stddev( const typename Container::value_type& mean, const typename Container::value_type& stddev, const Container& xs) { assert(size_of_cont(xs) != 0); typedef typename Container::value_type T; const auto mean_and_stddev = fplus::mean_stddev<T>(xs); const auto f = [&](const T& x) -> T { return mean + stddev * (x - mean_and_stddev.first) / mean_and_stddev.second; }; return fplus::transform(f, xs); }
T elem_at_idx_or_replicate(signed int idx, const Container& xs) { assert(is_not_empty(xs)); if (idx < 0) { return xs.front(); } if (idx >= static_cast<signed int>(size_of_cont(xs))) { return xs.back(); } auto it = std::begin(xs); internal::advance_iterator(it, static_cast<std::size_t>(idx)); return *it; }
Container normalize_min_max( const typename Container::value_type& lower, const typename Container::value_type& upper, const Container& xs) { assert(size_of_cont(xs) != 0); assert(lower <= upper); typedef typename Container::value_type T; const auto minmax_it_p = std::minmax_element(std::begin(xs), std::end(xs)); const T x_min = *minmax_it_p.first; const T x_max = *minmax_it_p.second; const auto f = [&](const T& x) -> T { return lower + (upper - lower) * (x - x_min) / (x_max - x_min); }; return fplus::transform(f, xs); }
Container extrapolate_wrap(std::size_t count_begin, std::size_t count_end, const Container& xs) { assert(is_not_empty(xs)); Container ys; const auto xs_size = size_of_cont(xs); internal::prepare_container(ys, xs_size + count_begin + count_end); auto it = internal::get_back_inserter<Container>(ys); const signed int idx_end = static_cast<signed int>(xs_size + count_end); const signed int idx_start = -static_cast<signed int>(count_begin); for (signed int idx = idx_start; idx < idx_end; ++idx) { *it = elem_at_idx_or_wrap(idx, xs); } return ys; }
ContainerOut find_all_instances_of_token_non_overlapping (const Container& token, const Container& xs) { auto overlapping_instances = find_all_instances_of_token<ContainerOut>( token, xs); ContainerOut result; auto outIt = internal::get_back_inserter(result); std::size_t token_size = size_of_cont(token); for (const auto idx : overlapping_instances) { if (result.empty() || result.back() + token_size <= idx) { *outIt = idx; } } return result; }