Added a bunch of things I needed in previous challenges
This commit is contained in:
parent
960e9e2897
commit
d3a93a875f
7
Cargo.lock
generated
Normal file
7
Cargo.lock
generated
Normal file
@ -0,0 +1,7 @@
|
||||
# This file is automatically @generated by Cargo.
|
||||
# It is not intended for manual editing.
|
||||
version = 4
|
||||
|
||||
[[package]]
|
||||
name = "utils"
|
||||
version = "0.1.0"
|
104
src/combination.rs
Normal file
104
src/combination.rs
Normal file
@ -0,0 +1,104 @@
|
||||
use std::error::Error;
|
||||
|
||||
fn factorial(num: usize) -> usize {
|
||||
let mut fact = 1;
|
||||
for n in 1..=num {
|
||||
fact *= n;
|
||||
}
|
||||
fact
|
||||
}
|
||||
|
||||
fn binomial(n: usize, k: usize) -> usize {
|
||||
if k > n {
|
||||
0
|
||||
} else {
|
||||
factorial(n) / (factorial(k) * factorial(n - k))
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct Combinator<T: Clone + Ord> {
|
||||
pub current: Vec<T>,
|
||||
pub k: usize,
|
||||
idx: usize,
|
||||
}
|
||||
|
||||
impl<T: Clone + Ord> Combinator<T> {
|
||||
pub fn new(elements: Vec<T>, k: usize) -> Result<Combinator<T>, Box<dyn Error>> {
|
||||
if k > elements.len() || k == 0 {
|
||||
return Err(Box::from("Out of bounds"));
|
||||
}
|
||||
Ok(Self {
|
||||
current: elements,
|
||||
k,
|
||||
idx: 0,
|
||||
})
|
||||
}
|
||||
|
||||
pub fn nth_lex(mut elements: Vec<T>, k: usize, nth: usize) -> Result<Vec<T>, Box<dyn Error>> {
|
||||
elements.sort();
|
||||
let num_elements = elements.len();
|
||||
let num_combinations = binomial(num_elements, k);
|
||||
if nth > num_combinations || k > num_elements || nth == 0 || k == 0 {
|
||||
return Err(Box::from("Out of bounds"));
|
||||
}
|
||||
let mut i = 0;
|
||||
let mut remaining_k = k;
|
||||
let mut comb = Vec::new();
|
||||
let mut remainder = nth - 1;
|
||||
while remaining_k > 0 {
|
||||
// Count the number of combinations that start with elements[i]
|
||||
// example with n = 5, k = 2
|
||||
// nth <= 4 select first
|
||||
// nth <= 7 select second
|
||||
// nth <= 9 select third
|
||||
// nth == 10 select fourth
|
||||
let count = binomial(num_elements - i - 1, remaining_k - 1);
|
||||
if remainder < count {
|
||||
// If the nth combination is within the count, pick this element
|
||||
comb.push(elements[i].clone());
|
||||
remaining_k -= 1;
|
||||
} else {
|
||||
remainder -= count;
|
||||
}
|
||||
i += 1;
|
||||
}
|
||||
Ok(comb)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Clone + Ord> Iterator for Combinator<T> {
|
||||
type Item = Vec<T>;
|
||||
|
||||
fn next(&mut self) -> Option<Self::Item> {
|
||||
let num_elements = self.current.len();
|
||||
let num_combinations = binomial(num_elements, self.k);
|
||||
if self.idx == num_combinations {
|
||||
return None;
|
||||
}
|
||||
let mut i = 0;
|
||||
let mut remaining_k = self.k;
|
||||
let mut comb = Vec::new();
|
||||
let mut remainder = self.idx - 1;
|
||||
while remaining_k > 0 {
|
||||
// Count the number of combinations that start with elements[i]
|
||||
// example with n = 5, k = 2
|
||||
// nth <= 4 select first
|
||||
// nth <= 7 select second
|
||||
// nth <= 9 select third
|
||||
// nth == 10 select fourth
|
||||
let count = binomial(num_elements - i - 1, remaining_k - 1);
|
||||
if remainder < count {
|
||||
// If the nth combination is within the count, pick this element
|
||||
comb.push(self.current[i].clone());
|
||||
remaining_k -= 1;
|
||||
} else {
|
||||
remainder -= count;
|
||||
}
|
||||
i += 1;
|
||||
}
|
||||
self.idx += 1;
|
||||
self.current = comb;
|
||||
Some(self.current.clone())
|
||||
}
|
||||
}
|
33
src/grid.rs
Normal file
33
src/grid.rs
Normal file
@ -0,0 +1,33 @@
|
||||
use std::error::Error;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct Grid<T: Clone>(pub Vec<Vec<T>>);
|
||||
|
||||
impl<T: Clone> Grid<T> {
|
||||
pub fn new(grid: Vec<Vec<T>>) -> Result<Self, Box<dyn Error>> {
|
||||
let row_length = grid[0].len();
|
||||
for row in &grid {
|
||||
if row_length != row.len() {
|
||||
return Err(Box::from("Rows need to all be equal in length"));
|
||||
}
|
||||
}
|
||||
Ok(Grid(grid))
|
||||
}
|
||||
|
||||
pub fn invert(&mut self) -> Self {
|
||||
let height = self.0.len();
|
||||
let width = self.0[0].len();
|
||||
|
||||
let mut new_grid = Vec::with_capacity(width);
|
||||
|
||||
for col_idx in 0..width {
|
||||
let mut new_row = Vec::with_capacity(height);
|
||||
for row_idx in 0..height {
|
||||
new_row.push(self.0[row_idx][col_idx].clone());
|
||||
}
|
||||
new_grid.push(new_row);
|
||||
}
|
||||
self.0 = new_grid;
|
||||
Grid(self.0.clone())
|
||||
}
|
||||
}
|
5
src/lib.rs
Normal file
5
src/lib.rs
Normal file
@ -0,0 +1,5 @@
|
||||
pub mod combination;
|
||||
pub mod grid;
|
||||
pub mod math;
|
||||
pub mod number;
|
||||
pub mod permutation;
|
@ -1,3 +0,0 @@
|
||||
fn main() {
|
||||
println!("Hello, world!");
|
||||
}
|
74
src/math.rs
Normal file
74
src/math.rs
Normal file
@ -0,0 +1,74 @@
|
||||
use std::collections::HashSet;
|
||||
|
||||
pub fn prime_factors(number: u64) -> Vec<u64> {
|
||||
let mut factors = vec![2];
|
||||
let upper: u64 = (number as f64).sqrt().ceil() as u64;
|
||||
for i in 3..upper {
|
||||
let mut is_prime = true;
|
||||
for factor in &factors {
|
||||
if i % factor == 0 {
|
||||
is_prime = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if is_prime && number % i == 0 {
|
||||
factors.push(i);
|
||||
}
|
||||
}
|
||||
|
||||
factors
|
||||
}
|
||||
|
||||
pub fn nth_prime(nth: i64) -> Option<i64> {
|
||||
let mut primes: Vec<i64> = vec![2];
|
||||
|
||||
let mut i = 3;
|
||||
|
||||
while primes.len() < nth as usize {
|
||||
let mut is_prime = true;
|
||||
for prime in &primes {
|
||||
if i % prime == 0 {
|
||||
is_prime = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if is_prime {
|
||||
primes.push(i);
|
||||
}
|
||||
i += 1;
|
||||
}
|
||||
|
||||
primes.pop()
|
||||
}
|
||||
|
||||
pub fn factorial(n: u64) -> u64 {
|
||||
let mut result = 1;
|
||||
for i in 1..=n {
|
||||
result *= i;
|
||||
}
|
||||
result
|
||||
}
|
||||
|
||||
pub fn get_divisors(n: u64) -> Vec<u64> {
|
||||
let mut divisors = HashSet::from([1]);
|
||||
let mut potential_divisor = 2;
|
||||
while (potential_divisor * potential_divisor) <= n {
|
||||
if n % potential_divisor == 0 {
|
||||
divisors.insert(potential_divisor);
|
||||
divisors.insert(n / potential_divisor);
|
||||
}
|
||||
potential_divisor += 1;
|
||||
}
|
||||
divisors.iter().copied().collect()
|
||||
}
|
||||
|
||||
pub fn fib(n: u64) -> u64 {
|
||||
let mut last_two = (1, 1);
|
||||
let mut iteration = 1;
|
||||
while iteration < n {
|
||||
last_two = (last_two.1, last_two.0 + last_two.1);
|
||||
iteration += 1;
|
||||
}
|
||||
|
||||
last_two.0
|
||||
}
|
423
src/number.rs
Normal file
423
src/number.rs
Normal file
@ -0,0 +1,423 @@
|
||||
use std::cmp::{min, Ordering};
|
||||
use std::fmt::{Display, Formatter};
|
||||
use std::iter::zip;
|
||||
use std::ops::{Add, Div, Mul, Rem, Sub};
|
||||
|
||||
#[derive(Clone, Debug, Eq, PartialEq, Hash)]
|
||||
pub enum Sign {
|
||||
Positif,
|
||||
Negatif,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Eq, PartialEq, Hash)]
|
||||
pub struct Number {
|
||||
pub digits: Vec<isize>,
|
||||
pub sign: Sign,
|
||||
}
|
||||
|
||||
impl Number {
|
||||
pub fn get_digit(n: isize, pos: usize) -> isize {
|
||||
let modulo = 10isize.pow(pos as u32 + 1);
|
||||
let divisor = modulo / 10;
|
||||
(n % modulo) / divisor
|
||||
}
|
||||
|
||||
pub const fn byte_to_digit(b: u8) -> isize {
|
||||
// wrapping_sub('0' as u32) same as - 48 but less magical
|
||||
(b as isize).wrapping_sub('0' as isize)
|
||||
}
|
||||
|
||||
fn handle_overflows(&mut self) {
|
||||
let new_digits = &mut self.digits;
|
||||
let digits_len = new_digits.len();
|
||||
let mut digits_idx = digits_len - 1;
|
||||
loop {
|
||||
let digit_or_num = new_digits[digits_idx];
|
||||
let digit_len = if digit_or_num != 0 {
|
||||
(digit_or_num.abs() as f64 + 1.0).log10().ceil() as usize
|
||||
} else {
|
||||
1
|
||||
};
|
||||
for i in 0..digit_len {
|
||||
let new_digit = Self::get_digit(digit_or_num, i);
|
||||
let (digit_idx, is_overflow) = digits_idx.overflowing_sub(i);
|
||||
if is_overflow {
|
||||
new_digits.insert(0, new_digit);
|
||||
digits_idx += 1;
|
||||
} else {
|
||||
let digit = new_digits.get_mut(digit_idx).unwrap();
|
||||
if i == 0 {
|
||||
*digit = new_digit;
|
||||
} else {
|
||||
*digit += new_digit;
|
||||
}
|
||||
}
|
||||
}
|
||||
if digits_idx == 0 {
|
||||
break;
|
||||
}
|
||||
digits_idx -= 1;
|
||||
}
|
||||
}
|
||||
|
||||
fn handle_underflows(&mut self) {
|
||||
let new_digits = &mut self.digits;
|
||||
let mut digits_len = new_digits.len();
|
||||
for digit in new_digits.clone() {
|
||||
match digit.cmp(&0) {
|
||||
Ordering::Equal => {
|
||||
if digits_len == 1 {
|
||||
return;
|
||||
}
|
||||
digits_len -= 1;
|
||||
new_digits.remove(0);
|
||||
}
|
||||
Ordering::Less => {
|
||||
self.sign = Sign::Negatif;
|
||||
break;
|
||||
}
|
||||
_ => break,
|
||||
};
|
||||
}
|
||||
let mut digits_idx = digits_len - 1;
|
||||
loop {
|
||||
let digit = new_digits[digits_idx];
|
||||
if self.sign == Sign::Positif && digit < 0 && digits_idx > 0 {
|
||||
let mut_digit = new_digits.get_mut(digits_idx).unwrap();
|
||||
*mut_digit = 10 - digit.abs();
|
||||
let mut_digit = new_digits.get_mut(digits_idx - 1).unwrap();
|
||||
*mut_digit -= 1;
|
||||
} else {
|
||||
let mut_digit = new_digits.get_mut(digits_idx).unwrap();
|
||||
*mut_digit = digit.abs();
|
||||
}
|
||||
if digits_idx == 0 {
|
||||
break;
|
||||
}
|
||||
digits_idx -= 1;
|
||||
}
|
||||
for digit in new_digits.clone() {
|
||||
match digit.cmp(&0) {
|
||||
Ordering::Equal => {
|
||||
new_digits.remove(0);
|
||||
}
|
||||
_ => break,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
pub fn pow(self, n: u32) -> Self {
|
||||
let mut result = self.clone();
|
||||
if ((self.digits.len() * 8) as u32) < isize::BITS {
|
||||
let number = isize::from(self);
|
||||
for _i in 1..n {
|
||||
result = result * number;
|
||||
}
|
||||
result
|
||||
} else {
|
||||
let number = self.clone();
|
||||
for _i in 1..n {
|
||||
result = result * number.clone();
|
||||
}
|
||||
result
|
||||
}
|
||||
}
|
||||
|
||||
pub fn fact(self) -> Self {
|
||||
let mut fact = Number::from(1);
|
||||
if ((self.digits.len() * 8) as u32) < isize::BITS {
|
||||
let max = isize::from(self);
|
||||
for n in 1..=max {
|
||||
fact = fact * n;
|
||||
}
|
||||
fact
|
||||
} else {
|
||||
panic!("starting number too big")
|
||||
}
|
||||
}
|
||||
|
||||
pub fn fib(n: u64) -> Self {
|
||||
let mut last_two = (Self::from(1), Self::from(1));
|
||||
let mut iteration = 1;
|
||||
while iteration < n {
|
||||
last_two = (last_two.1.clone(), last_two.0 + last_two.1);
|
||||
iteration += 1;
|
||||
}
|
||||
|
||||
last_two.0
|
||||
}
|
||||
|
||||
fn div_with_rem(n1: Number, n2: Number) -> (Number, Number) {
|
||||
let n1_len = n1.digits.len();
|
||||
let n2_len = n2.digits.len();
|
||||
if n2_len > n1_len {
|
||||
return (Number::from(0), n2);
|
||||
}
|
||||
let dividend = n1.digits[..n2_len].to_vec();
|
||||
let mut quotient = vec![];
|
||||
let mut remainder = Number {
|
||||
digits: dividend.clone(),
|
||||
sign: Sign::Positif,
|
||||
};
|
||||
let mut iteration = 1;
|
||||
loop {
|
||||
let mut factor = 0;
|
||||
loop {
|
||||
let temp_remainder = remainder.clone() - n2.clone();
|
||||
if temp_remainder.sign == Sign::Negatif {
|
||||
quotient.push(factor);
|
||||
break;
|
||||
}
|
||||
remainder = temp_remainder;
|
||||
factor += 1;
|
||||
}
|
||||
if n1_len == n2_len + iteration - 1 {
|
||||
break;
|
||||
}
|
||||
remainder.digits.push(n1.digits[n2_len + iteration - 1]);
|
||||
iteration += 1;
|
||||
}
|
||||
let mut res = Number {
|
||||
digits: quotient,
|
||||
sign: Sign::Positif,
|
||||
};
|
||||
res.handle_overflows();
|
||||
for digit in res.clone().digits {
|
||||
if digit != 0 {
|
||||
break;
|
||||
}
|
||||
res.digits.remove(0);
|
||||
}
|
||||
for digit in remainder.clone().digits {
|
||||
if digit != 0 || remainder.digits.len() == 1 {
|
||||
break;
|
||||
}
|
||||
remainder.digits.remove(0);
|
||||
}
|
||||
(res, remainder)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Number> for isize {
|
||||
fn from(value: Number) -> Self {
|
||||
let mut num = 0;
|
||||
for (pos, &digit) in value.digits.iter().rev().enumerate() {
|
||||
num += digit * 10isize.pow(pos as u32);
|
||||
}
|
||||
num
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Number> for String {
|
||||
fn from(value: Number) -> Self {
|
||||
let string_vec: Vec<String> = value
|
||||
.digits
|
||||
.iter()
|
||||
.map(|&digit| digit.to_string())
|
||||
.collect();
|
||||
string_vec.concat()
|
||||
}
|
||||
}
|
||||
|
||||
impl From<&str> for Number {
|
||||
fn from(value: &str) -> Self {
|
||||
let bytes = value.as_bytes();
|
||||
let (sign, idx_start) = match bytes[0] {
|
||||
b'-' => (Sign::Negatif, 1),
|
||||
_ => (Sign::Positif, 0),
|
||||
};
|
||||
let mut digits = vec![];
|
||||
for &byte in &bytes[idx_start..] {
|
||||
let digit = Self::byte_to_digit(byte);
|
||||
digits.push(digit);
|
||||
}
|
||||
Self { digits, sign }
|
||||
}
|
||||
}
|
||||
|
||||
impl From<isize> for Number {
|
||||
fn from(value: isize) -> Self {
|
||||
let mut sign = Sign::Positif;
|
||||
if value < 0 {
|
||||
sign = Sign::Negatif;
|
||||
}
|
||||
let num_len = if value > 0 {
|
||||
(value as f64 + 1.0).log10().ceil() as usize
|
||||
} else {
|
||||
1
|
||||
};
|
||||
let mut digits = vec![];
|
||||
for digit_idx in 0..num_len {
|
||||
let digit = Self::get_digit(value, digit_idx);
|
||||
digits.push(digit);
|
||||
}
|
||||
let digits = digits.iter().rev().copied().collect();
|
||||
Self { digits, sign }
|
||||
}
|
||||
}
|
||||
|
||||
impl Display for Number {
|
||||
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
||||
let number_string = self
|
||||
.digits
|
||||
.iter()
|
||||
.map(|&digit| digit.to_string())
|
||||
.collect::<Vec<String>>()
|
||||
.join("");
|
||||
match self.sign {
|
||||
Sign::Positif => write!(f, "{number_string}"),
|
||||
Sign::Negatif => write!(f, "-{number_string}"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Add for Number {
|
||||
type Output = Self;
|
||||
|
||||
fn add(self, rhs: Self) -> Self::Output {
|
||||
let self_len = self.digits.len();
|
||||
let rhs_len = rhs.digits.len();
|
||||
let mut self_digits = self.digits.clone();
|
||||
let mut rhs_digits = rhs.digits.clone();
|
||||
if self_len != rhs_len {
|
||||
let difference = (self_len).abs_diff(rhs_len);
|
||||
let pad = vec![0isize; difference];
|
||||
if min(self_len, rhs_len) == self_len {
|
||||
self_digits = [pad, self.digits].concat();
|
||||
} else {
|
||||
rhs_digits = [pad, rhs.digits].concat();
|
||||
}
|
||||
}
|
||||
let zipped = zip(self_digits.iter(), rhs_digits.iter());
|
||||
let added = zipped
|
||||
.map(|(self_digit, rhs_digit)| self_digit + rhs_digit)
|
||||
.collect();
|
||||
let mut overflown_number = Self {
|
||||
digits: added,
|
||||
sign: Sign::Positif,
|
||||
};
|
||||
overflown_number.handle_overflows();
|
||||
overflown_number
|
||||
}
|
||||
}
|
||||
|
||||
impl Sub for Number {
|
||||
type Output = Self;
|
||||
|
||||
fn sub(self, rhs: Self) -> Self::Output {
|
||||
let self_len = self.digits.len();
|
||||
let rhs_len = rhs.digits.len();
|
||||
let mut self_digits = self.digits.clone();
|
||||
let mut rhs_digits = rhs.digits.clone();
|
||||
if self_len != rhs_len {
|
||||
let difference = (self_len).abs_diff(rhs_len);
|
||||
let pad = vec![0isize; difference];
|
||||
if min(self_len, rhs_len) == self_len {
|
||||
self_digits = [pad, self.digits].concat();
|
||||
} else {
|
||||
rhs_digits = [pad, rhs.digits].concat();
|
||||
}
|
||||
}
|
||||
let zipped = zip(self_digits.iter(), rhs_digits.iter());
|
||||
let added = zipped
|
||||
.map(|(self_digit, rhs_digit)| self_digit - rhs_digit)
|
||||
.collect();
|
||||
let mut underflown_number = Self {
|
||||
digits: added,
|
||||
sign: Sign::Positif,
|
||||
};
|
||||
underflown_number.handle_underflows();
|
||||
underflown_number
|
||||
}
|
||||
}
|
||||
|
||||
impl Mul for Number {
|
||||
type Output = Self;
|
||||
|
||||
fn mul(self, rhs: Self) -> Self::Output {
|
||||
let multiplied = self.digits.iter().rev().enumerate().map(|(pos, &digit)| {
|
||||
let mut mult = digit * rhs.clone();
|
||||
mult.digits = [mult.digits, vec![0; pos]].concat();
|
||||
mult
|
||||
});
|
||||
let mut overflown_number = multiplied.reduce(|acc, num| acc + num).unwrap();
|
||||
overflown_number.handle_overflows();
|
||||
overflown_number
|
||||
}
|
||||
}
|
||||
|
||||
impl Mul<Number> for isize {
|
||||
type Output = Number;
|
||||
|
||||
fn mul(self, rhs: Number) -> Self::Output {
|
||||
let multiplied = rhs.digits.iter().map(|digit| digit * self).collect();
|
||||
let mut overflown_number = Number {
|
||||
digits: multiplied,
|
||||
sign: Sign::Positif,
|
||||
};
|
||||
overflown_number.handle_overflows();
|
||||
overflown_number
|
||||
}
|
||||
}
|
||||
|
||||
impl Mul<isize> for Number {
|
||||
type Output = Self;
|
||||
|
||||
fn mul(self, rhs: isize) -> Self::Output {
|
||||
let multiplied = self.digits.iter().map(|digit| digit * rhs).collect();
|
||||
let mut overflown_number = Self {
|
||||
digits: multiplied,
|
||||
sign: Sign::Positif,
|
||||
};
|
||||
overflown_number.handle_overflows();
|
||||
overflown_number
|
||||
}
|
||||
}
|
||||
|
||||
impl Div for Number {
|
||||
type Output = Self;
|
||||
|
||||
fn div(self, rhs: Self) -> Self::Output {
|
||||
Self::div_with_rem(self, rhs).0
|
||||
}
|
||||
}
|
||||
|
||||
impl Rem for Number {
|
||||
type Output = Self;
|
||||
|
||||
fn rem(self, rhs: Self) -> Self::Output {
|
||||
Self::div_with_rem(self, rhs).1
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod number_tests {
|
||||
use crate::number::{Number, Sign};
|
||||
|
||||
#[test]
|
||||
fn test_from_isize() {
|
||||
let number = Number::from(-1234);
|
||||
assert_eq!(
|
||||
number,
|
||||
Number {
|
||||
digits: vec![1234],
|
||||
sign: Sign::Negatif
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_get_digit() {
|
||||
let num = 12345;
|
||||
let digit_1 = Number::get_digit(num, 0);
|
||||
let digit_2 = Number::get_digit(num, 1);
|
||||
let digit_3 = Number::get_digit(num, 2);
|
||||
let digit_4 = Number::get_digit(num, 3);
|
||||
let digit_5 = Number::get_digit(num, 4);
|
||||
assert_eq!(digit_1, 5);
|
||||
assert_eq!(digit_2, 4);
|
||||
assert_eq!(digit_3, 3);
|
||||
assert_eq!(digit_4, 2);
|
||||
assert_eq!(digit_5, 1);
|
||||
}
|
||||
}
|
83
src/permutation.rs
Normal file
83
src/permutation.rs
Normal file
@ -0,0 +1,83 @@
|
||||
use std::error::Error;
|
||||
|
||||
fn factorial(num: usize) -> usize {
|
||||
let mut fact = 1;
|
||||
for n in 1..=num {
|
||||
fact *= n;
|
||||
}
|
||||
fact
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct Permutator<T: Copy + Ord> {
|
||||
pub current: Vec<T>,
|
||||
idx: usize,
|
||||
}
|
||||
|
||||
impl<T: Copy + Ord> Permutator<T> {
|
||||
pub fn new(elements: Vec<T>) -> Self {
|
||||
Self {
|
||||
current: elements,
|
||||
idx: 0,
|
||||
}
|
||||
}
|
||||
|
||||
/// Explanation
|
||||
///
|
||||
/// there are 10! possible permutations
|
||||
/// for each first number there are 9!, for each first 2 numbers 8!, etc.
|
||||
/// we check how many times we have 9! permutations before we're over 1_000_000
|
||||
/// aka. 1000000 / 9!
|
||||
/// we take the remainder and check how many times we have 8! before we?re over it
|
||||
/// (1000000 % 9!) 8!
|
||||
/// etc.
|
||||
/// every iteration we remove the digit by the idx from the original permutation
|
||||
/// we only check for 999999 permutations because we already have the first one
|
||||
///
|
||||
pub fn nth_lex(mut digits: Vec<T>, nth: usize) -> Result<Vec<T>, Box<dyn Error>> {
|
||||
digits.sort();
|
||||
if nth == 1 {
|
||||
return Ok(digits);
|
||||
}
|
||||
if nth > factorial(digits.len()) || nth == 0 {
|
||||
return Err(Box::from("Out of bounds"));
|
||||
}
|
||||
let mut perm = Vec::new();
|
||||
let num_unique_digits = digits.len();
|
||||
let mut remainder = nth - 1;
|
||||
for idx in 1..=digits.len() {
|
||||
let permutations = remainder / factorial(num_unique_digits - idx);
|
||||
remainder %= factorial(num_unique_digits - idx);
|
||||
perm.push(digits[permutations]);
|
||||
digits.remove(permutations);
|
||||
}
|
||||
Ok(perm)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Copy + Ord> Iterator for Permutator<T> {
|
||||
type Item = Vec<T>;
|
||||
/// Returns the next permutation and changes the current permutation to it
|
||||
/// This operation wraps around
|
||||
fn next(&mut self) -> Option<Self::Item> {
|
||||
if self.current.is_empty() {
|
||||
return None;
|
||||
}
|
||||
let mut digits = self.current.clone();
|
||||
if self.idx == factorial(digits.len()) {
|
||||
return None;
|
||||
}
|
||||
let mut perm = Vec::new();
|
||||
let num_unique_digits = digits.len();
|
||||
let mut remainder = 1;
|
||||
for idx in 1..=digits.len() {
|
||||
let permutations = remainder / factorial(num_unique_digits - idx);
|
||||
remainder %= factorial(num_unique_digits - idx);
|
||||
perm.push(digits[permutations]);
|
||||
digits.remove(permutations);
|
||||
}
|
||||
self.idx += 1;
|
||||
self.current = digits;
|
||||
Some(self.current.clone())
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user