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