Skip to content

Commit

Permalink
.
Browse files Browse the repository at this point in the history
  • Loading branch information
Martin Ockajak committed Jul 10, 2024
1 parent c65677c commit e754564
Show file tree
Hide file tree
Showing 8 changed files with 216 additions and 72 deletions.
7 changes: 3 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -110,7 +110,7 @@ data.group_by(|x| x % 2); // HashMap::from([(0, vec![2]), (1, vec![1, 3]
| *minmax_by* | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: |
| *minmax_by_key* | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: |
| *minmax_item* | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: |
| *move_item* | :heavy_check_mark: | | | |
| *move_at* | :heavy_check_mark: | | | |
| *multicombinations* | :heavy_check_mark: | | | |
| *pad_left* | :heavy_check_mark: | | | |
| *pad_left_with* | :heavy_check_mark: | | | |
Expand All @@ -122,8 +122,9 @@ data.group_by(|x| x % 2); // HashMap::from([(0, vec![2]), (1, vec![1, 3]
| *permutations* | :heavy_check_mark: | | | |
| *position* | :heavy_check_mark: | :heavy_check_mark: | | |
| *positions* | :heavy_check_mark: | :heavy_check_mark: | | |
| *position_of* | :heavy_check_mark: | :heavy_check_mark: | | |
| *positions_of* | :heavy_check_mark: | :heavy_check_mark: | | |
| *position_of* | :heavy_check_mark: | :heavy_check_mark: | | |
| *position_sequence* | :heavy_check_mark: | :heavy_check_mark: | | |
| *powerset* | :heavy_check_mark: | | :heavy_check_mark: | |
| *product* | :heavy_check_mark: | | :heavy_check_mark: | |
| *product_keys* | | | | :heavy_check_mark: |
Expand Down Expand Up @@ -155,9 +156,7 @@ data.group_by(|x| x % 2); // HashMap::from([(0, vec![2]), (1, vec![1, 3]
| *splice* | :heavy_check_mark: | | | |
| *step_by* | :heavy_check_mark: | | | |
| *subset* | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: |
| *subsequence* | :heavy_check_mark: | :heavy_check_mark: | | |
| *superset* | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: |
| *supersequence* | :heavy_check_mark: | :heavy_check_mark: | | |
| *sum* | :heavy_check_mark: | | :heavy_check_mark: | |
| *sum_keys* | | | | :heavy_check_mark: |
| *sum_values* | | | | :heavy_check_mark: |
Expand Down
8 changes: 8 additions & 0 deletions src/extensions/collections/linked_list.rs
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,14 @@ impl<Item> Ordered<Item> for LinkedList<Item> {
fn positions(&self, predicate: impl FnMut(&Item) -> bool) -> Vec<usize> {
positions(self.iter(), predicate)
}

#[inline]
fn position_sequence<'a>(&'a self, elements: &'a impl Iterable<Item<'a> = &'a Item>) -> Option<usize>
where
Item: PartialEq + 'a,
{
position_sequence(self.iter(), elements)
}
}

