ndarray_slice/
lib.rs

1//! Fast and robust slice-based algorithms (e.g., [sorting], [selection], [search]) for
2//! non-contiguous (sub)views into *n*-dimensional arrays. Reimplements algorithms in [`slice`] and
3#![cfg_attr(feature = "rayon", doc = "[`rayon::slice`]")]
4#![cfg_attr(not(feature = "rayon"), doc = "`rayon::slice`")]
5//! for [`ndarray`] with arbitrary memory layout (e.g., non-contiguous).
6//!
7//! # Example
8//!
9//! ```
10//! use ndarray_slice::{ndarray::arr2, Slice1Ext};
11//!
12//! // 2-dimensional array of 4 rows and 5 columns.
13//! let mut v = arr2(&[[-5, 4, 1, -3,  2],   // row 0, axis 0
14//!                    [ 8, 3, 2,  4,  8],   // row 1, axis 0
15//!                    [38, 9, 3,  0,  3],   // row 2, axis 0
16//!                    [ 4, 9, 0,  8, -1]]); // row 3, axis 0
17//! //                    \     \       \
18//! //                  column 0 \    column 4         axis 1
19//! //                         column 2                axis 1
20//!
21//! // Mutable subview into the last column.
22//! let mut column = v.column_mut(4);
23//!
24//! // Due to row-major memory layout, columns are non-contiguous
25//! // and hence cannot be sorted by viewing them as mutable slices.
26//! assert_eq!(column.as_slice_mut(), None);
27//!
28//! // Instead, sorting is specifically implemented for non-contiguous
29//! // mutable (sub)views.
30//! column.sort_unstable();
31//!
32//! assert!(v == arr2(&[[-5, 4, 1, -3, -1],
33//!                     [ 8, 3, 2,  4,  2],
34//!                     [38, 9, 3,  0,  3],
35//!                     [ 4, 9, 0,  8,  8]]));
36//! //                                   \
37//! //                                 column 4 sorted, others untouched
38//! ```
39//!
40//! # Current Implementation
41//!
42//! Complexities where *n* is the length of the (sub)view and *m* the count of indices to select.
43//!
44//! | Resource | Complexity | Sorting (stable) | Sorting (unstable)  | Selection (unstable) | Bulk Selection (unstable) |
45//! |----------|------------|------------------|---------------------|----------------------|---------------------------|
46//! | Time     | Best       | *O*(*n*)         | *O*(*n*)            | *O*(*n*)             | *O*(*n* log *m*)          |
47//! | Time     | Average    | *O*(*n* log *n*) | *O*(*n* log *n*)    | *O*(*n*)             | *O*(*n* log *m*)          |
48//! | Time     | Worst      | *O*(*n* log *n*) | *O*(*n* log *n*)    | *O*(*n*)             | *O*(*n* log *m*)          |
49//! | Space    | Best       | *O*(1)           | *O*(1)              | *O*(1)               | *O*(*m*)                  |
50//! | Space    | Average    | *O*(*n*/2)       | *O*(log *n*)        | *O*(1)               | *O*(*m*+log *m*)          |
51//! | Space    | Worst      | *O*(*n*/2)       | *O*(log *n*)        | *O*(1)               | *O*(*m*+log *m*)          |
52//!
53//!
54//! [sorting]: https://en.wikipedia.org/wiki/Sorting_algorithm
55//! [selection]: https://en.wikipedia.org/wiki/Selection_algorithm
56//! [search]: https://en.wikipedia.org/wiki/Search_algorithm
57//!
58//! # Roadmap
59//!
60//!   * Add `SliceExt` trait for *n*-dimensional array or (sub)view with methods expecting `Axis` as
61//!     their first argument. Comparing methods will always be suffixed with `_by` or `_by_key`
62//!     defining how to compare multi-dimensional elements (e.g., rows) along the provided axis of
63//!     interest (e.g., columns).
64//!
65//! # Features
66//!
67//!   * `alloc` for stable `sort`/`sort_by`/`sort_by_key`. Enabled by `std`.
68//!   * `std` for stable `sort_by_cached_key`. Enabled by `default` or `rayon`.
69//!   * `stacker` for spilling recursion stack over to heap if necessary. Enabled by `default`.
70//!   * `rayon` for parallel `par_sort*`/`par_select_many_nth_unstable*`.
71
72#![deny(
73	missing_docs,
74	rustdoc::broken_intra_doc_links,
75	rustdoc::missing_crate_level_docs
76)]
77#![cfg_attr(not(feature = "std"), no_std)]
78#![cfg_attr(miri, feature(maybe_uninit_slice))]
79
80#[inline(always)]
81fn maybe_grow<R, F: FnOnce() -> R>(callback: F) -> R {
82	#[cfg(feature = "stacker")]
83	{
84		stacker::maybe_grow(32 * 1_024, 1_024 * 1_024, callback)
85	}
86	#[cfg(not(feature = "stacker"))]
87	{
88		callback()
89	}
90}
91
92mod heap_sort;
93mod insertion_sort;
94mod merge_sort;
95mod partition;
96mod partition_dedup;
97mod quick_sort;
98mod stable_sort;
99
100#[cfg(feature = "rayon")]
101mod par;
102#[cfg(feature = "rayon")]
103use par::{
104	merge_sort::par_merge_sort, partition::par_partition_at_indices, quick_sort::par_quick_sort,
105};
106
107#[cfg(feature = "alloc")]
108use crate::stable_sort::stable_sort;
109
110use crate::{
111	partition::{is_sorted, partition_at_index, partition_at_indices, reverse},
112	partition_dedup::partition_dedup,
113	quick_sort::quick_sort,
114};
115use core::cmp::Ordering::{self, Equal, Greater, Less};
116use ndarray::{ArrayBase, ArrayViewMut1, Data, DataMut, Ix1};
117
118pub use ndarray;
119
120// Derivative work of [`core::slice`] licensed under `MIT OR Apache-2.0`.
121//
122// [`core::slice`]: https://doc.rust-lang.org/src/core/slice/mod.rs.html
123
124/// Extension trait for 1-dimensional [`ArrayBase<S, Ix1>`](`ArrayBase`) array or (sub)view with
125/// arbitrary memory layout (e.g., non-contiguous) providing methods (e.g., [sorting], [selection],
126/// [search]) similar to [`slice`] and
127#[cfg_attr(feature = "rayon", doc = "[`rayon::slice`].")]
128#[cfg_attr(not(feature = "rayon"), doc = "`rayon::slice`.")]
129///
130/// [sorting]: https://en.wikipedia.org/wiki/Sorting_algorithm
131/// [selection]: https://en.wikipedia.org/wiki/Selection_algorithm
132/// [search]: https://en.wikipedia.org/wiki/Search_algorithm
133pub trait Slice1Ext<A, S>
134where
135	S: Data<Elem = A>,
136{
137	/// Sorts the array in parallel.
138	///
139	/// This sort is stable (i.e., does not reorder equal elements) and *O*(*n* log *n*) worst-case.
140	///
141	/// When applicable, unstable sorting is preferred because it is generally faster than stable
142	/// sorting and it doesn't allocate auxiliary memory.
143	/// See [`par_sort_unstable`](Slice1Ext::par_sort_unstable).
144	///
145	/// # Current Implementation
146	///
147	/// The current algorithm is an adaptive, iterative merge sort inspired by
148	/// [timsort](https://en.wikipedia.org/wiki/Timsort).
149	/// It is designed to be very fast in cases where the array is nearly sorted, or consists of
150	/// two or more sorted sequences concatenated one after another.
151	///
152	/// Also, it allocates temporary storage half the size of `self`, but for short arrays a
153	/// non-allocating insertion sort is used instead.
154	///
155	/// In order to sort the array in parallel, the array is first divided into smaller chunks and
156	/// all chunks are sorted in parallel. Then, adjacent chunks that together form non-descending
157	/// or descending runs are concatenated. Finally, the remaining chunks are merged together using
158	/// parallel subdivision of chunks and parallel merge operation.
159	///
160	/// # Examples
161	///
162	/// ```
163	/// use ndarray_slice::{ndarray::arr1, Slice1Ext};
164	///
165	/// let mut v = arr1(&[-5, 4, 1, -3, 2]);
166	///
167	/// v.par_sort();
168	/// assert!(v == arr1(&[-5, -3, 1, 2, 4]));
169	/// ```
170	#[cfg(feature = "rayon")]
171	fn par_sort(&mut self)
172	where
173		A: Ord + Send,
174		S: DataMut;
175	/// Sorts the array in parallel with a comparator function.
176	///
177	/// This sort is stable (i.e., does not reorder equal elements) and *O*(*n* log *n*) worst-case.
178	///
179	/// The comparator function must define a total ordering for the elements in the array. If
180	/// the ordering is not total, the order of the elements is unspecified. An order is a
181	/// total order if it is (for all `a`, `b` and `c`):
182	///
183	/// * total and antisymmetric: exactly one of `a < b`, `a == b` or `a > b` is true, and
184	/// * transitive, `a < b` and `b < c` implies `a < c`. The same must hold for both `==` and `>`.
185	///
186	/// For example, while [`f64`] doesn't implement [`Ord`] because `NaN != NaN`, we can use
187	/// `partial_cmp` as our sort function when we know the array doesn't contain a `NaN`.
188	///
189	/// ```
190	/// use ndarray_slice::{ndarray::arr1, Slice1Ext};
191	///
192	/// let mut floats = arr1(&[5f64, 4.0, 1.0, 3.0, 2.0]);
193	/// floats.par_sort_by(|a, b| a.partial_cmp(b).unwrap());
194	/// assert_eq!(floats, arr1(&[1.0, 2.0, 3.0, 4.0, 5.0]));
195	/// ```
196	///
197	/// When applicable, unstable sorting is preferred because it is generally faster than stable
198	/// sorting and it doesn't allocate auxiliary memory.
199	/// See [`par_sort_unstable_by`](Slice1Ext::par_sort_unstable_by).
200	///
201	/// # Current Implementation
202	///
203	/// The current algorithm is an adaptive, iterative merge sort inspired by
204	/// [timsort](https://en.wikipedia.org/wiki/Timsort).
205	/// It is designed to be very fast in cases where the array is nearly sorted, or consists of
206	/// two or more sorted sequences concatenated one after another.
207	///
208	/// Also, it allocates temporary storage half the size of `self`, but for short arrays a
209	/// non-allocating insertion sort is used instead.
210	///
211	/// In order to sort the array in parallel, the array is first divided into smaller chunks and
212	/// all chunks are sorted in parallel. Then, adjacent chunks that together form non-descending
213	/// or descending runs are concatenated. Finally, the remaining chunks are merged together using
214	/// parallel subdivision of chunks and parallel merge operation.
215	///
216	/// # Examples
217	///
218	/// ```
219	/// use ndarray_slice::{ndarray::arr1, Slice1Ext};
220	///
221	/// let mut v = arr1(&[5, 4, 1, 3, 2]);
222	/// v.par_sort_by(|a, b| a.cmp(b));
223	/// assert!(v == arr1(&[1, 2, 3, 4, 5]));
224	///
225	/// // reverse sorting
226	/// v.par_sort_by(|a, b| b.cmp(a));
227	/// assert!(v == arr1(&[5, 4, 3, 2, 1]));
228	/// ```
229	#[cfg(feature = "rayon")]
230	fn par_sort_by<F>(&mut self, compare: F)
231	where
232		A: Send,
233		F: Fn(&A, &A) -> Ordering + Sync,
234		S: DataMut;
235	/// Sorts the array in parallel with a key extraction function.
236	///
237	/// This sort is stable (i.e., does not reorder equal elements) and *O*(*mn* log *n*)
238	/// worst-case, where the key function is *O*(*m*).
239	///
240	/// For expensive key functions (e.g. functions that are not simple property accesses or
241	/// basic operations), [`par_sort_by_cached_key`](Slice1Ext::par_sort_by_cached_key) is likely to be
242	/// significantly faster, as it does not recompute element keys."
243	///
244	/// When applicable, unstable sorting is preferred because it is generally faster than stable
245	/// sorting and it doesn't allocate auxiliary memory.
246	/// See [`par_sort_unstable_by_key`](Slice1Ext::par_sort_unstable_by_key).
247	///
248	/// # Current Implementation
249	///
250	/// The current algorithm is an adaptive, iterative merge sort inspired by
251	/// [timsort](https://en.wikipedia.org/wiki/Timsort).
252	/// It is designed to be very fast in cases where the array is nearly sorted, or consists of
253	/// two or more sorted sequences concatenated one after another.
254	///
255	/// Also, it allocates temporary storage half the size of `self`, but for short arrays a
256	/// non-allocating insertion sort is used instead.
257	///
258	/// In order to sort the array in parallel, the array is first divided into smaller chunks and
259	/// all chunks are sorted in parallel. Then, adjacent chunks that together form non-descending
260	/// or descending runs are concatenated. Finally, the remaining chunks are merged together using
261	/// parallel subdivision of chunks and parallel merge operation.
262	///
263	/// # Examples
264	///
265	/// ```
266	/// use ndarray_slice::{ndarray::arr1, Slice1Ext};
267	///
268	/// let mut v = arr1(&[-5i32, 4, 2, -3, 1]);
269	///
270	/// v.par_sort_by_key(|k| k.abs());
271	/// assert!(v == arr1(&[1, 2, -3, 4, -5]));
272	/// ```
273	#[cfg(feature = "rayon")]
274	fn par_sort_by_key<K, F>(&mut self, f: F)
275	where
276		A: Send,
277		K: Ord,
278		F: Fn(&A) -> K + Sync,
279		S: DataMut;
280	/// Sorts the array in parallel with a key extraction function.
281	///
282	/// During sorting, the key function is called at most once per element, by using
283	/// temporary storage to remember the results of key evaluation.
284	/// The order of calls to the key function is unspecified and may change in future versions
285	/// of the standard library.
286	///
287	/// This sort is stable (i.e., does not reorder equal elements) and *O*(*mn* + *n* log *n*)
288	/// worst-case, where the key function is *O*(*m*).
289	///
290	/// For simple key functions (e.g., functions that are property accesses or
291	/// basic operations), [`par_sort_by_key`](Slice1Ext::par_sort_by_key) is likely to be
292	/// faster.
293	///
294	/// # Current Implementation
295	///
296	/// The current algorithm is based on [pattern-defeating quicksort][pdqsort] by Orson Peters,
297	/// which combines the fast average case of randomized quicksort with the fast worst case of
298	/// heapsort, while achieving linear time on arrays with certain patterns. It uses some
299	/// randomization to avoid degenerate cases, but with a fixed seed to always provide
300	/// deterministic behavior.
301	///
302	/// In the worst case, the algorithm allocates temporary storage in a `Vec<(K, usize)>` the
303	/// length of the array.
304	///
305	/// In order to sort the array in parallel, the array is first divided into smaller chunks and
306	/// all chunks are sorted in parallel. Then, adjacent chunks that together form non-descending
307	/// or descending runs are concatenated. Finally, the remaining chunks are merged together using
308	/// parallel subdivision of chunks and parallel merge operation.
309	///
310	/// # Examples
311	///
312	/// ```
313	/// # if !cfg!(miri) {
314	/// use ndarray_slice::{ndarray::arr1, Slice1Ext};
315	///
316	/// let mut v = arr1(&[-5i32, 4, 32, -3, 2]);
317	///
318	/// v.par_sort_by_cached_key(|k| k.to_string());
319	/// assert!(v == arr1(&[-3, -5, 2, 32, 4]));
320	/// # }
321	/// ```
322	///
323	/// [pdqsort]: https://github.com/orlp/pdqsort
324	#[cfg(feature = "rayon")]
325	fn par_sort_by_cached_key<K, F>(&mut self, f: F)
326	where
327		A: Send + Sync,
328		F: Fn(&A) -> K + Sync,
329		K: Ord + Send,
330		S: DataMut;
331
332	/// This sort is stable (i.e., does not reorder equal elements) and *O*(*n* log *n*) worst-case.
333	///
334	/// When applicable, unstable sorting is preferred because it is generally faster than stable
335	/// sorting and it doesn't allocate auxiliary memory.
336	/// See [`sort_unstable`](Slice1Ext::sort_unstable).
337	///
338	/// # Current Implementation
339	///
340	/// The current algorithm is an adaptive, iterative merge sort inspired by
341	/// [timsort](https://en.wikipedia.org/wiki/Timsort).
342	/// It is designed to be very fast in cases where the array is nearly sorted, or consists of
343	/// two or more sorted sequences concatenated one after another.
344	///
345	/// Also, it allocates temporary storage half the size of `self`, but for short arrays a
346	/// non-allocating insertion sort is used instead.
347	///
348	/// # Examples
349	///
350	/// ```
351	/// use ndarray_slice::{ndarray::arr1, Slice1Ext};
352	///
353	/// let mut v = arr1(&[-5, 4, 1, -3, 2]);
354	///
355	/// v.sort();
356	/// assert!(v == arr1(&[-5, -3, 1, 2, 4]));
357	/// ```
358	#[cfg(feature = "alloc")]
359	fn sort(&mut self)
360	where
361		A: Ord,
362		S: DataMut;
363	/// Sorts the array with a comparator function.
364	///
365	/// This sort is stable (i.e., does not reorder equal elements) and *O*(*n* log *n*) worst-case.
366	///
367	/// The comparator function must define a total ordering for the elements in the array. If
368	/// the ordering is not total, the order of the elements is unspecified. An order is a
369	/// total order if it is (for all `a`, `b` and `c`):
370	///
371	/// * total and antisymmetric: exactly one of `a < b`, `a == b` or `a > b` is true, and
372	/// * transitive, `a < b` and `b < c` implies `a < c`. The same must hold for both `==` and `>`.
373	///
374	/// For example, while [`f64`] doesn't implement [`Ord`] because `NaN != NaN`, we can use
375	/// `partial_cmp` as our sort function when we know the array doesn't contain a `NaN`.
376	///
377	/// ```
378	/// use ndarray_slice::{ndarray::arr1, Slice1Ext};
379	///
380	/// let mut floats = arr1(&[5f64, 4.0, 1.0, 3.0, 2.0]);
381	/// floats.sort_by(|a, b| a.partial_cmp(b).unwrap());
382	/// assert_eq!(floats, arr1(&[1.0, 2.0, 3.0, 4.0, 5.0]));
383	/// ```
384	///
385	/// When applicable, unstable sorting is preferred because it is generally faster than stable
386	/// sorting and it doesn't allocate auxiliary memory.
387	/// See [`sort_unstable_by`](Slice1Ext::sort_unstable_by).
388	///
389	/// # Current Implementation
390	///
391	/// The current algorithm is an adaptive, iterative merge sort inspired by
392	/// [timsort](https://en.wikipedia.org/wiki/Timsort).
393	/// It is designed to be very fast in cases where the array is nearly sorted, or consists of
394	/// two or more sorted sequences concatenated one after another.
395	///
396	/// Also, it allocates temporary storage half the size of `self`, but for short arrays a
397	/// non-allocating insertion sort is used instead.
398	///
399	/// # Examples
400	///
401	/// ```
402	/// use ndarray_slice::{ndarray::arr1, Slice1Ext};
403	///
404	/// let mut v = arr1(&[5, 4, 1, 3, 2]);
405	/// v.sort_by(|a, b| a.cmp(b));
406	/// assert!(v == arr1(&[1, 2, 3, 4, 5]));
407	///
408	/// // reverse sorting
409	/// v.sort_by(|a, b| b.cmp(a));
410	/// assert!(v == arr1(&[5, 4, 3, 2, 1]));
411	/// ```
412	#[cfg(feature = "alloc")]
413	fn sort_by<F>(&mut self, compare: F)
414	where
415		F: FnMut(&A, &A) -> Ordering,
416		S: DataMut;
417	/// Sorts the array with a key extraction function.
418	///
419	/// This sort is stable (i.e., does not reorder equal elements) and *O*(*mn* log *n*)
420	/// worst-case, where the key function is *O*(*m*).
421	///
422	#[cfg_attr(
423		feature = "std",
424		doc = "\
425	For expensive key functions (e.g. functions that are not simple property accesses or
426	basic operations), [`sort_by_cached_key`](Slice1Ext::sort_by_cached_key) is likely to be
427	significantly faster, as it does not recompute element keys."
428	)]
429	///
430	/// When applicable, unstable sorting is preferred because it is generally faster than stable
431	/// sorting and it doesn't allocate auxiliary memory.
432	/// See [`sort_unstable_by_key`](Slice1Ext::sort_unstable_by_key).
433	///
434	/// # Current Implementation
435	///
436	/// The current algorithm is an adaptive, iterative merge sort inspired by
437	/// [timsort](https://en.wikipedia.org/wiki/Timsort).
438	/// It is designed to be very fast in cases where the array is nearly sorted, or consists of
439	/// two or more sorted sequences concatenated one after another.
440	///
441	/// Also, it allocates temporary storage half the size of `self`, but for short arrays a
442	/// non-allocating insertion sort is used instead.
443	///
444	/// # Examples
445	///
446	/// ```
447	/// use ndarray_slice::{ndarray::arr1, Slice1Ext};
448	///
449	/// let mut v = arr1(&[-5i32, 4, 2, -3, 1]);
450	///
451	/// v.sort_by_key(|k| k.abs());
452	/// assert!(v == arr1(&[1, 2, -3, 4, -5]));
453	/// ```
454	#[cfg(feature = "alloc")]
455	fn sort_by_key<K, F>(&mut self, f: F)
456	where
457		K: Ord,
458		F: FnMut(&A) -> K,
459		S: DataMut;
460
461	/// Sorts the array with a key extraction function.
462	///
463	/// During sorting, the key function is called at most once per element, by using
464	/// temporary storage to remember the results of key evaluation.
465	/// The order of calls to the key function is unspecified and may change in future versions
466	/// of the standard library.
467	///
468	/// This sort is stable (i.e., does not reorder equal elements) and *O*(*mn* + *n* log *n*)
469	/// worst-case, where the key function is *O*(*m*).
470	///
471	/// For simple key functions (e.g., functions that are property accesses or
472	/// basic operations), [`sort_by_key`](Slice1Ext::sort_by_key) is likely to be
473	/// faster.
474	///
475	/// # Current Implementation
476	///
477	/// The current algorithm is based on [pattern-defeating quicksort][pdqsort] by Orson Peters,
478	/// which combines the fast average case of randomized quicksort with the fast worst case of
479	/// heapsort, while achieving linear time on arrays with certain patterns. It uses some
480	/// randomization to avoid degenerate cases, but with a fixed seed to always provide
481	/// deterministic behavior.
482	///
483	/// In the worst case, the algorithm allocates temporary storage in a `Vec<(K, usize)>` the
484	/// length of the array.
485	///
486	/// # Examples
487	///
488	/// ```
489	/// use ndarray_slice::{ndarray::arr1, Slice1Ext};
490	///
491	/// let mut v = arr1(&[-5i32, 4, 32, -3, 2]);
492	///
493	/// v.sort_by_cached_key(|k| k.to_string());
494	/// assert!(v == arr1(&[-3, -5, 2, 32, 4]));
495	/// ```
496	///
497	/// [pdqsort]: https://github.com/orlp/pdqsort
498	#[cfg(feature = "std")]
499	fn sort_by_cached_key<K, F>(&mut self, f: F)
500	where
501		F: FnMut(&A) -> K,
502		K: Ord,
503		S: DataMut;
504
505	/// Sorts the array in parallel, but might not preserve the order of equal elements.
506	///
507	/// This sort is unstable (i.e., may reorder equal elements), in-place
508	/// (i.e., does not allocate), and *O*(*n* log *n*) worst-case.
509	///
510	/// # Current Implementation
511	///
512	/// The current algorithm is based on [pattern-defeating quicksort][pdqsort] by Orson Peters,
513	/// which combines the fast average case of randomized quicksort with the fast worst case of
514	/// heapsort, while achieving linear time on arrays with certain patterns. It uses some
515	/// randomization to avoid degenerate cases, but with a fixed seed to always provide
516	/// deterministic behavior.
517	///
518	/// It is typically faster than stable sorting, except in a few special cases, e.g., when the
519	/// array consists of several concatenated sorted sequences.
520	///
521	/// All quicksorts work in two stages: partitioning into two halves followed by recursive
522	/// calls. The partitioning phase is sequential, but the two recursive calls are performed in
523	/// parallel.
524	///
525	/// # Examples
526	///
527	/// ```
528	/// use ndarray_slice::{ndarray::arr1, Slice1Ext};
529	///
530	/// let mut v = arr1(&[-5, 4, 1, -3, 2]);
531	///
532	/// v.par_sort_unstable();
533	/// assert!(v == arr1(&[-5, -3, 1, 2, 4]));
534	/// ```
535	///
536	/// [pdqsort]: https://github.com/orlp/pdqsort
537	#[cfg(feature = "rayon")]
538	fn par_sort_unstable(&mut self)
539	where
540		A: Ord + Send,
541		S: DataMut;
542	/// Sorts the array in parallel with a comparator function, but might not preserve the order of equal
543	/// elements.
544	///
545	/// This sort is unstable (i.e., may reorder equal elements), in-place
546	/// (i.e., does not allocate), and *O*(*n* log *n*) worst-case.
547	///
548	/// The comparator function must define a total ordering for the elements in the array. If
549	/// the ordering is not total, the order of the elements is unspecified. An order is a
550	/// total order if it is (for all `a`, `b` and `c`):
551	///
552	/// * total and antisymmetric: exactly one of `a < b`, `a == b` or `a > b` is true, and
553	/// * transitive, `a < b` and `b < c` implies `a < c`. The same must hold for both `==` and `>`.
554	///
555	/// For example, while [`f64`] doesn't implement [`Ord`] because `NaN != NaN`, we can use
556	/// `partial_cmp` as our sort function when we know the array doesn't contain a `NaN`.
557	///
558	/// ```
559	/// use ndarray_slice::{ndarray::arr1, Slice1Ext};
560	///
561	/// let mut floats = arr1(&[5f64, 4.0, 1.0, 3.0, 2.0]);
562	/// floats.par_sort_unstable_by(|a, b| a.partial_cmp(b).unwrap());
563	/// assert_eq!(floats, arr1(&[1.0, 2.0, 3.0, 4.0, 5.0]));
564	/// ```
565	///
566	/// # Current Implementation
567	///
568	/// The current algorithm is based on [pattern-defeating quicksort][pdqsort] by Orson Peters,
569	/// which combines the fast average case of randomized quicksort with the fast worst case of
570	/// heapsort, while achieving linear time on arrays with certain patterns. It uses some
571	/// randomization to avoid degenerate cases, but with a fixed seed to always provide
572	/// deterministic behavior.
573	///
574	/// It is typically faster than stable sorting, except in a few special cases, e.g., when the
575	/// array consists of several concatenated sorted sequences.
576	///
577	/// All quicksorts work in two stages: partitioning into two halves followed by recursive
578	/// calls. The partitioning phase is sequential, but the two recursive calls are performed in
579	/// parallel.
580	///
581	/// # Examples
582	///
583	/// ```
584	/// use ndarray_slice::{ndarray::arr1, Slice1Ext};
585	///
586	/// let mut v = arr1(&[5, 4, 1, 3, 2]);
587	/// v.par_sort_unstable_by(|a, b| a.cmp(b));
588	/// assert!(v == arr1(&[1, 2, 3, 4, 5]));
589	///
590	/// // reverse sorting
591	/// v.par_sort_unstable_by(|a, b| b.cmp(a));
592	/// assert!(v == arr1(&[5, 4, 3, 2, 1]));
593	/// ```
594	///
595	/// [pdqsort]: https://github.com/orlp/pdqsort
596	#[cfg(feature = "rayon")]
597	fn par_sort_unstable_by<F>(&mut self, compare: F)
598	where
599		A: Send,
600		F: Fn(&A, &A) -> Ordering + Sync,
601		S: DataMut;
602	/// Sorts the array in parallel with a key extraction function, but might not preserve the order of equal
603	/// elements.
604	///
605	/// This sort is unstable (i.e., may reorder equal elements), in-place
606	/// (i.e., does not allocate), and *O*(*mn* log *n*) worst-case, where the key function is
607	/// *O*(*m*).
608	///
609	/// # Current Implementation
610	///
611	/// The current algorithm is based on [pattern-defeating quicksort][pdqsort] by Orson Peters,
612	/// which combines the fast average case of randomized quicksort with the fast worst case of
613	/// heapsort, while achieving linear time on arrays with certain patterns. It uses some
614	/// randomization to avoid degenerate cases, but with a fixed seed to always provide
615	/// deterministic behavior.
616	///
617	/// Due to its key calling strategy, [`par_sort_unstable_by_key`](#method.par_sort_unstable_by_key)
618	/// is likely to be slower than [`par_sort_by_cached_key`](#method.par_sort_by_cached_key) in
619	/// cases where the key function is expensive.
620	///
621	/// All quicksorts work in two stages: partitioning into two halves followed by recursive
622	/// calls. The partitioning phase is sequential, but the two recursive calls are performed in
623	/// parallel.
624	///
625	/// # Examples
626	///
627	/// ```
628	/// use ndarray_slice::{ndarray::arr1, Slice1Ext};
629	///
630	/// let mut v = arr1(&[-5i32, 4, 2, -3, 1]);
631	///
632	/// v.par_sort_unstable_by_key(|k| k.abs());
633	/// assert!(v == arr1(&[1, 2, -3, 4, -5]));
634	/// ```
635	///
636	/// [pdqsort]: https://github.com/orlp/pdqsort
637	#[cfg(feature = "rayon")]
638	fn par_sort_unstable_by_key<K, F>(&mut self, f: F)
639	where
640		A: Send,
641		K: Ord,
642		F: Fn(&A) -> K + Sync,
643		S: DataMut;
644
645	/// Sorts the array, but might not preserve the order of equal elements.
646	///
647	/// This sort is unstable (i.e., may reorder equal elements), in-place
648	/// (i.e., does not allocate), and *O*(*n* log *n*) worst-case.
649	///
650	/// # Current Implementation
651	///
652	/// The current algorithm is based on [pattern-defeating quicksort][pdqsort] by Orson Peters,
653	/// which combines the fast average case of randomized quicksort with the fast worst case of
654	/// heapsort, while achieving linear time on arrays with certain patterns. It uses some
655	/// randomization to avoid degenerate cases, but with a fixed seed to always provide
656	/// deterministic behavior.
657	///
658	/// It is typically faster than stable sorting, except in a few special cases, e.g., when the
659	/// array consists of several concatenated sorted sequences.
660	///
661	/// # Examples
662	///
663	/// ```
664	/// use ndarray_slice::{ndarray::arr1, Slice1Ext};
665	///
666	/// let mut v = arr1(&[-5, 4, 1, -3, 2]);
667	///
668	/// v.sort_unstable();
669	/// assert!(v == arr1(&[-5, -3, 1, 2, 4]));
670	/// ```
671	///
672	/// [pdqsort]: https://github.com/orlp/pdqsort
673	fn sort_unstable(&mut self)
674	where
675		A: Ord,
676		S: DataMut;
677	/// Sorts the array with a comparator function, but might not preserve the order of equal
678	/// elements.
679	///
680	/// This sort is unstable (i.e., may reorder equal elements), in-place
681	/// (i.e., does not allocate), and *O*(*n* log *n*) worst-case.
682	///
683	/// The comparator function must define a total ordering for the elements in the array. If
684	/// the ordering is not total, the order of the elements is unspecified. An order is a
685	/// total order if it is (for all `a`, `b` and `c`):
686	///
687	/// * total and antisymmetric: exactly one of `a < b`, `a == b` or `a > b` is true, and
688	/// * transitive, `a < b` and `b < c` implies `a < c`. The same must hold for both `==` and `>`.
689	///
690	/// For example, while [`f64`] doesn't implement [`Ord`] because `NaN != NaN`, we can use
691	/// `partial_cmp` as our sort function when we know the array doesn't contain a `NaN`.
692	///
693	/// ```
694	/// use ndarray_slice::{ndarray::arr1, Slice1Ext};
695	///
696	/// let mut floats = arr1(&[5f64, 4.0, 1.0, 3.0, 2.0]);
697	/// floats.sort_unstable_by(|a, b| a.partial_cmp(b).unwrap());
698	/// assert_eq!(floats, arr1(&[1.0, 2.0, 3.0, 4.0, 5.0]));
699	/// ```
700	///
701	/// # Current Implementation
702	///
703	/// The current algorithm is based on [pattern-defeating quicksort][pdqsort] by Orson Peters,
704	/// which combines the fast average case of randomized quicksort with the fast worst case of
705	/// heapsort, while achieving linear time on arrays with certain patterns. It uses some
706	/// randomization to avoid degenerate cases, but with a fixed seed to always provide
707	/// deterministic behavior.
708	///
709	/// It is typically faster than stable sorting, except in a few special cases, e.g., when the
710	/// array consists of several concatenated sorted sequences.
711	///
712	/// # Examples
713	///
714	/// ```
715	/// use ndarray_slice::{ndarray::arr1, Slice1Ext};
716	///
717	/// let mut v = arr1(&[5, 4, 1, 3, 2]);
718	/// v.sort_unstable_by(|a, b| a.cmp(b));
719	/// assert!(v == arr1(&[1, 2, 3, 4, 5]));
720	///
721	/// // reverse sorting
722	/// v.sort_unstable_by(|a, b| b.cmp(a));
723	/// assert!(v == arr1(&[5, 4, 3, 2, 1]));
724	/// ```
725	///
726	/// [pdqsort]: https://github.com/orlp/pdqsort
727	fn sort_unstable_by<F>(&mut self, compare: F)
728	where
729		F: FnMut(&A, &A) -> Ordering,
730		S: DataMut;
731	/// Sorts the array with a key extraction function, but might not preserve the order of equal
732	/// elements.
733	///
734	/// This sort is unstable (i.e., may reorder equal elements), in-place
735	/// (i.e., does not allocate), and *O*(*mn* log *n*) worst-case, where the key function is
736	/// *O*(*m*).
737	///
738	/// # Current Implementation
739	///
740	/// The current algorithm is based on [pattern-defeating quicksort][pdqsort] by Orson Peters,
741	/// which combines the fast average case of randomized quicksort with the fast worst case of
742	/// heapsort, while achieving linear time on arrays with certain patterns. It uses some
743	/// randomization to avoid degenerate cases, but with a fixed seed to always provide
744	/// deterministic behavior.
745	///
746	/// Due to its key calling strategy, [`sort_unstable_by_key`](#method.sort_unstable_by_key)
747	/// is likely to be slower than [`sort_by_cached_key`](#method.sort_by_cached_key) in
748	/// cases where the key function is expensive.
749	///
750	/// # Examples
751	///
752	/// ```
753	/// use ndarray_slice::{ndarray::arr1, Slice1Ext};
754	///
755	/// let mut v = arr1(&[-5i32, 4, 2, -3, 1]);
756	///
757	/// v.sort_unstable_by_key(|k| k.abs());
758	/// assert!(v == arr1(&[1, 2, -3, 4, -5]));
759	/// ```
760	///
761	/// [pdqsort]: https://github.com/orlp/pdqsort
762	fn sort_unstable_by_key<K, F>(&mut self, f: F)
763	where
764		K: Ord,
765		F: FnMut(&A) -> K,
766		S: DataMut;
767
768	/// Checks if the elements of this array are sorted.
769	///
770	/// That is, for each element `a` and its following element `b`, `a <= b` must hold. If the
771	/// array yields exactly zero or one element, `true` is returned.
772	///
773	/// Note that if `Self::Item` is only `PartialOrd`, but not `Ord`, the above definition
774	/// implies that this function returns `false` if any two consecutive items are not
775	/// comparable.
776	///
777	/// # Examples
778	///
779	/// ```
780	/// use ndarray_slice::{ndarray::arr1, Slice1Ext};
781	///
782	/// let empty: [i32; 0] = [];
783	///
784	/// assert!(arr1(&[1, 2, 2, 9]).is_sorted());
785	/// assert!(!arr1(&[1, 3, 2, 4]).is_sorted());
786	/// assert!(arr1(&[0]).is_sorted());
787	/// assert!(arr1(&empty).is_sorted());
788	/// assert!(!arr1(&[0.0, 1.0, f32::NAN]).is_sorted());
789	/// ```
790	#[must_use]
791	fn is_sorted(&self) -> bool
792	where
793		A: PartialOrd;
794	/// Checks if the elements of this array are sorted using the given comparator function.
795	///
796	/// Instead of using `PartialOrd::partial_cmp`, this function uses the given `compare`
797	/// function to determine whether two elements are to be considered in sorted order.
798	///
799	/// # Examples
800	///
801	/// ```
802	/// use ndarray_slice::{ndarray::arr1, Slice1Ext};
803	///
804	/// assert!(arr1(&[1, 2, 2, 9]).is_sorted_by(|a, b| a <= b));
805	/// assert!(!arr1(&[1, 2, 2, 9]).is_sorted_by(|a, b| a < b));
806	///
807	/// assert!(arr1(&[0]).is_sorted_by(|a, b| true));
808	/// assert!(arr1(&[0]).is_sorted_by(|a, b| false));
809	///
810	/// let empty: [i32; 0] = [];
811	/// assert!(arr1(&empty).is_sorted_by(|a, b| false));
812	/// assert!(arr1(&empty).is_sorted_by(|a, b| true));
813	/// ```
814	#[must_use]
815	fn is_sorted_by<F>(&self, compare: F) -> bool
816	where
817		F: FnMut(&A, &A) -> bool;
818	/// Checks if the elements of this array are sorted using the given key extraction function.
819	///
820	/// Instead of comparing the array's elements directly, this function compares the keys of the
821	/// elements, as determined by `f`. Apart from that, it's equivalent to [`is_sorted`]; see its
822	/// documentation for more information.
823	///
824	/// [`is_sorted`]: Slice1Ext::is_sorted
825	///
826	/// # Examples
827	///
828	/// ```
829	/// use ndarray_slice::{ndarray::arr1, Slice1Ext};
830	///
831	/// assert!(arr1(&["c", "bb", "aaa"]).is_sorted_by_key(|s| s.len()));
832	/// assert!(!arr1(&[-2i32, -1, 0, 3]).is_sorted_by_key(|n| n.abs()));
833	/// ```
834	#[must_use]
835	fn is_sorted_by_key<F, K>(&self, f: F) -> bool
836	where
837		F: FnMut(&A) -> K,
838		K: PartialOrd;
839
840	/// Reorder the array in parallel such that the elements at `indices` are at their final sorted position.
841	///
842	/// Bulk version of [`select_nth_unstable`] extending `collection` with `&mut element`
843	/// in the order of `indices`. The provided `indices` must be sorted and unique which can be
844	/// achieved with [`par_sort_unstable`] followed by [`partition_dedup`].
845	///
846	/// # Current Implementation
847	///
848	/// The current algorithm chooses `at = indices.len() / 2` as pivot index and recurses in parallel into the
849	/// left and right subviews of `indices` (i.e., `..at` and `at + 1..`) with corresponding left
850	/// and right subviews of `self` (i.e., `..pivot` and `pivot + 1..`) where `pivot = indices[at]`.
851	/// Requiring `indices` to be already sorted, reduces the time complexity in the length *m* of
852	/// `indices` from *O*(*m*) to *O*(log *m*) compared to invoking [`select_nth_unstable`] on the
853	/// full view of `self` for each index.
854	///
855	/// # Panics
856	///
857	/// Panics when any `indices[i] >= len()`, meaning it always panics on empty arrays. Panics
858	/// when `indices` is unsorted or contains duplicates.
859	///
860	/// [`par_sort_unstable`]: Slice1Ext::par_sort_unstable
861	/// [`partition_dedup`]: Slice1Ext::partition_dedup
862	/// [`select_nth_unstable`]: Slice1Ext::select_nth_unstable
863	///
864	/// # Examples
865	///
866	/// ```
867	/// use ndarray_slice::{ndarray::arr1, Slice1Ext};
868	///
869	/// let mut v = arr1(&[-5i32, 4, 2, -3, 1, 9, 3, 4, 0]);
870	///
871	/// // Find values at following indices.
872	/// let indices = arr1(&[1, 4, 6]);
873	///
874	/// let mut values = Vec::new();
875	/// v.par_select_many_nth_unstable(&indices, &mut values);
876	///
877	/// assert!(values == [&-3, &2, &4]);
878	/// ```
879	#[cfg(feature = "rayon")]
880	fn par_select_many_nth_unstable<'a, S2>(
881		&'a mut self,
882		indices: &ArrayBase<S2, Ix1>,
883		collection: &mut Vec<&'a mut A>,
884	) where
885		A: Ord + Send,
886		S: DataMut,
887		S2: Data<Elem = usize> + Sync;
888	/// Reorder the array in parallel with a comparator function such that the elements at `indices` are at
889	/// their final sorted position.
890	///
891	/// Bulk version of [`select_nth_unstable_by`] extending `collection` with `&mut element`
892	/// in the order of `indices`. The provided `indices` must be sorted and unique which can be
893	/// achieved with [`par_sort_unstable`] followed by [`partition_dedup`].
894	///
895	/// # Current Implementation
896	///
897	/// The current algorithm chooses `at = indices.len() / 2` as pivot index and recurses in parallel into the
898	/// left and right subviews of `indices` (i.e., `..at` and `at + 1..`) with corresponding left
899	/// and right subviews of `self` (i.e., `..pivot` and `pivot + 1..`) where `pivot = indices[at]`.
900	/// Requiring `indices` to be already sorted, reduces the time complexity in the length *m* of
901	/// `indices` from *O*(*m*) to *O*(log *m*) compared to invoking [`select_nth_unstable_by`] on the
902	/// full view of `self` for each index.
903	///
904	/// # Panics
905	///
906	/// Panics when any `indices[i] >= len()`, meaning it always panics on empty arrays. Panics
907	/// when `indices` is unsorted or contains duplicates.
908	///
909	/// [`par_sort_unstable`]: Slice1Ext::par_sort_unstable
910	/// [`partition_dedup`]: Slice1Ext::partition_dedup
911	/// [`select_nth_unstable_by`]: Slice1Ext::select_nth_unstable_by
912	///
913	/// # Examples
914	///
915	/// ```
916	/// use ndarray_slice::{ndarray::arr1, Slice1Ext};
917	/// use std::collections::HashMap;
918	///
919	/// let mut v = arr1(&[-5i32, 4, 2, -3, 1, 9, 3, 4, 0]);
920	///
921	/// // Find values at following indices.
922	/// let indices = arr1(&[1, 4, 6]);
923	///
924	/// let mut values = Vec::new();
925	/// v.par_select_many_nth_unstable_by(&indices, &mut values, |a, b| b.cmp(a));
926	///
927	/// assert!(values == [&4, &2, &0]);
928	/// ```
929	#[cfg(feature = "rayon")]
930	fn par_select_many_nth_unstable_by<'a, F, S2>(
931		&'a mut self,
932		indices: &ArrayBase<S2, Ix1>,
933		collection: &mut Vec<&'a mut A>,
934		compare: F,
935	) where
936		A: Send,
937		F: Fn(&A, &A) -> Ordering + Sync,
938		S: DataMut,
939		S2: Data<Elem = usize> + Sync;
940	/// Reorder the array in parallel with a key extraction function such that the elements at `indices` are at
941	/// their final sorted position.
942	///
943	/// Bulk version of [`select_nth_unstable_by_key`] extending `collection` with `&mut element`
944	/// in the order of `indices`. The provided `indices` must be sorted and unique which can be
945	/// achieved with [`par_sort_unstable`] followed by [`partition_dedup`].
946	///
947	/// # Current Implementation
948	///
949	/// The current algorithm chooses `at = indices.len() / 2` as pivot index and recurses in parallel into the
950	/// left and right subviews of `indices` (i.e., `..at` and `at + 1..`) with corresponding left
951	/// and right subviews of `self` (i.e., `..pivot` and `pivot + 1..`) where `pivot = indices[at]`.
952	/// Requiring `indices` to be already sorted, reduces the time complexity in the length *m* of
953	/// `indices` from *O*(*m*) to *O*(log *m*) compared to invoking [`select_nth_unstable_by_key`] on the
954	/// full view of `self` for each index.
955	///
956	/// # Panics
957	///
958	/// Panics when any `indices[i] >= len()`, meaning it always panics on empty arrays. Panics
959	/// when `indices` is unsorted or contains duplicates.
960	///
961	/// [`par_sort_unstable`]: Slice1Ext::par_sort_unstable
962	/// [`partition_dedup`]: Slice1Ext::partition_dedup
963	/// [`select_nth_unstable_by_key`]: Slice1Ext::select_nth_unstable_by_key
964	///
965	/// # Examples
966	///
967	/// ```
968	/// use ndarray_slice::{ndarray::arr1, Slice1Ext};
969	/// use std::collections::HashMap;
970	///
971	/// let mut v = arr1(&[-5i32, 4, 2, -3, 1, 9, 3, 4, 0]);
972	///
973	/// // Find values at following indices.
974	/// let indices = arr1(&[1, 4, 6]);
975	///
976	/// let mut values = Vec::new();
977	/// v.par_select_many_nth_unstable_by_key(&indices, &mut values, |&a| a.abs());
978	///
979	/// assert!(values == [&1, &3, &4]);
980	/// ```
981	#[cfg(feature = "rayon")]
982	fn par_select_many_nth_unstable_by_key<'a, K, F, S2>(
983		&'a mut self,
984		indices: &ArrayBase<S2, Ix1>,
985		collection: &mut Vec<&'a mut A>,
986		f: F,
987	) where
988		A: Send,
989		K: Ord,
990		F: Fn(&A) -> K + Sync,
991		S: DataMut,
992		S2: Data<Elem = usize> + Sync;
993
994	/// Reorder the array such that the elements at `indices` are at their final sorted position.
995	///
996	/// Bulk version of [`select_nth_unstable`] extending `collection` with `(index, &mut element)`
997	/// tuples in the order of `indices`. The provided `indices` must be sorted and unique which can
998	/// be achieved with [`sort_unstable`] followed by [`partition_dedup`].
999	///
1000	/// # Current Implementation
1001	///
1002	/// The current algorithm chooses `at = indices.len() / 2` as pivot index and recurses into the
1003	/// left and right subviews of `indices` (i.e., `..at` and `at + 1..`) with corresponding left
1004	/// and right subviews of `self` (i.e., `..pivot` and `pivot + 1..`) where `pivot = indices[at]`.
1005	/// Requiring `indices` to be already sorted, reduces the time complexity in the length *m* of
1006	/// `indices` from *O*(*m*) to *O*(log *m*) compared to invoking [`select_nth_unstable`] on the
1007	/// full view of `self` for each index.
1008	///
1009	/// # Panics
1010	///
1011	/// Panics when any `indices[i] >= len()`, meaning it always panics on empty arrays. Panics
1012	/// when `indices` is unsorted or contains duplicates.
1013	///
1014	/// [`sort_unstable`]: Slice1Ext::sort_unstable
1015	/// [`partition_dedup`]: Slice1Ext::partition_dedup
1016	/// [`select_nth_unstable`]: Slice1Ext::select_nth_unstable
1017	///
1018	/// # Examples
1019	///
1020	/// ```
1021	/// use ndarray_slice::{ndarray::arr1, Slice1Ext};
1022	/// use std::collections::HashMap;
1023	///
1024	/// let mut v = arr1(&[-5i32, 4, 2, -3, 1, 9, 3, 4, 0]);
1025	///
1026	/// // Find values at following indices.
1027	/// let indices = arr1(&[1, 4, 6]);
1028	///
1029	/// let mut map = HashMap::new();
1030	/// v.select_many_nth_unstable(&indices, &mut map);
1031	/// let values = indices.map(|index| *map[index]);
1032	///
1033	/// assert!(values == arr1(&[-3, 2, 4]));
1034	/// ```
1035	fn select_many_nth_unstable<'a, E, S2>(
1036		&'a mut self,
1037		indices: &ArrayBase<S2, Ix1>,
1038		collection: &mut E,
1039	) where
1040		A: Ord + 'a,
1041		E: Extend<(usize, &'a mut A)>,
1042		S: DataMut,
1043		S2: Data<Elem = usize>;
1044	/// Reorder the array with a comparator function such that the elements at `indices` are at
1045	/// their final sorted position.
1046	///
1047	/// Bulk version of [`select_nth_unstable_by`] extending `collection` with `(index, &mut element)`
1048	/// tuples in the order of `indices`. The provided `indices` must be sorted and unique which can
1049	/// be achieved with [`sort_unstable`] followed by [`partition_dedup`].
1050	///
1051	/// # Current Implementation
1052	///
1053	/// The current algorithm chooses `at = indices.len() / 2` as pivot index and recurses into the
1054	/// left and right subviews of `indices` (i.e., `..at` and `at + 1..`) with corresponding left
1055	/// and right subviews of `self` (i.e., `..pivot` and `pivot + 1..`) where `pivot = indices[at]`.
1056	/// Requiring `indices` to be already sorted, reduces the time complexity in the length *m* of
1057	/// `indices` from *O*(*m*) to *O*(log *m*) compared to invoking [`select_nth_unstable_by`] on the
1058	/// full view of `self` for each index.
1059	///
1060	/// # Panics
1061	///
1062	/// Panics when any `indices[i] >= len()`, meaning it always panics on empty arrays. Panics
1063	/// when `indices` is unsorted or contains duplicates.
1064	///
1065	/// [`sort_unstable`]: Slice1Ext::sort_unstable
1066	/// [`partition_dedup`]: Slice1Ext::partition_dedup
1067	/// [`select_nth_unstable_by`]: Slice1Ext::select_nth_unstable_by
1068	///
1069	/// # Examples
1070	///
1071	/// ```
1072	/// use ndarray_slice::{ndarray::arr1, Slice1Ext};
1073	/// use std::collections::HashMap;
1074	///
1075	/// let mut v = arr1(&[-5i32, 4, 2, -3, 1, 9, 3, 4, 0]);
1076	///
1077	/// // Find values at following indices.
1078	/// let indices = arr1(&[1, 4, 6]);
1079	///
1080	/// let mut map = HashMap::new();
1081	/// v.select_many_nth_unstable_by(&indices, &mut map, |a, b| b.cmp(a));
1082	/// let values = indices.map(|index| *map[index]);
1083	///
1084	/// assert!(values == arr1(&[4, 2, 0]));
1085	/// ```
1086	fn select_many_nth_unstable_by<'a, E, F, S2>(
1087		&'a mut self,
1088		indices: &ArrayBase<S2, Ix1>,
1089		collection: &mut E,
1090		compare: F,
1091	) where
1092		A: 'a,
1093		E: Extend<(usize, &'a mut A)>,
1094		F: FnMut(&A, &A) -> Ordering,
1095		S: DataMut,
1096		S2: Data<Elem = usize>;
1097	/// Reorder the array with a key extraction function such that the elements at `indices` are at
1098	/// their final sorted position.
1099	///
1100	/// Bulk version of [`select_nth_unstable_by_key`] extending `collection` with `(index, &mut element)`
1101	/// tuples in the order of `indices`. The provided `indices` must be sorted and unique which can
1102	/// be achieved with [`sort_unstable`] followed by [`partition_dedup`].
1103	///
1104	/// # Current Implementation
1105	///
1106	/// The current algorithm chooses `at = indices.len() / 2` as pivot index and recurses into the
1107	/// left and right subviews of `indices` (i.e., `..at` and `at + 1..`) with corresponding left
1108	/// and right subviews of `self` (i.e., `..pivot` and `pivot + 1..`) where `pivot = indices[at]`.
1109	/// Requiring `indices` to be already sorted, reduces the time complexity in the length *m* of
1110	/// `indices` from *O*(*m*) to *O*(log *m*) compared to invoking [`select_nth_unstable_by_key`] on the
1111	/// full view of `self` for each index.
1112	///
1113	/// # Panics
1114	///
1115	/// Panics when any `indices[i] >= len()`, meaning it always panics on empty arrays. Panics
1116	/// when `indices` is unsorted or contains duplicates.
1117	///
1118	/// [`sort_unstable`]: Slice1Ext::sort_unstable
1119	/// [`partition_dedup`]: Slice1Ext::partition_dedup
1120	/// [`select_nth_unstable_by_key`]: Slice1Ext::select_nth_unstable_by_key
1121	///
1122	/// # Examples
1123	///
1124	/// ```
1125	/// use ndarray_slice::{ndarray::arr1, Slice1Ext};
1126	/// use std::collections::HashMap;
1127	///
1128	/// let mut v = arr1(&[-5i32, 4, 2, -3, 1, 9, 3, 4, 0]);
1129	///
1130	/// // Find values at following indices.
1131	/// let indices = arr1(&[1, 4, 6]);
1132	///
1133	/// let mut map = HashMap::new();
1134	/// v.select_many_nth_unstable_by_key(&indices, &mut map, |&a| a.abs());
1135	/// let values = indices.map(|index| *map[index]);
1136	///
1137	/// assert!(values == arr1(&[1, 3, 4]));
1138	/// ```
1139	fn select_many_nth_unstable_by_key<'a, E, K, F, S2>(
1140		&'a mut self,
1141		indices: &ArrayBase<S2, Ix1>,
1142		collection: &mut E,
1143		f: F,
1144	) where
1145		A: 'a,
1146		E: Extend<(usize, &'a mut A)>,
1147		K: Ord,
1148		F: FnMut(&A) -> K,
1149		S: DataMut,
1150		S2: Data<Elem = usize>;
1151	/// Reorder the array such that the element at `index` after the reordering is at its final sorted position.
1152	///
1153	/// This reordering has the additional property that any value at position `i < index` will be
1154	/// less than or equal to any value at a position `j > index`. Additionally, this reordering is
1155	/// unstable (i.e. any number of equal elements may end up at position `index`), in-place
1156	/// (i.e. does not allocate), and runs in *O*(*n*) time.
1157	/// This function is also known as "kth element" in other libraries.
1158	///
1159	/// It returns a triplet of the following from the reordered array:
1160	/// the subarray prior to `index`, the element at `index`, and the subarray after `index`;
1161	/// accordingly, the values in those two subarrays will respectively all be less-than-or-equal-to
1162	/// and greater-than-or-equal-to the value of the element at `index`.
1163	///
1164	/// # Current Implementation
1165	///
1166	/// The current algorithm is an introselect implementation based on Pattern Defeating Quicksort, which is also
1167	/// the basis for [`sort_unstable`]. The fallback algorithm is Median of Medians using Tukey's Ninther for
1168	/// pivot selection, which guarantees linear runtime for all inputs.
1169	///
1170	/// [`sort_unstable`]: Slice1Ext::sort_unstable
1171	///
1172	/// # Panics
1173	///
1174	/// Panics when `index >= len()`, meaning it always panics on empty arrays.
1175	///
1176	/// # Examples
1177	///
1178	/// ```
1179	/// use ndarray_slice::{ndarray::arr1, Slice1Ext};
1180	///
1181	/// let mut v = arr1(&[-5i32, 4, 2, -3, 1]);
1182	///
1183	/// // Find the items less than or equal to the median, the median, and greater than or equal to
1184	/// // the median.
1185	/// let (lesser, median, greater) = v.select_nth_unstable(2);
1186	///
1187	/// assert!(lesser == arr1(&[-3, -5]) || lesser == arr1(&[-5, -3]));
1188	/// assert_eq!(median, &mut 1);
1189	/// assert!(greater == arr1(&[4, 2]) || greater == arr1(&[2, 4]));
1190	///
1191	/// // We are only guaranteed the array will be one of the following, based on the way we sort
1192	/// // about the specified index.
1193	/// assert!(v == arr1(&[-3, -5, 1, 2, 4]) ||
1194	///         v == arr1(&[-5, -3, 1, 2, 4]) ||
1195	///         v == arr1(&[-3, -5, 1, 4, 2]) ||
1196	///         v == arr1(&[-5, -3, 1, 4, 2]));
1197	/// ```
1198	#[must_use]
1199	fn select_nth_unstable(
1200		&mut self,
1201		index: usize,
1202	) -> (ArrayViewMut1<'_, A>, &mut A, ArrayViewMut1<'_, A>)
1203	where
1204		A: Ord,
1205		S: DataMut;
1206	/// Reorder the array with a comparator function such that the element at `index` after the reordering is at
1207	/// its final sorted position.
1208	///
1209	/// This reordering has the additional property that any value at position `i < index` will be
1210	/// less than or equal to any value at a position `j > index` using the comparator function.
1211	/// Additionally, this reordering is unstable (i.e. any number of equal elements may end up at
1212	/// position `index`), in-place (i.e. does not allocate), and runs in *O*(*n*) time.
1213	/// This function is also known as "kth element" in other libraries.
1214	///
1215	/// It returns a triplet of the following from
1216	/// the array reordered according to the provided comparator function: the subarray prior to
1217	/// `index`, the element at `index`, and the subarray after `index`; accordingly, the values in
1218	/// those two subarrays will respectively all be less-than-or-equal-to and greater-than-or-equal-to
1219	/// the value of the element at `index`.
1220	///
1221	/// # Current Implementation
1222	///
1223	/// The current algorithm is an introselect implementation based on Pattern Defeating Quicksort, which is also
1224	/// the basis for [`sort_unstable`]. The fallback algorithm is Median of Medians using Tukey's Ninther for
1225	/// pivot selection, which guarantees linear runtime for all inputs.
1226	///
1227	/// [`sort_unstable`]: Slice1Ext::sort_unstable
1228	///
1229	/// # Panics
1230	///
1231	/// Panics when `index >= len()`, meaning it always panics on empty arrays.
1232	///
1233	/// # Examples
1234	///
1235	/// ```
1236	/// use ndarray_slice::{ndarray::arr1, Slice1Ext};
1237	///
1238	/// let mut v = arr1(&[-5i32, 4, 2, -3, 1]);
1239	///
1240	/// // Find the median as if the array were sorted in descending order.
1241	/// v.select_nth_unstable_by(2, |a, b| b.cmp(a));
1242	/// // Find the items less than or equal to the median, the median, and greater than or equal to
1243	/// // the median as if the slice were sorted in descending order.
1244	/// let (lesser, median, greater) = v.select_nth_unstable_by(2, |a, b| b.cmp(a));
1245	///
1246	/// assert!(lesser == arr1(&[4, 2]) || lesser == arr1(&[2, 4]));
1247	/// assert_eq!(median, &mut 1);
1248	/// assert!(greater == arr1(&[-3, -5]) || greater == arr1(&[-5, -3]));
1249	///
1250	/// // We are only guaranteed the array will be one of the following, based on the way we sort
1251	/// // about the specified index.
1252	/// assert!(v == arr1(&[2, 4, 1, -5, -3]) ||
1253	///         v == arr1(&[2, 4, 1, -3, -5]) ||
1254	///         v == arr1(&[4, 2, 1, -5, -3]) ||
1255	///         v == arr1(&[4, 2, 1, -3, -5]));
1256	/// ```
1257	#[must_use]
1258	fn select_nth_unstable_by<F>(
1259		&mut self,
1260		index: usize,
1261		compare: F,
1262	) -> (ArrayViewMut1<'_, A>, &mut A, ArrayViewMut1<'_, A>)
1263	where
1264		F: FnMut(&A, &A) -> Ordering,
1265		S: DataMut;
1266	/// Reorder the array with a key extraction function such that the element at `index` after the reordering is
1267	/// at its final sorted position.
1268	///
1269	/// This reordering has the additional property that any value at position `i < index` will be
1270	/// less than or equal to any value at a position `j > index` using the key extraction function.
1271	/// Additionally, this reordering is unstable (i.e. any number of equal elements may end up at
1272	/// position `index`), in-place (i.e. does not allocate), and runs in *O*(*n*) time.
1273	/// This function is also known as "kth element" in other libraries.
1274	///
1275	/// It returns a triplet of the following from
1276	/// the array reordered according to the provided key extraction function: the subarray prior to
1277	/// `index`, the element at `index`, and the subarray after `index`; accordingly, the values in
1278	/// those two subarrays will respectively all be less-than-or-equal-to and greater-than-or-equal-to
1279	/// the value of the element at `index`.
1280	///
1281	/// # Current Implementation
1282	///
1283	/// The current algorithm is an introselect implementation based on Pattern Defeating Quicksort, which is also
1284	/// the basis for [`sort_unstable`]. The fallback algorithm is Median of Medians using Tukey's Ninther for
1285	/// pivot selection, which guarantees linear runtime for all inputs.
1286	///
1287	/// [`sort_unstable`]: Slice1Ext::sort_unstable
1288	///
1289	/// # Panics
1290	///
1291	/// Panics when `index >= len()`, meaning it always panics on empty arrays.
1292	///
1293	/// # Examples
1294	///
1295	/// ```
1296	/// use ndarray_slice::{ndarray::arr1, Slice1Ext};
1297	///
1298	/// let mut v = arr1(&[-5i32, 4, 2, -3, 1]);
1299	///
1300	/// // Return the median as if the array were sorted according to absolute value.
1301	/// v.select_nth_unstable_by_key(2, |a| a.abs());
1302	/// // Find the items less than or equal to the median, the median, and greater than or equal to
1303	/// // the median as if the slice were sorted according to absolute value.
1304	/// let (lesser, median, greater) = v.select_nth_unstable_by_key(2, |a| a.abs());
1305	///
1306	/// assert!(lesser == arr1(&[1, 2]) || lesser == arr1(&[2, 1]));
1307	/// assert_eq!(median, &mut -3);
1308	/// assert!(greater == arr1(&[4, -5]) || greater == arr1(&[-5, 4]));
1309	///
1310	/// // We are only guaranteed the array will be one of the following, based on the way we sort
1311	/// // about the specified index.
1312	/// assert!(v == arr1(&[1, 2, -3, 4, -5]) ||
1313	///         v == arr1(&[1, 2, -3, -5, 4]) ||
1314	///         v == arr1(&[2, 1, -3, 4, -5]) ||
1315	///         v == arr1(&[2, 1, -3, -5, 4]));
1316	/// ```
1317	#[must_use]
1318	fn select_nth_unstable_by_key<K, F>(
1319		&mut self,
1320		index: usize,
1321		f: F,
1322	) -> (ArrayViewMut1<'_, A>, &mut A, ArrayViewMut1<'_, A>)
1323	where
1324		K: Ord,
1325		F: FnMut(&A) -> K,
1326		S: DataMut;
1327
1328	/// Returns the index of the partition point according to the given predicate
1329	/// (the index of the first element of the second partition).
1330	///
1331	/// The array is assumed to be partitioned according to the given predicate.
1332	/// This means that all elements for which the predicate returns true are at the start of the array
1333	/// and all elements for which the predicate returns false are at the end.
1334	/// For example, `[7, 15, 3, 5, 4, 12, 6]` is partitioned under the predicate `x % 2 != 0`
1335	/// (all odd numbers are at the start, all even at the end).
1336	///
1337	/// If this array is not partitioned, the returned result is unspecified and meaningless,
1338	/// as this method performs a kind of binary search.
1339	///
1340	/// See also [`binary_search`], [`binary_search_by`], and [`binary_search_by_key`].
1341	///
1342	/// [`binary_search`]: Slice1Ext::binary_search
1343	/// [`binary_search_by`]: Slice1Ext::binary_search_by
1344	/// [`binary_search_by_key`]: Slice1Ext::binary_search_by_key
1345	///
1346	/// # Examples
1347	///
1348	/// ```
1349	/// use ndarray_slice::{
1350	///     ndarray::{arr1, s},
1351	///     Slice1Ext,
1352	/// };
1353	///
1354	/// let v = arr1(&[1, 2, 3, 3, 5, 6, 7]);
1355	/// let i = v.partition_point(|&x| x < 5);
1356	///
1357	/// assert_eq!(i, 4);
1358	/// assert!(v.slice(s![..i]).iter().all(|&x| x < 5));
1359	/// assert!(v.slice(s![i..]).iter().all(|&x| !(x < 5)));
1360	/// ```
1361	///
1362	/// If all elements of the array match the predicate, including if the array
1363	/// is empty, then the length of the array will be returned:
1364	///
1365	/// ```
1366	/// use ndarray_slice::{ndarray::arr1, Slice1Ext};
1367	///
1368	/// let a = arr1(&[2, 4, 8]);
1369	/// assert_eq!(a.partition_point(|x| x < &100), a.len());
1370	/// let a = arr1(&[0i32; 0]);
1371	/// assert_eq!(a.partition_point(|x| x < &100), 0);
1372	/// ```
1373	///
1374	/// If you want to insert an item to a sorted vector, while maintaining
1375	/// sort order:
1376	///
1377	/// ```
1378	/// use ndarray_slice::{ndarray::array, Slice1Ext};
1379	///
1380	/// let mut s = array![0, 1, 1, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55];
1381	/// let num = 42;
1382	/// let idx = s.partition_point(|&x| x < num);
1383	/// let (mut s, off) = s.into_raw_vec_and_offset();
1384	/// let off = off.unwrap_or_default();
1385	/// s.insert(off + idx, num);
1386	/// assert_eq!(s[off..], [0, 1, 1, 1, 1, 2, 3, 5, 8, 13, 21, 34, 42, 55]);
1387	/// ```
1388	#[must_use]
1389	fn partition_point<P>(&self, pred: P) -> usize
1390	where
1391		P: FnMut(&A) -> bool;
1392
1393	/// Returns `true` if the array contains an element with the given value.
1394	///
1395	/// This operation is *O*(*n*).
1396	///
1397	/// Note that if you have a sorted array, [`binary_search`] may be faster.
1398	///
1399	/// [`binary_search`]: Slice1Ext::binary_search
1400	///
1401	/// # Examples
1402	///
1403	/// ```
1404	/// use ndarray_slice::{ndarray::arr1, Slice1Ext};
1405	///
1406	/// let v = arr1(&[10, 40, 30]);
1407	/// assert!(v.contains(&30));
1408	/// assert!(!v.contains(&50));
1409	/// ```
1410	///
1411	/// If you do not have a `&A`, but some other value that you can compare
1412	/// with one (for example, `String` implements `PartialEq<str>`), you can
1413	/// use `iter().any`:
1414	///
1415	/// ```
1416	/// use ndarray_slice::{ndarray::arr1, Slice1Ext};
1417	///
1418	/// let v = arr1(&[String::from("hello"), String::from("world")]); // array of `String`
1419	/// assert!(v.iter().any(|e| e == "hello")); // search with `&str`
1420	/// assert!(!v.iter().any(|e| e == "hi"));
1421	/// ```
1422	#[must_use]
1423	fn contains(&self, x: &A) -> bool
1424	where
1425		A: PartialEq;
1426
1427	/// Binary searches this array for a given element.
1428	/// This behaves similarly to [`contains`] if this array is sorted.
1429	///
1430	/// If the value is found then [`Result::Ok`] is returned, containing the
1431	/// index of the matching element. If there are multiple matches, then any
1432	/// one of the matches could be returned. The index is chosen
1433	/// deterministically, but is subject to change in future versions of Rust.
1434	/// If the value is not found then [`Result::Err`] is returned, containing
1435	/// the index where a matching element could be inserted while maintaining
1436	/// sorted order.
1437	///
1438	/// See also [`binary_search_by`], [`binary_search_by_key`], and [`partition_point`].
1439	///
1440	/// [`contains`]: Slice1Ext::contains
1441	/// [`binary_search_by`]: Slice1Ext::binary_search_by
1442	/// [`binary_search_by_key`]: Slice1Ext::binary_search_by_key
1443	/// [`partition_point`]: Slice1Ext::partition_point
1444	///
1445	/// # Examples
1446	///
1447	/// Looks up a series of four elements. The first is found, with a
1448	/// uniquely determined position; the second and third are not
1449	/// found; the fourth could match any position in `[1, 4]`.
1450	///
1451	/// ```
1452	/// use ndarray_slice::{ndarray::arr1, Slice1Ext};
1453	///
1454	/// let s = arr1(&[0, 1, 1, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55]);
1455	///
1456	/// assert_eq!(s.binary_search(&13),  Ok(9));
1457	/// assert_eq!(s.binary_search(&4),   Err(7));
1458	/// assert_eq!(s.binary_search(&100), Err(13));
1459	/// let r = s.binary_search(&1);
1460	/// assert!(match r { Ok(1..=4) => true, _ => false, });
1461	/// ```
1462	///
1463	/// If you want to find that whole *range* of matching items, rather than
1464	/// an arbitrary matching one, that can be done using [`partition_point`]:
1465	/// ```
1466	/// use ndarray_slice::{
1467	///     ndarray::{arr1, s},
1468	///     Slice1Ext,
1469	/// };
1470	///
1471	/// let s = arr1(&[0, 1, 1, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55]);
1472	///
1473	/// let low = s.partition_point(|x| x < &1);
1474	/// assert_eq!(low, 1);
1475	/// let high = s.partition_point(|x| x <= &1);
1476	/// assert_eq!(high, 5);
1477	/// let r = s.binary_search(&1);
1478	/// assert!((low..high).contains(&r.unwrap()));
1479	///
1480	/// assert!(s.slice(s![..low]).iter().all(|&x| x < 1));
1481	/// assert!(s.slice(s![low..high]).iter().all(|&x| x == 1));
1482	/// assert!(s.slice(s![high..]).iter().all(|&x| x > 1));
1483	///
1484	/// // For something not found, the "range" of equal items is empty
1485	/// assert_eq!(s.partition_point(|x| x < &11), 9);
1486	/// assert_eq!(s.partition_point(|x| x <= &11), 9);
1487	/// assert_eq!(s.binary_search(&11), Err(9));
1488	/// ```
1489	///
1490	/// If you want to insert an item to a sorted vector, while maintaining
1491	/// sort order, consider using [`partition_point`]:
1492	///
1493	/// ```
1494	/// use ndarray_slice::{
1495	///     ndarray::{arr1, array},
1496	///     Slice1Ext,
1497	/// };
1498	///
1499	/// let mut s = array![0, 1, 1, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55];
1500	/// let num = 42;
1501	/// let idx = s.partition_point(|&x| x < num);
1502	/// // The above is equivalent to `let idx = s.binary_search(&num).unwrap_or_else(|x| x);`
1503	/// let (mut s, off) = s.into_raw_vec_and_offset();
1504	/// let off = off.unwrap_or_default();
1505	/// s.insert(off + idx, num);
1506	/// assert_eq!(s[off..], [0, 1, 1, 1, 1, 2, 3, 5, 8, 13, 21, 34, 42, 55]);
1507	/// ```
1508	fn binary_search(&self, x: &A) -> Result<usize, usize>
1509	where
1510		A: Ord;
1511	/// Binary searches this array with a comparator function.
1512	/// This behaves similarly to [`contains`] if this array is sorted.
1513	///
1514	/// The comparator function should implement an order consistent
1515	/// with the sort order of the underlying array, returning an
1516	/// order code that indicates whether its argument is `Less`,
1517	/// `Equal` or `Greater` the desired target.
1518	///
1519	/// If the value is found then [`Result::Ok`] is returned, containing the
1520	/// index of the matching element. If there are multiple matches, then any
1521	/// one of the matches could be returned. The index is chosen
1522	/// deterministically, but is subject to change in future versions of Rust.
1523	/// If the value is not found then [`Result::Err`] is returned, containing
1524	/// the index where a matching element could be inserted while maintaining
1525	/// sorted order.
1526	///
1527	/// See also [`binary_search`], [`binary_search_by_key`], and [`partition_point`].
1528	///
1529	/// [`contains`]: Slice1Ext::contains
1530	/// [`binary_search`]: Slice1Ext::binary_search
1531	/// [`binary_search_by_key`]: Slice1Ext::binary_search_by_key
1532	/// [`partition_point`]: Slice1Ext::partition_point
1533	///
1534	/// # Examples
1535	///
1536	/// Looks up a series of four elements. The first is found, with a
1537	/// uniquely determined position; the second and third are not
1538	/// found; the fourth could match any position in `[1, 4]`.
1539	///
1540	/// ```
1541	/// use ndarray_slice::{ndarray::arr1, Slice1Ext};
1542	///
1543	/// let s = arr1(&[0, 1, 1, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55]);
1544	///
1545	/// let seek = 13;
1546	/// assert_eq!(s.binary_search_by(|probe| probe.cmp(&seek)), Ok(9));
1547	/// let seek = 4;
1548	/// assert_eq!(s.binary_search_by(|probe| probe.cmp(&seek)), Err(7));
1549	/// let seek = 100;
1550	/// assert_eq!(s.binary_search_by(|probe| probe.cmp(&seek)), Err(13));
1551	/// let seek = 1;
1552	/// let r = s.binary_search_by(|probe| probe.cmp(&seek));
1553	/// assert!(match r { Ok(1..=4) => true, _ => false, });
1554	/// ```
1555	fn binary_search_by<F>(&self, f: F) -> Result<usize, usize>
1556	where
1557		F: FnMut(&A) -> Ordering;
1558	/// Binary searches this array with a key extraction function.
1559	/// This behaves similarly to [`contains`] if this array is sorted.
1560	///
1561	#[cfg_attr(
1562		feature = "alloc",
1563		doc = "\
1564	    Assumes that the array is sorted by the key, for instance with
1565	    [`sort_by_key`] using the same key extraction function."
1566	)]
1567	///
1568	/// If the value is found then [`Result::Ok`] is returned, containing the
1569	/// index of the matching element. If there are multiple matches, then any
1570	/// one of the matches could be returned. The index is chosen
1571	/// deterministically, but is subject to change in future versions of Rust.
1572	/// If the value is not found then [`Result::Err`] is returned, containing
1573	/// the index where a matching element could be inserted while maintaining
1574	/// sorted order.
1575	///
1576	/// See also [`binary_search`], [`binary_search_by`], and [`partition_point`].
1577	///
1578	/// [`contains`]: Slice1Ext::contains
1579	#[cfg_attr(
1580		feature = "alloc",
1581		doc = "\
1582	    [`sort_by_key`]: Slice1Ext::sort_by_key"
1583	)]
1584	/// [`binary_search`]: Slice1Ext::binary_search
1585	/// [`binary_search_by`]: Slice1Ext::binary_search_by
1586	/// [`partition_point`]: Slice1Ext::partition_point
1587	///
1588	/// # Examples
1589	///
1590	/// Looks up a series of four elements in a array of pairs sorted by
1591	/// their second elements. The first is found, with a uniquely
1592	/// determined position; the second and third are not found; the
1593	/// fourth could match any position in `[1, 4]`.
1594	///
1595	/// ```
1596	/// use ndarray_slice::{ndarray::arr1, Slice1Ext};
1597	///
1598	/// let s = arr1(&[(0, 0), (2, 1), (4, 1), (5, 1), (3, 1),
1599	///          (1, 2), (2, 3), (4, 5), (5, 8), (3, 13),
1600	///          (1, 21), (2, 34), (4, 55)]);
1601	///
1602	/// assert_eq!(s.binary_search_by_key(&13, |&(a, b)| b),  Ok(9));
1603	/// assert_eq!(s.binary_search_by_key(&4, |&(a, b)| b),   Err(7));
1604	/// assert_eq!(s.binary_search_by_key(&100, |&(a, b)| b), Err(13));
1605	/// let r = s.binary_search_by_key(&1, |&(a, b)| b);
1606	/// assert!(match r { Ok(1..=4) => true, _ => false, });
1607	/// ```
1608	fn binary_search_by_key<B, F>(&self, b: &B, f: F) -> Result<usize, usize>
1609	where
1610		F: FnMut(&A) -> B,
1611		B: Ord;
1612
1613	/// Moves all consecutive repeated elements to the end of the array according to the
1614	/// [`PartialEq`] trait implementation.
1615	///
1616	/// Returns two arrays. The first contains no consecutive repeated elements.
1617	/// The second contains all the duplicates in no specified order.
1618	///
1619	/// If the array is sorted, the first returned array contains no duplicates.
1620	///
1621	/// # Examples
1622	///
1623	/// ```
1624	/// use ndarray_slice::{ndarray::arr1, Slice1Ext};
1625	///
1626	/// let mut array = arr1(&[1, 2, 2, 3, 3, 2, 1, 1]);
1627	///
1628	/// let (dedup, duplicates) = array.partition_dedup();
1629	///
1630	/// assert_eq!(dedup, arr1(&[1, 2, 3, 2, 1]));
1631	/// assert_eq!(duplicates, arr1(&[2, 3, 1]));
1632	/// ```
1633	fn partition_dedup(&mut self) -> (ArrayViewMut1<'_, A>, ArrayViewMut1<'_, A>)
1634	where
1635		A: PartialEq,
1636		S: DataMut;
1637	/// Moves all but the first of consecutive elements to the end of the array satisfying
1638	/// a given equality relation.
1639	///
1640	/// Returns two arrays. The first contains no consecutive repeated elements.
1641	/// The second contains all the duplicates in no specified order.
1642	///
1643	/// The `same_bucket` function is passed references to two elements from the array and
1644	/// must determine if the elements compare equal. The elements are passed in opposite order
1645	/// from their order in the array, so if `same_bucket(a, b)` returns `true`, `a` is moved
1646	/// at the end of the array.
1647	///
1648	/// If the array is sorted, the first returned array contains no duplicates.
1649	///
1650	/// # Examples
1651	///
1652	/// ```
1653	/// use ndarray_slice::{ndarray::arr1, Slice1Ext};
1654	///
1655	/// let mut array = arr1(&["foo", "Foo", "BAZ", "Bar", "bar", "baz", "BAZ"]);
1656	///
1657	/// let (dedup, duplicates) = array.partition_dedup_by(|a, b| a.eq_ignore_ascii_case(b));
1658	///
1659	/// assert_eq!(dedup, arr1(&["foo", "BAZ", "Bar", "baz"]));
1660	/// assert_eq!(duplicates, arr1(&["bar", "Foo", "BAZ"]));
1661	/// ```
1662	fn partition_dedup_by<F>(
1663		&mut self,
1664		same_bucket: F,
1665	) -> (ArrayViewMut1<'_, A>, ArrayViewMut1<'_, A>)
1666	where
1667		F: FnMut(&mut A, &mut A) -> bool,
1668		S: DataMut;
1669	/// Moves all but the first of consecutive elements to the end of the array that resolve
1670	/// to the same key.
1671	///
1672	/// Returns two arrays. The first contains no consecutive repeated elements.
1673	/// The second contains all the duplicates in no specified order.
1674	///
1675	/// If the array is sorted, the first returned array contains no duplicates.
1676	///
1677	/// # Examples
1678	///
1679	/// ```
1680	/// use ndarray_slice::{ndarray::arr1, Slice1Ext};
1681	///
1682	/// let mut array = arr1(&[10, 20, 21, 30, 30, 20, 11, 13]);
1683	///
1684	/// let (dedup, duplicates) = array.partition_dedup_by_key(|i| *i / 10);
1685	///
1686	/// assert_eq!(dedup, arr1(&[10, 20, 30, 20, 11]));
1687	/// assert_eq!(duplicates, arr1(&[21, 30, 13]));
1688	/// ```
1689	fn partition_dedup_by_key<K, F>(
1690		&mut self,
1691		key: F,
1692	) -> (ArrayViewMut1<'_, A>, ArrayViewMut1<'_, A>)
1693	where
1694		F: FnMut(&mut A) -> K,
1695		K: PartialEq,
1696		S: DataMut;
1697
1698	/// Reverses the order of elements in the array, in place.
1699	///
1700	/// # Examples
1701	///
1702	/// ```
1703	/// use ndarray_slice::{ndarray::arr1, Slice1Ext};
1704	///
1705	/// let mut v = arr1(&[1, 2, 3]);
1706	/// v.reverse();
1707	/// assert!(v == arr1(&[3, 2, 1]));
1708	/// ```
1709	fn reverse(&mut self)
1710	where
1711		S: DataMut;
1712}
1713
1714impl<A, S> Slice1Ext<A, S> for ArrayBase<S, Ix1>
1715where
1716	S: Data<Elem = A>,
1717{
1718	#[cfg(feature = "rayon")]
1719	#[inline]
1720	fn par_sort(&mut self)
1721	where
1722		A: Ord + Send,
1723		S: DataMut,
1724	{
1725		par_merge_sort(self.view_mut(), A::lt);
1726	}
1727	#[cfg(feature = "rayon")]
1728	#[inline]
1729	fn par_sort_by<F>(&mut self, compare: F)
1730	where
1731		A: Send,
1732		F: Fn(&A, &A) -> Ordering + Sync,
1733		S: DataMut,
1734	{
1735		par_merge_sort(self.view_mut(), |a: &A, b: &A| compare(a, b) == Less)
1736	}
1737	#[cfg(feature = "rayon")]
1738	#[inline]
1739	fn par_sort_by_key<K, F>(&mut self, f: F)
1740	where
1741		A: Send,
1742		K: Ord,
1743		F: Fn(&A) -> K + Sync,
1744		S: DataMut,
1745	{
1746		par_merge_sort(self.view_mut(), |a: &A, b: &A| f(a).lt(&f(b)))
1747	}
1748	#[cfg(feature = "rayon")]
1749	fn par_sort_by_cached_key<K, F>(&mut self, f: F)
1750	where
1751		A: Send + Sync,
1752		F: Fn(&A) -> K + Sync,
1753		K: Ord + Send,
1754		S: DataMut,
1755	{
1756		use core::mem;
1757		use rayon::{
1758			iter::{ParallelBridge, ParallelIterator},
1759			slice::ParallelSliceMut,
1760		};
1761
1762		//let slice = self.as_parallel_slice_mut();
1763		let len = self.len();
1764		if len < 2 {
1765			return;
1766		}
1767
1768		// Helper macro for indexing our vector by the smallest possible type, to reduce allocation.
1769		macro_rules! sort_by_key {
1770			($t:ty) => {{
1771				let mut indices: Vec<_> = self
1772					.iter()
1773					.enumerate()
1774					.par_bridge()
1775					.map(|(i, x)| (f(&*x), i as $t))
1776					.collect();
1777				// The elements of `indices` are unique, as they are indexed, so any sort will be
1778				// stable with respect to the original slice. We use `sort_unstable` here because
1779				// it requires less memory allocation.
1780				indices.par_sort_unstable();
1781				for i in 0..len {
1782					let mut index = indices[i].1;
1783					while (index as usize) < i {
1784						index = indices[index as usize].1;
1785					}
1786					indices[i].1 = index;
1787					self.swap(i, index as usize);
1788				}
1789			}};
1790		}
1791
1792		let sz_u8 = mem::size_of::<(K, u8)>();
1793		let sz_u16 = mem::size_of::<(K, u16)>();
1794		let sz_u32 = mem::size_of::<(K, u32)>();
1795		let sz_usize = mem::size_of::<(K, usize)>();
1796
1797		if sz_u8 < sz_u16 && len <= (u8::MAX as usize) {
1798			return sort_by_key!(u8);
1799		}
1800		if sz_u16 < sz_u32 && len <= (u16::MAX as usize) {
1801			return sort_by_key!(u16);
1802		}
1803		if sz_u32 < sz_usize && len <= (u32::MAX as usize) {
1804			return sort_by_key!(u32);
1805		}
1806		sort_by_key!(usize)
1807	}
1808
1809	#[cfg(feature = "alloc")]
1810	#[inline]
1811	fn sort(&mut self)
1812	where
1813		A: Ord,
1814		S: DataMut,
1815	{
1816		stable_sort(self.view_mut(), A::lt);
1817	}
1818	#[cfg(feature = "alloc")]
1819	#[inline]
1820	fn sort_by<F>(&mut self, mut compare: F)
1821	where
1822		F: FnMut(&A, &A) -> Ordering,
1823		S: DataMut,
1824	{
1825		stable_sort(self.view_mut(), &mut |a: &A, b: &A| compare(a, b) == Less)
1826	}
1827	#[cfg(feature = "alloc")]
1828	#[inline]
1829	fn sort_by_key<K, F>(&mut self, mut f: F)
1830	where
1831		K: Ord,
1832		F: FnMut(&A) -> K,
1833		S: DataMut,
1834	{
1835		stable_sort(self.view_mut(), &mut |a: &A, b: &A| f(a).lt(&f(b)))
1836	}
1837	#[cfg(feature = "std")]
1838	fn sort_by_cached_key<K, F>(&mut self, f: F)
1839	where
1840		F: FnMut(&A) -> K,
1841		K: Ord,
1842		S: DataMut,
1843	{
1844		use core::mem;
1845
1846		// Helper macro for indexing our vector by the smallest possible type, to reduce allocation.
1847		macro_rules! sort_by_key {
1848			($t:ty, $array:ident, $f:ident) => {{
1849				let mut indices: Vec<_> = $array
1850					.iter()
1851					.map($f)
1852					.enumerate()
1853					.map(|(i, k)| (k, i as $t))
1854					.collect();
1855				// The elements of `indices` are unique, as they are indexed, so any sort will be
1856				// stable with respect to the original array. We use `sort_unstable` here because
1857				// it requires less memory allocation.
1858				indices.sort_unstable();
1859				for i in 0..$array.len() {
1860					let mut index = indices[i].1;
1861					while (index as usize) < i {
1862						index = indices[index as usize].1;
1863					}
1864					indices[i].1 = index;
1865					$array.swap(i, index as usize);
1866				}
1867			}};
1868		}
1869
1870		let sz_u8 = mem::size_of::<(K, u8)>();
1871		let sz_u16 = mem::size_of::<(K, u16)>();
1872		let sz_u32 = mem::size_of::<(K, u32)>();
1873		let sz_usize = mem::size_of::<(K, usize)>();
1874
1875		let len = self.len();
1876		if len < 2 {
1877			return;
1878		}
1879		if sz_u8 < sz_u16 && len <= (u8::MAX as usize) {
1880			return sort_by_key!(u8, self, f);
1881		}
1882		if sz_u16 < sz_u32 && len <= (u16::MAX as usize) {
1883			return sort_by_key!(u16, self, f);
1884		}
1885		if sz_u32 < sz_usize && len <= (u32::MAX as usize) {
1886			return sort_by_key!(u32, self, f);
1887		}
1888		sort_by_key!(usize, self, f)
1889	}
1890
1891	#[cfg(feature = "rayon")]
1892	#[inline]
1893	fn par_sort_unstable(&mut self)
1894	where
1895		A: Ord + Send,
1896		S: DataMut,
1897	{
1898		par_quick_sort(self.view_mut(), A::lt);
1899	}
1900	#[cfg(feature = "rayon")]
1901	#[inline]
1902	fn par_sort_unstable_by<F>(&mut self, compare: F)
1903	where
1904		A: Send,
1905		F: Fn(&A, &A) -> Ordering + Sync,
1906		S: DataMut,
1907	{
1908		par_quick_sort(self.view_mut(), |a: &A, b: &A| compare(a, b) == Less)
1909	}
1910	#[cfg(feature = "rayon")]
1911	#[inline]
1912	fn par_sort_unstable_by_key<K, F>(&mut self, f: F)
1913	where
1914		A: Send,
1915		K: Ord,
1916		F: Fn(&A) -> K + Sync,
1917		S: DataMut,
1918	{
1919		par_quick_sort(self.view_mut(), |a: &A, b: &A| f(a).lt(&f(b)))
1920	}
1921
1922	#[inline]
1923	fn sort_unstable(&mut self)
1924	where
1925		A: Ord,
1926		S: DataMut,
1927	{
1928		quick_sort(self.view_mut(), A::lt);
1929	}
1930	#[inline]
1931	fn sort_unstable_by<F>(&mut self, mut compare: F)
1932	where
1933		F: FnMut(&A, &A) -> Ordering,
1934		S: DataMut,
1935	{
1936		quick_sort(self.view_mut(), &mut |a: &A, b: &A| compare(a, b) == Less)
1937	}
1938	#[inline]
1939	fn sort_unstable_by_key<K, F>(&mut self, mut f: F)
1940	where
1941		K: Ord,
1942		F: FnMut(&A) -> K,
1943		S: DataMut,
1944	{
1945		quick_sort(self.view_mut(), &mut |a: &A, b: &A| f(a).lt(&f(b)))
1946	}
1947
1948	#[inline]
1949	fn is_sorted(&self) -> bool
1950	where
1951		A: PartialOrd,
1952	{
1953		is_sorted(self.view(), |a, b| a <= b)
1954	}
1955	#[inline]
1956	fn is_sorted_by<F>(&self, compare: F) -> bool
1957	where
1958		F: FnMut(&A, &A) -> bool,
1959	{
1960		is_sorted(self.view(), compare)
1961	}
1962	#[inline]
1963	fn is_sorted_by_key<F, K>(&self, mut f: F) -> bool
1964	where
1965		F: FnMut(&A) -> K,
1966		K: PartialOrd,
1967	{
1968		is_sorted(self.view(), |a, b| f(a) <= f(b))
1969	}
1970
1971	#[cfg(feature = "rayon")]
1972	#[inline]
1973	fn par_select_many_nth_unstable<'a, S2>(
1974		&'a mut self,
1975		indices: &ArrayBase<S2, Ix1>,
1976		collection: &mut Vec<&'a mut A>,
1977	) where
1978		A: Ord + Send,
1979		S: DataMut,
1980		S2: Data<Elem = usize> + Sync,
1981	{
1982		collection.reserve_exact(indices.len());
1983		let values = collection.spare_capacity_mut();
1984		par_partition_at_indices(self.view_mut(), 0, indices.view(), values, &A::lt);
1985		unsafe { collection.set_len(collection.len() + indices.len()) };
1986	}
1987	#[cfg(feature = "rayon")]
1988	#[inline]
1989	fn par_select_many_nth_unstable_by<'a, F, S2>(
1990		&'a mut self,
1991		indices: &ArrayBase<S2, Ix1>,
1992		collection: &mut Vec<&'a mut A>,
1993		compare: F,
1994	) where
1995		A: Send,
1996		F: Fn(&A, &A) -> Ordering + Sync,
1997		S: DataMut,
1998		S2: Data<Elem = usize> + Sync,
1999	{
2000		collection.reserve_exact(indices.len());
2001		let values = collection.spare_capacity_mut();
2002		par_partition_at_indices(
2003			self.view_mut(),
2004			0,
2005			indices.view(),
2006			values,
2007			&|a: &A, b: &A| compare(a, b) == Less,
2008		);
2009		unsafe { collection.set_len(collection.len() + indices.len()) };
2010	}
2011	#[cfg(feature = "rayon")]
2012	#[inline]
2013	fn par_select_many_nth_unstable_by_key<'a, K, F, S2>(
2014		&'a mut self,
2015		indices: &ArrayBase<S2, Ix1>,
2016		collection: &mut Vec<&'a mut A>,
2017		f: F,
2018	) where
2019		A: Send,
2020		K: Ord,
2021		F: Fn(&A) -> K + Sync,
2022		S: DataMut,
2023		S2: Data<Elem = usize> + Sync,
2024	{
2025		collection.reserve_exact(indices.len());
2026		let values = collection.spare_capacity_mut();
2027		par_partition_at_indices(
2028			self.view_mut(),
2029			0,
2030			indices.view(),
2031			values,
2032			&|a: &A, b: &A| f(a).lt(&f(b)),
2033		);
2034		unsafe { collection.set_len(collection.len() + indices.len()) };
2035	}
2036
2037	#[inline]
2038	fn select_many_nth_unstable<'a, E, S2>(
2039		&'a mut self,
2040		indices: &ArrayBase<S2, Ix1>,
2041		collection: &mut E,
2042	) where
2043		A: Ord + 'a,
2044		E: Extend<(usize, &'a mut A)>,
2045		S: DataMut,
2046		S2: Data<Elem = usize>,
2047	{
2048		partition_at_indices(self.view_mut(), 0, indices.view(), collection, &mut A::lt);
2049	}
2050	#[inline]
2051	fn select_many_nth_unstable_by<'a, E, F, S2>(
2052		&'a mut self,
2053		indices: &ArrayBase<S2, Ix1>,
2054		collection: &mut E,
2055		mut compare: F,
2056	) where
2057		A: 'a,
2058		E: Extend<(usize, &'a mut A)>,
2059		F: FnMut(&A, &A) -> Ordering,
2060		S: DataMut,
2061		S2: Data<Elem = usize>,
2062	{
2063		partition_at_indices(
2064			self.view_mut(),
2065			0,
2066			indices.view(),
2067			collection,
2068			&mut |a: &A, b: &A| compare(a, b) == Less,
2069		);
2070	}
2071	#[inline]
2072	fn select_many_nth_unstable_by_key<'a, E, K, F, S2>(
2073		&'a mut self,
2074		indices: &ArrayBase<S2, Ix1>,
2075		collection: &mut E,
2076		mut f: F,
2077	) where
2078		A: 'a,
2079		E: Extend<(usize, &'a mut A)>,
2080		K: Ord,
2081		F: FnMut(&A) -> K,
2082		S: DataMut,
2083		S2: Data<Elem = usize>,
2084	{
2085		partition_at_indices(
2086			self.view_mut(),
2087			0,
2088			indices.view(),
2089			collection,
2090			&mut |a: &A, b: &A| f(a).lt(&f(b)),
2091		);
2092	}
2093
2094	#[inline]
2095	fn select_nth_unstable(
2096		&mut self,
2097		index: usize,
2098	) -> (ArrayViewMut1<'_, A>, &mut A, ArrayViewMut1<'_, A>)
2099	where
2100		A: Ord,
2101		S: DataMut,
2102	{
2103		partition_at_index(self.view_mut(), index, &mut A::lt)
2104	}
2105	#[inline]
2106	fn select_nth_unstable_by<F>(
2107		&mut self,
2108		index: usize,
2109		mut compare: F,
2110	) -> (ArrayViewMut1<'_, A>, &mut A, ArrayViewMut1<'_, A>)
2111	where
2112		F: FnMut(&A, &A) -> Ordering,
2113		S: DataMut,
2114	{
2115		partition_at_index(self.view_mut(), index, &mut |a: &A, b: &A| {
2116			compare(a, b) == Less
2117		})
2118	}
2119	#[inline]
2120	fn select_nth_unstable_by_key<K, F>(
2121		&mut self,
2122		index: usize,
2123		mut f: F,
2124	) -> (ArrayViewMut1<'_, A>, &mut A, ArrayViewMut1<'_, A>)
2125	where
2126		K: Ord,
2127		F: FnMut(&A) -> K,
2128		S: DataMut,
2129	{
2130		partition_at_index(self.view_mut(), index, &mut |a: &A, b: &A| f(a).lt(&f(b)))
2131	}
2132
2133	#[inline]
2134	fn partition_point<P>(&self, mut pred: P) -> usize
2135	where
2136		P: FnMut(&A) -> bool,
2137	{
2138		self.binary_search_by(|x| if pred(x) { Less } else { Greater })
2139			.unwrap_or_else(|i| i)
2140	}
2141
2142	#[inline]
2143	fn contains(&self, x: &A) -> bool
2144	where
2145		A: PartialEq,
2146	{
2147		self.iter().any(|a| a == x)
2148	}
2149
2150	#[inline]
2151	fn binary_search(&self, x: &A) -> Result<usize, usize>
2152	where
2153		A: Ord,
2154	{
2155		self.binary_search_by(|p| p.cmp(x))
2156	}
2157	fn binary_search_by<F>(&self, mut f: F) -> Result<usize, usize>
2158	where
2159		F: FnMut(&A) -> Ordering,
2160	{
2161		// INVARIANTS:
2162		// - 0 <= left <= left + size = right <= self.len()
2163		// - f returns Less for everything in self[..left]
2164		// - f returns Greater for everything in self[right..]
2165		let mut size = self.len();
2166		let mut left = 0;
2167		let mut right = size;
2168		while left < right {
2169			let mid = left + size / 2;
2170
2171			// SAFETY: the while condition means `size` is strictly positive, so
2172			// `size/2 < size`. Thus `left + size/2 < left + size`, which
2173			// coupled with the `left + size <= self.len()` invariant means
2174			// we have `left + size/2 < self.len()`, and this is in-bounds.
2175			let cmp = f(unsafe { self.uget(mid) });
2176
2177			// This control flow produces conditional moves, which results in
2178			// fewer branches and instructions than if/else or matching on
2179			// cmp::Ordering.
2180			// This is x86 asm for u8: https://rust.godbolt.org/z/698eYffTx.
2181			left = if cmp == Less { mid + 1 } else { left };
2182			right = if cmp == Greater { mid } else { right };
2183			if cmp == Equal {
2184				// SAFETY: same as the `get_unchecked` above
2185				//unsafe { crate::intrinsics::assume(mid < self.len()) };
2186				debug_assert!(mid < self.len());
2187				return Ok(mid);
2188			}
2189
2190			size = right - left;
2191		}
2192
2193		// SAFETY: directly true from the overall invariant.
2194		// Note that this is `<=`, unlike the assume in the `Ok` path.
2195		//unsafe { crate::intrinsics::assume(left <= self.len()) };
2196		debug_assert!(left <= self.len());
2197		Err(left)
2198	}
2199	#[inline]
2200	fn binary_search_by_key<B, F>(&self, b: &B, mut f: F) -> Result<usize, usize>
2201	where
2202		F: FnMut(&A) -> B,
2203		B: Ord,
2204	{
2205		self.binary_search_by(|k| f(k).cmp(b))
2206	}
2207
2208	#[inline]
2209	fn partition_dedup(&mut self) -> (ArrayViewMut1<'_, A>, ArrayViewMut1<'_, A>)
2210	where
2211		A: PartialEq,
2212		S: DataMut,
2213	{
2214		self.partition_dedup_by(|a, b| a == b)
2215	}
2216	#[inline]
2217	fn partition_dedup_by<F>(
2218		&mut self,
2219		same_bucket: F,
2220	) -> (ArrayViewMut1<'_, A>, ArrayViewMut1<'_, A>)
2221	where
2222		F: FnMut(&mut A, &mut A) -> bool,
2223		S: DataMut,
2224	{
2225		partition_dedup(self.view_mut(), same_bucket)
2226	}
2227	#[inline]
2228	fn partition_dedup_by_key<K, F>(
2229		&mut self,
2230		mut key: F,
2231	) -> (ArrayViewMut1<'_, A>, ArrayViewMut1<'_, A>)
2232	where
2233		F: FnMut(&mut A) -> K,
2234		K: PartialEq,
2235		S: DataMut,
2236	{
2237		self.partition_dedup_by(|a, b| key(a) == key(b))
2238	}
2239
2240	#[inline]
2241	fn reverse(&mut self)
2242	where
2243		S: DataMut,
2244	{
2245		reverse(self.view_mut());
2246	}
2247}