xset_operation.hpp 7.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213
  1. /***************************************************************************
  2. * Copyright (c) Johan Mabille, Sylvain Corlay and Wolf Vollprecht *
  3. * Copyright (c) QuantStack *
  4. * *
  5. * Distributed under the terms of the BSD 3-Clause License. *
  6. * *
  7. * The full license is in the file LICENSE, distributed with this software. *
  8. ****************************************************************************/
  9. #ifndef XTENSOR_XSET_OPERATION_HPP
  10. #define XTENSOR_XSET_OPERATION_HPP
  11. #include <algorithm>
  12. #include <functional>
  13. #include <type_traits>
  14. #include <xtl/xsequence.hpp>
  15. #include "xfunction.hpp"
  16. #include "xmath.hpp"
  17. #include "xscalar.hpp"
  18. #include "xstrided_view.hpp"
  19. #include "xstrides.hpp"
  20. #include "xutils.hpp"
  21. namespace xt
  22. {
  23. namespace detail
  24. {
  25. template <bool lvalue>
  26. struct lambda_isin
  27. {
  28. template <class E>
  29. static auto make(E&& e)
  30. {
  31. return [&e](const auto& t)
  32. {
  33. return std::find(e.begin(), e.end(), t) != e.end();
  34. };
  35. }
  36. };
  37. template <>
  38. struct lambda_isin<false>
  39. {
  40. template <class E>
  41. static auto make(E&& e)
  42. {
  43. return [e](const auto& t)
  44. {
  45. return std::find(e.begin(), e.end(), t) != e.end();
  46. };
  47. }
  48. };
  49. }
  50. /**
  51. * @ingroup logical_operators
  52. * @brief isin
  53. *
  54. * Returns a boolean array of the same shape as ``element`` that is ``true`` where an element of
  55. * ``element`` is in ``test_elements`` and ``False`` otherwise.
  56. * @param element an \ref xexpression
  57. * @param test_elements an array
  58. * @return a boolean array
  59. */
  60. template <class E, class T>
  61. inline auto isin(E&& element, std::initializer_list<T> test_elements) noexcept
  62. {
  63. auto lambda = [test_elements](const auto& t)
  64. {
  65. return std::find(test_elements.begin(), test_elements.end(), t) != test_elements.end();
  66. };
  67. return make_lambda_xfunction(std::move(lambda), std::forward<E>(element));
  68. }
  69. /**
  70. * @ingroup logical_operators
  71. * @brief isin
  72. *
  73. * Returns a boolean array of the same shape as ``element`` that is ``true`` where an element of
  74. * ``element`` is in ``test_elements`` and ``False`` otherwise.
  75. * @param element an \ref xexpression
  76. * @param test_elements an array
  77. * @return a boolean array
  78. */
  79. template <class E, class F, class = typename std::enable_if_t<has_iterator_interface<F>::value>>
  80. inline auto isin(E&& element, F&& test_elements) noexcept
  81. {
  82. auto lambda = detail::lambda_isin<std::is_lvalue_reference<F>::value>::make(std::forward<F>(test_elements
  83. ));
  84. return make_lambda_xfunction(std::move(lambda), std::forward<E>(element));
  85. }
  86. /**
  87. * @ingroup logical_operators
  88. * @brief isin
  89. *
  90. * Returns a boolean array of the same shape as ``element`` that is ``true`` where an element of
  91. * ``element`` is in ``test_elements`` and ``False`` otherwise.
  92. * @param element an \ref xexpression
  93. * @param test_elements_begin iterator to the beginning of an array
  94. * @param test_elements_end iterator to the end of an array
  95. * @return a boolean array
  96. */
  97. template <class E, class I, class = typename std::enable_if_t<is_iterator<I>::value>>
  98. inline auto isin(E&& element, I&& test_elements_begin, I&& test_elements_end) noexcept
  99. {
  100. auto lambda = [&test_elements_begin, &test_elements_end](const auto& t)
  101. {
  102. return std::find(test_elements_begin, test_elements_end, t) != test_elements_end;
  103. };
  104. return make_lambda_xfunction(std::move(lambda), std::forward<E>(element));
  105. }
  106. /**
  107. * @ingroup logical_operators
  108. * @brief in1d
  109. *
  110. * Returns a boolean array of the same shape as ``element`` that is ``true`` where an element of
  111. * ``element`` is in ``test_elements`` and ``False`` otherwise.
  112. * @param element an \ref xexpression
  113. * @param test_elements an array
  114. * @return a boolean array
  115. */
  116. template <class E, class T>
  117. inline auto in1d(E&& element, std::initializer_list<T> test_elements) noexcept
  118. {
  119. XTENSOR_ASSERT(element.dimension() == 1ul);
  120. return isin(std::forward<E>(element), std::forward<std::initializer_list<T>>(test_elements));
  121. }
  122. /**
  123. * @ingroup logical_operators
  124. * @brief in1d
  125. *
  126. * Returns a boolean array of the same shape as ``element`` that is ``true`` where an element of
  127. * ``element`` is in ``test_elements`` and ``False`` otherwise.
  128. * @param element an \ref xexpression
  129. * @param test_elements an array
  130. * @return a boolean array
  131. */
  132. template <class E, class F, class = typename std::enable_if_t<has_iterator_interface<F>::value>>
  133. inline auto in1d(E&& element, F&& test_elements) noexcept
  134. {
  135. XTENSOR_ASSERT(element.dimension() == 1ul);
  136. XTENSOR_ASSERT(test_elements.dimension() == 1ul);
  137. return isin(std::forward<E>(element), std::forward<F>(test_elements));
  138. }
  139. /**
  140. * @ingroup logical_operators
  141. * @brief in1d
  142. *
  143. * Returns a boolean array of the same shape as ``element`` that is ``true`` where an element of
  144. * ``element`` is in ``test_elements`` and ``False`` otherwise.
  145. * @param element an \ref xexpression
  146. * @param test_elements_begin iterator to the beginning of an array
  147. * @param test_elements_end iterator to the end of an array
  148. * @return a boolean array
  149. */
  150. template <class E, class I, class = typename std::enable_if_t<is_iterator<I>::value>>
  151. inline auto in1d(E&& element, I&& test_elements_begin, I&& test_elements_end) noexcept
  152. {
  153. XTENSOR_ASSERT(element.dimension() == 1ul);
  154. return isin(
  155. std::forward<E>(element),
  156. std::forward<I>(test_elements_begin),
  157. std::forward<I>(test_elements_end)
  158. );
  159. }
  160. /**
  161. * @ingroup searchsorted
  162. * @brief Find indices where elements should be inserted to maintain order.
  163. *
  164. * @param a Input array: sorted (array_like).
  165. * @param v Values to insert into a (array_like).
  166. * @param right If ``false``, the index of the first suitable location found is given.
  167. * @return Array of insertion points with the same shape as v.
  168. */
  169. template <class E1, class E2>
  170. inline auto searchsorted(E1&& a, E2&& v, bool right = true)
  171. {
  172. XTENSOR_ASSERT(std::is_sorted(a.cbegin(), a.cend()));
  173. auto out = xt::empty<size_t>(v.shape());
  174. if (right)
  175. {
  176. for (size_t i = 0; i < v.size(); ++i)
  177. {
  178. out(i) = static_cast<std::size_t>(std::lower_bound(a.cbegin(), a.cend(), v(i)) - a.cbegin());
  179. }
  180. }
  181. else
  182. {
  183. for (size_t i = 0; i < v.size(); ++i)
  184. {
  185. out(i) = static_cast<std::size_t>(std::upper_bound(a.cbegin(), a.cend(), v(i)) - a.cbegin());
  186. }
  187. }
  188. return out;
  189. }
  190. }
  191. #endif