NumCpp  2.12.1
A Templatized Header Only C++ Implementation of the Python NumPy Library
insert.hpp
Go to the documentation of this file.
1
28#pragma once
29
30#include <cmath>
31#include <utility>
32#include <vector>
33
36#include "NumCpp/Core/Slice.hpp"
37#include "NumCpp/Core/Types.hpp"
39#include "NumCpp/NdArray.hpp"
40
41namespace nc
42{
43 //============================================================================
44 // Method Description:
54 template<typename dtype>
55 NdArray<dtype> insert(const NdArray<dtype>& arr, int32 index, const dtype& value)
56 {
57 const NdArray<dtype> values = { value };
58 return insert(arr, index, values);
59 }
60
61 //============================================================================
62 // Method Description:
72 template<typename dtype>
73 NdArray<dtype> insert(const NdArray<dtype>& arr, int32 index, const NdArray<dtype>& values)
74 {
75 if (index < 0)
76 {
77 index += arr.size();
78 // still
79 if (index < 0)
80 {
81 THROW_INVALID_ARGUMENT_ERROR("index out of range");
82 }
83 }
84 else if (index > static_cast<int32>(arr.size()))
85 {
86 THROW_INVALID_ARGUMENT_ERROR("index out of range");
87 }
88
89 const auto valuesSlice = Slice(index, index + values.size());
90 auto result = NdArray<dtype>(1, arr.size() + values.size());
91 result.put(valuesSlice, values);
92
93 NdArray<bool> mask(result.shape());
94 mask.fill(true);
95 mask.put(valuesSlice, false);
96 result.putMask(mask, arr.flatten());
97
98 return result;
99 }
100
101 //============================================================================
102 // Method Description:
113 template<typename dtype>
114 NdArray<dtype> insert(const NdArray<dtype>& arr, int32 index, const dtype& value, Axis axis)
115 {
116 const NdArray<dtype> values = { value };
117 return insert(arr, index, values, axis);
118 }
119
120 //============================================================================
121 // Method Description:
132 template<typename dtype>
133 NdArray<dtype> insert(const NdArray<dtype>& arr, int32 index, const NdArray<dtype>& values, Axis axis)
134 {
135 switch (axis)
136 {
137 case Axis::NONE:
138 {
139 return insert(arr, index, values);
140 }
141 case Axis::ROW:
142 {
143 if (!(values.size() == arr.numCols() || values.isscalar() || values.numCols() == arr.numCols()))
144 {
145 THROW_INVALID_ARGUMENT_ERROR("input values shape cannot be broadcast to input array dimensions");
146 }
147
148 if (index < 0)
149 {
150 index += arr.numRows();
151 // still
152 if (index < 0)
153 {
154 THROW_INVALID_ARGUMENT_ERROR("index out of range");
155 }
156 }
157 else if (index > static_cast<int32>(arr.numRows()))
158 {
159 THROW_INVALID_ARGUMENT_ERROR("index out of range");
160 }
161
162 auto result = NdArray<dtype>();
163 int32 valuesSize{};
164 if (values.size() == arr.numCols() || values.isscalar())
165 {
166 result.resizeFast(arr.numRows() + 1, arr.numCols());
167 valuesSize = 1;
168 }
169 else if (values.numCols() == arr.numCols())
170 {
171 result.resizeFast(arr.numRows() + values.numRows(), arr.numCols());
172 valuesSize = values.numRows();
173 }
174
175 auto mask = ones_like<bool>(result);
176 mask.put(Slice(index, index + valuesSize), mask.cSlice(), false);
177
178 result.putMask(mask, arr);
179 result.putMask(!mask, values);
180
181 return result;
182 }
183 case Axis::COL:
184 {
185 if (!(values.size() == arr.numRows() || values.isscalar() || values.numRows() == arr.numRows()))
186 {
187 THROW_INVALID_ARGUMENT_ERROR("input values shape cannot be broadcast to input array dimensions");
188 }
189
190 if (index < 0)
191 {
192 index += arr.numCols();
193 // still
194 if (index < 0)
195 {
196 THROW_INVALID_ARGUMENT_ERROR("index out of range");
197 }
198 }
199 else if (index > static_cast<int32>(arr.numCols()))
200 {
201 THROW_INVALID_ARGUMENT_ERROR("index out of range");
202 }
203
204 auto result = NdArray<dtype>();
205 int32 valuesSize{};
206 if (values.size() == arr.numRows() || values.isscalar())
207 {
208 result.resizeFast(arr.numRows(), arr.numCols() + 1);
209 valuesSize = 1;
210 }
211 else if (values.numRows() == arr.numRows())
212 {
213 result.resizeFast(arr.numRows(), arr.numCols() + values.numCols());
214 valuesSize = values.numCols();
215 }
216
217 auto mask = ones_like<bool>(result);
218 mask.put(mask.rSlice(), Slice(index, index + valuesSize), false);
219
220 result.putMask(mask, arr);
221 result.putMask(!mask, values);
222
223 return result;
224 }
225 default:
226 {
227 // get rid of compiler warning
228 return {};
229 }
230 }
231 }
232
233 //============================================================================
234 // Method Description:
245 template<typename dtype, typename Indices, type_traits::ndarray_int_concept<Indices> = 0>
246 NdArray<dtype> insert(const NdArray<dtype>& arr, const Indices& indices, const dtype& value, Axis axis = Axis::NONE)
247 {
248 const NdArray<dtype> values = { value };
249 return insert(arr, indices, values, axis);
250 }
251
252 //============================================================================
253 // Method Description:
264 template<typename dtype>
265 NdArray<dtype> insert(const NdArray<dtype>& arr, Slice slice, const dtype& value, Axis axis = Axis::NONE)
266 {
267 auto sliceIndices = slice.toIndices(arr.dimSize(axis));
268 return insert(arr,
269 NdArray<uint32>(sliceIndices.data(), sliceIndices.size(), PointerPolicy::SHELL),
270 value,
271 axis);
272 }
273
274 //============================================================================
275 // Method Description:
286 template<typename dtype, typename Indices, type_traits::ndarray_int_concept<Indices> = 0>
287 NdArray<dtype>
288 insert(const NdArray<dtype>& arr, const Indices& indices, const NdArray<dtype>& values, Axis axis = Axis::NONE)
289 {
290 const auto isScalarValue = values.isscalar();
291
292 switch (axis)
293 {
294 case Axis::NONE:
295 {
296 if (!isScalarValue && indices.size() != values.size())
297 {
298 THROW_INVALID_ARGUMENT_ERROR("could not broadcast values into indices");
299 }
300
301 const auto arrSize = static_cast<int32>(arr.size());
302
303 std::vector<std::pair<int32, dtype>> indexValues(indices.size());
304 if (isScalarValue)
305 {
306 const auto value = values.front();
307 stl_algorithms::transform(indices.begin(),
308 indices.end(),
309 indexValues.begin(),
310 [arrSize, value](auto index) -> std::pair<int32, dtype>
311 {
312 if constexpr (type_traits::is_ndarray_signed_int_v<Indices>)
313 {
314 if (index < 0)
315 {
316 index += arrSize;
317 }
318 // still
319 if (index < 0)
320 {
321 THROW_INVALID_ARGUMENT_ERROR("index out of range");
322 }
323 }
324 if (static_cast<int32>(index) > arrSize)
325 {
326 THROW_INVALID_ARGUMENT_ERROR("index out of range");
327 }
328
329 return std::make_pair(static_cast<int32>(index), value);
330 });
331 }
332 else
333 {
334 stl_algorithms::transform(indices.begin(),
335 indices.end(),
336 values.begin(),
337 indexValues.begin(),
338 [arrSize](auto index, const auto& value) -> std::pair<int32, dtype>
339 {
340 if constexpr (type_traits::is_ndarray_signed_int_v<Indices>)
341 {
342 if (index < 0)
343 {
344 index += arrSize;
345 }
346 // still
347 if (index < 0)
348 {
349 THROW_INVALID_ARGUMENT_ERROR("index out of range");
350 }
351 }
352 if (static_cast<int32>(index) > arrSize)
353 {
354 THROW_INVALID_ARGUMENT_ERROR("index out of range");
355 }
356
357 return std::make_pair(static_cast<int32>(index), value);
358 });
359 }
360
361 stl_algorithms::sort(indexValues.begin(),
362 indexValues.end(),
363 [](const auto& indexValue1, const auto& indexValue2) noexcept -> bool
364 { return indexValue1.first < indexValue2.first; });
365 auto indexValuesUnique = std::vector<typename decltype(indexValues)::value_type>{};
366 std::unique_copy(indexValues.begin(),
367 indexValues.end(),
368 std::back_inserter(indexValuesUnique),
369 [](const auto& indexValue1, const auto& indexValue2) noexcept -> bool
370 { return indexValue1.first == indexValue2.first; });
371
372 auto result = NdArray<dtype>(1, arr.size() + indexValuesUnique.size());
373
374 auto mask = ones_like<bool>(result);
375 int32 counter = 0;
376 std::for_each(indexValuesUnique.begin(),
377 indexValuesUnique.end(),
378 [&counter, &mask](auto& indexValue) noexcept -> void
379 { mask[indexValue.first + counter++] = false; });
380
381 result.putMask(mask, arr);
382
383 auto valuesSorted = [&indexValuesUnique]
384 {
385 std::vector<dtype> values_;
386 values_.reserve(indexValuesUnique.size());
387 std::transform(indexValuesUnique.begin(),
388 indexValuesUnique.end(),
389 std::back_inserter(values_),
390 [](const auto& indexValue) { return indexValue.second; });
391 return values_;
392 }();
393
394 result.putMask(!mask, NdArray<dtype>(valuesSorted.data(), valuesSorted.size(), PointerPolicy::SHELL));
395
396 return result;
397 }
398 case Axis::ROW:
399 {
400 const auto arrNumRows = static_cast<int32>(arr.numRows());
401
402 std::vector<std::pair<int32, NdArray<dtype>>> indexValues(indices.size());
403 if (values.isscalar())
404 {
405 const auto value = values.front();
406 auto valueRow = NdArray<dtype>(1, arr.numCols());
407 valueRow.fill(value);
408 stl_algorithms::transform(indices.begin(),
409 indices.end(),
410 indexValues.begin(),
411 [arrNumRows, &valueRow](auto index) -> std::pair<int32, NdArray<dtype>>
412 {
413 if constexpr (type_traits::is_ndarray_signed_int_v<Indices>)
414 {
415 if (index < 0)
416 {
417 index += arrNumRows;
418 }
419 // still
420 if (index < 0)
421 {
422 THROW_INVALID_ARGUMENT_ERROR("index out of range");
423 }
424 }
425 if (static_cast<int32>(index) > arrNumRows)
426 {
427 THROW_INVALID_ARGUMENT_ERROR("index out of range");
428 }
429
430 return std::make_pair(static_cast<int32>(index), valueRow);
431 });
432 }
433 else if (values.size() == arr.numCols())
434 {
435 stl_algorithms::transform(indices.begin(),
436 indices.end(),
437 indexValues.begin(),
438 [arrNumRows, &values](auto index) -> std::pair<int32, NdArray<dtype>>
439 {
440 if constexpr (type_traits::is_ndarray_signed_int_v<Indices>)
441 {
442 if (index < 0)
443 {
444 index += arrNumRows;
445 }
446 // still
447 if (index < 0)
448 {
449 THROW_INVALID_ARGUMENT_ERROR("index out of range");
450 }
451 }
452 if (static_cast<int32>(index) > arrNumRows)
453 {
454 THROW_INVALID_ARGUMENT_ERROR("index out of range");
455 }
456
457 return std::make_pair(static_cast<int32>(index), values);
458 });
459 }
460 else if (values.numCols() == arr.numCols() && values.numRows() == indices.size())
461 {
462 int32 counter = 0;
463 std::transform(indices.begin(),
464 indices.end(),
465 indexValues.begin(),
466 [arrNumRows, &values, &counter](auto index) -> std::pair<int32, NdArray<dtype>>
467 {
468 if constexpr (type_traits::is_ndarray_signed_int_v<Indices>)
469 {
470 if (index < 0)
471 {
472 index += arrNumRows;
473 }
474 // still
475 if (index < 0)
476 {
477 THROW_INVALID_ARGUMENT_ERROR("index out of range");
478 }
479 }
480 if (static_cast<int32>(index) > arrNumRows)
481 {
482 THROW_INVALID_ARGUMENT_ERROR("index out of range");
483 }
484
485 return std::make_pair(static_cast<int32>(index),
486 values(counter++, values.cSlice()));
487 });
488 }
489 else
490 {
491 THROW_INVALID_ARGUMENT_ERROR("input values shape cannot be broadcast to input array dimensions");
492 }
493
494 stl_algorithms::sort(indexValues.begin(),
495 indexValues.end(),
496 [](const auto& indexValue1, const auto& indexValue2) noexcept -> bool
497 { return indexValue1.first < indexValue2.first; });
498 auto indexValuesUnique = std::vector<typename decltype(indexValues)::value_type>{};
499 std::unique_copy(indexValues.begin(),
500 indexValues.end(),
501 std::back_inserter(indexValuesUnique),
502 [](const auto& indexValue1, const auto& indexValue2) noexcept -> bool
503 { return indexValue1.first == indexValue2.first; });
504
505 auto result = NdArray<dtype>(arrNumRows + indexValuesUnique.size(), arr.numCols());
506
507 auto mask = ones_like<bool>(result);
508 int32 counter = 0;
509 std::for_each(indexValuesUnique.begin(),
510 indexValuesUnique.end(),
511 [&counter, &mask](auto& indexValue) noexcept -> void
512 { mask.put(indexValue.first + counter++, mask.cSlice(), false); });
513
514 result.putMask(mask, arr);
515
516 counter = 0;
517 for (const auto& [index, values_] : indexValuesUnique)
518 {
519 result.put(index + counter++, result.cSlice(), values_);
520 }
521
522 return result;
523 }
524 case Axis::COL:
525 {
526 return insert(arr.transpose(), indices, values.transpose(), Axis::ROW).transpose();
527 }
528 default:
529 {
530 // get rid of compiler warning
531 return {};
532 }
533 }
534 }
535
536 //============================================================================
537 // Method Description:
548 template<typename dtype>
549 NdArray<dtype> insert(const NdArray<dtype>& arr, Slice slice, const NdArray<dtype>& values, Axis axis = Axis::NONE)
550 {
551 auto sliceIndices = slice.toIndices(arr.dimSize(axis));
552 return insert(arr,
553 NdArray<uint32>(sliceIndices.data(), sliceIndices.size(), PointerPolicy::SHELL),
554 values,
555 axis);
556 }
557} // namespace nc
#define THROW_INVALID_ARGUMENT_ERROR(msg)
Definition: Error.hpp:37
Holds 1D and 2D arrays, the main work horse of the NumCpp library.
Definition: NdArrayCore.hpp:139
size_type dimSize(Axis inAxis) const noexcept
Definition: NdArrayCore.hpp:2684
size_type size() const noexcept
Definition: NdArrayCore.hpp:4524
size_type numCols() const noexcept
Definition: NdArrayCore.hpp:3465
self_type flatten() const
Definition: NdArrayCore.hpp:2847
self_type & fill(value_type inFillValue) noexcept
Definition: NdArrayCore.hpp:2808
const_reference front() const noexcept
Definition: NdArrayCore.hpp:2860
self_type & putMask(const NdArray< bool > &inMask, const value_type &inValue)
Definition: NdArrayCore.hpp:4135
size_type numRows() const noexcept
Definition: NdArrayCore.hpp:3477
iterator begin() noexcept
Definition: NdArrayCore.hpp:1315
bool isscalar() const noexcept
Definition: NdArrayCore.hpp:2956
self_type & put(index_type inIndex, const value_type &inValue)
Definition: NdArrayCore.hpp:3693
A Class for slicing into NdArrays.
Definition: Slice.hpp:45
std::vector< uint32 > toIndices(uint32 inArrayDimSize)
Definition: Slice.hpp:214
void sort(RandomIt first, RandomIt last) noexcept
Definition: StlAlgorithms.hpp:696
OutputIt transform(InputIt first, InputIt last, OutputIt destination, UnaryOperation unaryFunction)
Definition: StlAlgorithms.hpp:775
void for_each(InputIt first, InputIt last, UnaryFunction f)
Definition: StlAlgorithms.hpp:225
constexpr OutputIt unique_copy(InputIt first, InputIt last, OutputIt destination) noexcept
Definition: StlAlgorithms.hpp:823
Definition: Cartesian.hpp:40
NdArray< dtype > insert(const NdArray< dtype > &arr, int32 index, const dtype &value)
Definition: insert.hpp:55
Axis
Enum To describe an axis.
Definition: Enums.hpp:36
std::int32_t int32
Definition: Types.hpp:36
NdArray< dtype > insert(const NdArray< dtype > &arr, Slice slice, const NdArray< dtype > &values, Axis axis=Axis::NONE)
Definition: insert.hpp:549