impl<Item> Reversible<Item> for LinkedList<Item> {
Expand Down
8 changes: 8 additions & 0 deletions src/extensions/collections/slice.rs
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,14 @@ impl<Item> Ordered<Item> for [Item] {
fn positions(&self, predicate: impl FnMut(&Item) -> bool) -> Vec<usize> {
positions(self.iter(), predicate)
}

#[inline]
fn position_sequence<'a>(&'a self, elements: &'a impl Iterable<Item<'a> = &'a Item>) -> Option<usize>
where
Item: PartialEq + 'a,
{
position_sequence(self.iter(), elements)
}
}

impl<Item> Reversible<Item> for [Item] {
Expand Down
10 changes: 9 additions & 1 deletion src/extensions/collections/vec.rs
Original file line number Diff line number Diff line change
Expand Up @@ -121,14 +121,22 @@ impl<Item> Ordered<Item> for Vec<Item> {
fn positions(&self, predicate: impl FnMut(&Item) -> bool) -> Vec<usize> {
positions(self.iter(), predicate)
}

#[inline]
fn position_sequence<'a>(&'a self, elements: &'a impl Iterable<Item<'a> = &'a Item>) -> Option<usize>
where
Item: PartialEq + 'a,
{
position_sequence(self.iter(), elements)
}
}

impl<Item> Reversible<Item> for Vec<Item> {
#[inline]
fn common_suffix_length<'a, I>(&'a self, elements: &'a impl Iterable<Item<'a> = &'a Item, Iterator<'a> = I>) -> usize
where
I: DoubleEndedIterator<Item = &'a Item>,
Item: PartialEq + 'a
Item: PartialEq + 'a,
{
common_suffix_length(self.iter().rev(), elements)
}
Expand Down
8 changes: 8 additions & 0 deletions src/extensions/collections/vec_deque.rs
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,14 @@ impl<Item> Ordered<Item> for VecDeque<Item> {
fn positions(&self, predicate: impl FnMut(&Item) -> bool) -> Vec<usize> {
positions(self.iter(), predicate)
}

#[inline]
fn position_sequence<'a>(&'a self, elements: &'a impl Iterable<Item<'a> = &'a Item>) -> Option<usize>
where
Item: PartialEq + 'a,
{
position_sequence(self.iter(), elements)
}
}

impl<Item> Reversible<Item> for VecDeque<Item> {
Expand Down
65 changes: 65 additions & 0 deletions src/extensions/ordered.rs
Original file line number Diff line number Diff line change
Expand Up @@ -220,6 +220,48 @@ pub trait Ordered<Item> {
{
self.positions(|x| x == element)
}

/// Searches for a sub-sequence in a collection, returning its index.
///
/// After finding a starting element of specified sequence in a collection,
/// `position_seq()` compares each element of the collection with the specified value,
/// and if all of them matche, then `position_seq()` returns [`Some(start_index)`].
/// If any of the elements do not match, it returns [`None`].
///
/// `position_seq()` is short-circuiting; in other words, it will stop
/// processing as soon as it finds a matching sequence.
///
/// Returns `Some(0)` if specified sequence is empty.
///
/// # Overflow Behavior
///
/// The method does no guarding against overflows, so if there are more
/// than [`usize::MAX`] non-matching elements, it either produces the wrong
/// result or panics. If debug assertions are enabled, a panic is guaranteed.
///
/// # Panics
///
/// This function might panic if the collection has more than `usize::MAX`
/// non-matching elements.
///
/// [`Some(start_index)`]: Some
/// [`Some(0)`]: Some
///
/// # Example
///
/// ```
/// use crate::cantrip::*;
///
/// let a = vec![1, 2, 3, 4, 5];
///
/// assert_eq!(a.position_sequence(&vec![2, 3, 4]), Some(1));
/// assert_eq!(a.position_sequence(&vec![]), Some(0));
///
/// assert_eq!(a.position_sequence(&vec![1, 3]), None);
/// ```
fn position_sequence<'a>(&'a self, elements: &'a impl Iterable<Item<'a> = &'a Item>) -> Option<usize>
where
Item: PartialEq + 'a;
}

pub(crate) fn equivalent<'a, Item>(
Expand Down Expand Up @@ -302,3 +344,26 @@ where
{
iterator.enumerate().filter(|(_, item)| predicate(item)).map(|(index, _)| index).collect()
}

pub(crate) fn position_sequence<'a, Item>(
mut iterator: impl Iterator<Item = &'a Item>, elements: &'a impl Iterable<Item<'a> = &'a Item>,
) -> Option<usize>
where
Item: PartialEq + 'a,
{
let mut elements_iterator = elements.iterator();
if let Some(first_element) = elements_iterator.next() {
if let Some(start_index) = iterator.position(|item| item == first_element) {
for (item, element) in iterator.zip(elements_iterator) {
if item != element {
return None;
}
}
Some(start_index)
} else {
None
}
} else {
Some(0)
}
}
Loading

0 comments on commit e754564

Please sign in to comment.