diff --git a/README.md b/README.md index fb2e4e8..14d19f1 100644 --- a/README.md +++ b/README.md @@ -4,7 +4,7 @@ The `ladderz` project is a collection of math and tech concepts implemented in c - **[`ladderz` library](https://rzmk.github.io/ladderz/)** - A Rust library for running concept implementations - **[`lz` CLI](lz)** - A command line tool for running ladderz functions -- **[notebooks](notebooks)** - Jupyter notebooks with concept exercises and solutions in Python +- **[notebooks](notebooks)** - Rust & Python Jupyter notebooks with concept exercises and solutions > If you're looking for a more efficient implementation of a concept (e.g., for use in your programs), other resources may be more useful. @@ -41,7 +41,7 @@ Now let's run the `lz` CLI tool with the `prealgebra` subject and `get-factors` lz prealgebra get-factors 12 ``` -The printed output should be: +The printed output may be: ```console The factors of 12 are {2, 3, 6, 1, 4, 12}. @@ -53,7 +53,7 @@ We can use the `--raw` flag to get the raw output of the function: lz prealgebra get-factors 12 --raw ``` -The printed output may be: +The printed raw output may be: ```console {1, 2, 3, 4, 6, 12} @@ -154,7 +154,6 @@ Not currently implemented, but ideas that may be useful: - Linear Algebra - Statistics - Discrete Math - - Algorithms - Bioinformatics - **ladderz-py** - A package for running implementations of mathematical concepts in Python - **ladderz-app** - An interactive cross-platform (web, desktop, mobile) app potentially including visualizations, practice problems, & a course-like structure (potentially in Flutter or Tauri with Next.js & Rust) diff --git a/ladderz/src/dsa.rs b/ladderz/src/dsa.rs new file mode 100644 index 0000000..fd8c576 --- /dev/null +++ b/ladderz/src/dsa.rs @@ -0,0 +1,24 @@ +use std::collections::HashSet; + +pub fn contains_duplicate(nums: Vec) -> bool { + let mut seen = HashSet::::new(); + for &num in nums.iter() { + if seen.contains(&num) { + return true; + } + seen.insert(num); + } + false +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_contains_duplicate() { + let result = contains_duplicate(vec![1, 2, 3, 2]); + let expected = true; + assert_eq!(result, expected); + } +} diff --git a/ladderz/src/lib.rs b/ladderz/src/lib.rs index c29077c..d27c49c 100644 --- a/ladderz/src/lib.rs +++ b/ladderz/src/lib.rs @@ -9,7 +9,7 @@ //! ```toml //! ladderz = { git = "https://github.com/rzmk/ladderz", branch = "main" } //! ``` -//! +//! //! # Example //! //! ```rust @@ -43,3 +43,21 @@ /// ``` /// pub mod prealgebra; + +/// Various data structures and algorithms implementations. +/// +/// # Example +/// +/// ```rust +/// use ladderz::dsa::contains_duplicate; +/// +/// let nums: Vec = vec![2, 3, 4, 2]; +/// let result = contains_duplicate(nums.clone()); +/// println!("The vector {:?} {} contain a duplicate.", &nums, if result { "does" } else { "does not" }); +/// ``` +/// +/// ```console +/// The vector [2, 3, 4, 2] does contain a duplicate. +/// ``` +/// +pub mod dsa; diff --git a/ladderz/src/prealgebra.rs b/ladderz/src/prealgebra.rs index ab110f0..d26cc8b 100644 --- a/ladderz/src/prealgebra.rs +++ b/ladderz/src/prealgebra.rs @@ -113,7 +113,7 @@ pub fn is_multiple(x: u32, y: u32) -> bool { x % y == 0 } -/// Finds all the multiples of a positive integer `n` up to and including `end` (in the range [n, end]). +/// Finds all the multiples of a positive integer `n` starting from `start` and ending at `end` (inclusive). /// /// A multiple of `n` is a positive integer `num` where `num` is evenly divisible by `n` (i.e., `num % n == 0`). /// @@ -123,14 +123,18 @@ pub fn is_multiple(x: u32, y: u32) -> bool { /// use ladderz::prealgebra::get_multiples_in_range; /// use std::collections::HashSet; /// -/// let result: HashSet = get_multiples_in_range(2, 10); -/// let expected: HashSet = [2, 4, 6, 8, 10].into(); +/// let result: HashSet = get_multiples_in_range(2, 5, 10); +/// let expected: HashSet = [6, 8, 10].into(); /// assert_eq!(result, expected); /// ``` -pub fn get_multiples_in_range(n: u32, end: u32) -> HashSet { +pub fn get_multiples_in_range(n: u32, start: u32, end: u32) -> HashSet { let mut multiples: HashSet = HashSet::new(); - - for num in (n..end + 1).step_by(n as usize) { + let initial = if start % n == 0 { + start + } else { + start + n - (start % n) + }; + for num in (initial..end + 1).step_by(n as usize) { multiples.insert(num); } multiples @@ -304,16 +308,16 @@ mod tests { #[test] fn test_get_multiples_in_range() { - let result: HashSet = get_multiples_in_range(2, 20); - let expected: HashSet = [2, 4, 6, 8, 10, 12, 14, 16, 18, 20].into(); + let result: HashSet = get_multiples_in_range(2, 10, 20); + let expected: HashSet = [10, 12, 14, 16, 18, 20].into(); assert_eq!(result, expected); - let result_2: HashSet = get_multiples_in_range(5, 34); - let expected_2: HashSet = [5, 10, 15, 20, 25, 30].into(); + let result_2: HashSet = get_multiples_in_range(5, 23, 34); + let expected_2: HashSet = [25, 30].into(); assert_eq!(result_2, expected_2); - let result_3: HashSet = get_multiples_in_range(7, 11); - let expected_3: HashSet = [7].into(); + let result_3: HashSet = get_multiples_in_range(7, 10, 11); + let expected_3: HashSet = [].into(); assert_eq!(expected_3, result_3); } diff --git a/lz/src/dsa.rs b/lz/src/dsa.rs new file mode 100644 index 0000000..60856b4 --- /dev/null +++ b/lz/src/dsa.rs @@ -0,0 +1,57 @@ +use clap::Subcommand; + +#[derive(Subcommand)] +#[command(arg_required_else_help(true))] +pub enum Dsa { + /// Returns true or false based on whether the vector has a duplicate. + /// + /// ## Example + /// + /// ### Input + /// + /// ```bash + /// lz dsa contains-duplicate 1,2,3,2 + /// # Alternatively you may delimit the numbers with spaces: + /// lz dsa contains-duplicate 1 2 3 2 + /// ``` + /// + /// ### Output + /// + /// ```bash + /// The vector [1, 2, 3, 2] does contain a duplicate. + /// ``` + /// + /// ## Raw Output (use `-r` or `--raw`) + /// + /// ```bash + /// true + /// ``` + ContainsDuplicate { + /// The vector of numbers to detect whether it has a duplicate. + #[arg(value_delimiter = ',', num_args = 1)] + n: Vec, + /// Whether or not to return the raw output. + #[arg(short = 'r', long)] + raw: bool, + }, +} + +pub fn match_dsa(function: Option) { + use ladderz::dsa::*; + match function { + Some(Dsa::ContainsDuplicate { n, raw }) => match raw { + true => println!("{:?}", contains_duplicate(n)), + false => { + let result = contains_duplicate(n.clone()); + println!( + "The vector {:?} {} contain a duplicate.", + &n, + if result { "does" } else { "does not" } + ) + } + }, + None => { + println!("Please provide a function to use."); + } + } +} diff --git a/lz/src/main.rs b/lz/src/main.rs index 46027d4..c9d4cb5 100644 --- a/lz/src/main.rs +++ b/lz/src/main.rs @@ -1,31 +1,31 @@ //! # lz -//! +//! //! A command-line interface for various math/tech subjects. Based on the [ladderz](https://github.com/rzmk/ladderz) library. -//! +//! //! # Installation -//! +//! //! To install the command-line interface, run the following command in your terminal: -//! +//! //! ```bash //! cargo install --git https://github.com/rzmk/ladderz --branch main //! ``` -//! +//! //! # Example -//! +//! //! ```bash //! lz prealgebra is-factor 3 12 //! ``` -//! +//! //! ```console //! 3 is a factor of 12. //! ``` -//! +//! //! You may view the help menu for a subject and a function by running the command with the `-h` or `--help` flag: -//! +//! //! ```bash //! lz prealgebra is-factor -h //! ``` -//! +//! //! Learn more on [GitHub](https://github.com/rzmk/ladderz). // External modules @@ -34,6 +34,8 @@ use clap::{Parser, Subcommand}; // Local modules pub mod prealgebra; use prealgebra::{match_prealgebra, Prealgebra}; +pub mod dsa; +use dsa::{match_dsa, Dsa}; #[derive(Parser)] #[command( @@ -56,6 +58,10 @@ enum Subjects { #[command(subcommand)] function: Option, }, + Dsa { + #[command(subcommand)] + function: Option, + }, } fn main() { @@ -64,8 +70,7 @@ fn main() { // Match the subject to run the correct function. match cli.subject { Some(Subjects::Prealgebra { function }) => match_prealgebra(function), - None => { - println!("Please provide a subject to use."); - } + Some(Subjects::Dsa { function }) => match_dsa(function), + None => println!("Please provide a subject to use."), } } diff --git a/lz/src/prealgebra.rs b/lz/src/prealgebra.rs index 5660ce2..c36c603 100644 --- a/lz/src/prealgebra.rs +++ b/lz/src/prealgebra.rs @@ -4,23 +4,23 @@ use clap::Subcommand; #[command(arg_required_else_help(true))] pub enum Prealgebra { /// Finds all factor pairs for a positive integer. - /// + /// /// ## Example - /// + /// /// ### Input - /// + /// /// ```bash /// lz prealgebra factor-pairs 12 /// ``` - /// + /// /// ### Output - /// + /// /// ```bash /// The factor pairs of 12 are {(1, 12), (2, 6), (3, 4)}. /// ``` - /// + /// /// ## Raw Output (use `-r` or `--raw`) - /// + /// /// ```bash /// {(1, 12), (2, 6), (3, 4)} /// ``` @@ -34,21 +34,21 @@ pub enum Prealgebra { /// Finds all factors for a positive integer. /// /// ## Example - /// + /// /// ### Input - /// + /// /// ```bash /// lz prealgebra factors 12 /// ``` - /// + /// /// ### Output - /// + /// /// ```bash /// The factors of 12 are {1, 2, 3, 4, 6, 12}. /// ``` - /// + /// /// ## Raw Output (use `-r` or `--raw`) - /// + /// /// ```bash /// {1, 2, 3, 4, 6, 12} /// ``` @@ -60,29 +60,31 @@ pub enum Prealgebra { raw: bool, }, /// Finds all multiples of a positive integer in a given range. - /// + /// /// ## Example - /// + /// /// ### Input - /// + /// /// ```bash /// lz prealgebra multiples-in-range 3 10 /// ``` - /// + /// /// ### Output - /// + /// /// ```bash /// The multiples of 3 in the range [1, 10] are {3, 6, 9}. /// ``` - /// + /// /// ## Raw Output (use `-r` or `--raw`) - /// + /// /// ```bash /// {3, 6, 9} /// ``` MultiplesInRange { /// The positive integer to find multiples for. n: u32, + /// The lower bound of the range to find multiples in. + lower_bound: u32, /// The upper bound of the range to find multiples in. upper_bound: u32, /// Whether or not to return the raw output. @@ -90,23 +92,23 @@ pub enum Prealgebra { raw: bool, }, /// Finds all primes in a given range. - /// + /// /// ## Example - /// + /// /// ### Input - /// + /// /// ```bash /// lz prealgebra primes-in-range 1 10 /// ``` - /// + /// /// ### Output - /// + /// /// ```bash /// The primes in the range [1, 10] are {2, 3, 7, 5}. /// ``` - /// + /// /// ## Raw Output (use `-r` or `--raw`) - /// + /// /// ```bash /// {2, 3, 7, 5} /// ``` @@ -120,23 +122,23 @@ pub enum Prealgebra { raw: bool, }, /// Finds the prime factorization of a positive integer. - /// + /// /// ## Example - /// + /// /// ### Input - /// + /// /// ```bash /// lz prealgebra prime-factorization 12 /// ``` - /// + /// /// ### Output - /// + /// /// ```bash /// The prime factorization of 12 is {3: 1, 2: 2}. /// ``` - /// + /// /// ## Raw Output (use `-r` or `--raw`) - /// + /// /// ```bash /// {3: 1, 2: 2} /// ``` @@ -148,23 +150,23 @@ pub enum Prealgebra { raw: bool, }, /// Determines if a positive integer is composite. - /// + /// /// ## Example - /// + /// /// ### Input - /// + /// /// ```bash /// lz prealgebra is-composite 12 /// ``` - /// + /// /// ### Output - /// + /// /// ```bash /// 12 is composite. /// ``` - /// + /// /// ## Raw Output (use `-r` or `--raw`) - /// + /// /// ```bash /// true /// ``` @@ -176,23 +178,23 @@ pub enum Prealgebra { raw: bool, }, /// Determines if a positive integer is prime. - /// + /// /// ## Example - /// + /// /// ### Input - /// + /// /// ```bash /// lz prealgebra is-prime 12 /// ``` - /// + /// /// ### Output - /// + /// /// ```bash /// 12 is not prime. /// ``` - /// + /// /// ## Raw Output (use `-r` or `--raw`) - /// + /// /// ```bash /// false /// ``` @@ -204,23 +206,23 @@ pub enum Prealgebra { raw: bool, }, /// Determines if a positive integer is a factor of another positive integer. - /// + /// /// ## Example - /// + /// /// ### Input - /// + /// /// ```bash /// lz prealgebra is-factor 3 12 /// ``` - /// + /// /// ### Output - /// + /// /// ```bash /// 3 is a factor of 12. /// ``` - /// + /// /// ## Raw Output (use `-r` or `--raw`) - /// + /// /// ```bash /// true /// ``` @@ -234,23 +236,23 @@ pub enum Prealgebra { raw: bool, }, /// Determines if a positive integer is a multiple of another positive integer. - /// + /// /// ## Example - /// + /// /// ### Input - /// + /// /// ```bash /// lz prealgebra is-multiple 12 3 /// ``` - /// + /// /// ### Output - /// + /// /// ```bash /// 12 is a multiple of 3. /// ``` - /// + /// /// ## Raw Output (use `-r` or `--raw`) - /// + /// /// ```bash /// true /// ``` @@ -278,15 +280,17 @@ pub fn match_prealgebra(function: Option) { }, Some(Prealgebra::MultiplesInRange { n, + lower_bound, upper_bound, raw, }) => match raw { - true => println!("{:?}", get_multiples_in_range(n, upper_bound)), + true => println!("{:?}", get_multiples_in_range(n, lower_bound, upper_bound)), false => println!( - "The multiples of {} in the range [1, {}] are {:?}.", + "The multiples of {} in the range [{}, {}] are {:?}.", n, + lower_bound, upper_bound, - get_multiples_in_range(n, upper_bound) + get_multiples_in_range(n, lower_bound, upper_bound) ), }, Some(Prealgebra::PrimesInRange { @@ -340,8 +344,6 @@ pub fn match_prealgebra(function: Option) { m ), }, - None => { - println!("Please provide a function to use."); - } + None => println!("Please provide a function to use."), } } diff --git a/notebooks/pre-algebra.ipynb b/notebooks/python/pre-algebra.ipynb similarity index 100% rename from notebooks/pre-algebra.ipynb rename to notebooks/python/pre-algebra.ipynb diff --git a/notebooks/requirements.txt b/notebooks/python/requirements.txt similarity index 100% rename from notebooks/requirements.txt rename to notebooks/python/requirements.txt diff --git a/notebooks/rust/dsa.ipynb b/notebooks/rust/dsa.ipynb new file mode 100644 index 0000000..3e136db --- /dev/null +++ b/notebooks/rust/dsa.ipynb @@ -0,0 +1,80 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# ladderz dsa usage\n", + "\n", + "Here are some examples of using the `dsa` (data structures and algorithms) module from `ladderz`.\n", + "\n", + "> This notebook uses [evcxr](https://github.com/evcxr/evcxr) for a Rust Jupyter Kernel. See [the evcxr_jupyter README.md](https://github.com/evcxr/evcxr/blob/main/evcxr_jupyter/README.md) for more info on how to run this notebook on your machine." + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": { + "vscode": { + "languageId": "rust" + } + }, + "outputs": [], + "source": [ + "// Uncomment the next line and comment the subsequent line if not running notebook from source\n", + "// :dep ladderz = { git = \"https://github.com/rzmk/ladderz\", branch = \"main\" }\n", + ":dep ladderz = { path = \"../../ladderz\" }\n", + "\n", + "use ladderz::dsa;" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## 217. Contains Duplicate" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "metadata": { + "vscode": { + "languageId": "rust" + } + }, + "outputs": [ + { + "data": { + "text/plain": [ + "true" + ] + }, + "execution_count": 6, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "dsa::contains_duplicate(vec![1, 3, 4, 2, 4])" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Rust", + "language": "rust", + "name": "rust" + }, + "language_info": { + "codemirror_mode": "rust", + "file_extension": ".rs", + "mimetype": "text/rust", + "name": "Rust", + "pygment_lexer": "rust", + "version": "" + } + }, + "nbformat": 4, + "nbformat_minor": 2 +}