diff --git a/examples/cairo/scripts/remove_duplicates/.gitignore b/examples/cairo/scripts/remove_duplicates/.gitignore new file mode 100644 index 0000000..eb5a316 --- /dev/null +++ b/examples/cairo/scripts/remove_duplicates/.gitignore @@ -0,0 +1 @@ +target diff --git a/examples/cairo/scripts/remove_duplicates/.tool-versions b/examples/cairo/scripts/remove_duplicates/.tool-versions new file mode 100644 index 0000000..fb22047 --- /dev/null +++ b/examples/cairo/scripts/remove_duplicates/.tool-versions @@ -0,0 +1 @@ +scarb 2.11.2 diff --git a/examples/cairo/scripts/remove_duplicates/Scarb.lock b/examples/cairo/scripts/remove_duplicates/Scarb.lock new file mode 100644 index 0000000..4651254 --- /dev/null +++ b/examples/cairo/scripts/remove_duplicates/Scarb.lock @@ -0,0 +1,6 @@ +# Code generated by scarb DO NOT EDIT. +version = 1 + +[[package]] +name = "remove_duplicates" +version = "0.1.0" diff --git a/examples/cairo/scripts/remove_duplicates/Scarb.toml b/examples/cairo/scripts/remove_duplicates/Scarb.toml new file mode 100644 index 0000000..02839d1 --- /dev/null +++ b/examples/cairo/scripts/remove_duplicates/Scarb.toml @@ -0,0 +1,11 @@ +[package] +name = "remove_duplicates" +version = "0.1.0" +edition = "2024_07" + +# See more keys and their definitions at https://docs.swmansion.com/scarb/docs/reference/manifest.html + +[dependencies] + +[dev-dependencies] +cairo_test = "2.11.2" diff --git a/examples/cairo/scripts/remove_duplicates/src/lib.cairo b/examples/cairo/scripts/remove_duplicates/src/lib.cairo new file mode 100644 index 0000000..44b2a49 --- /dev/null +++ b/examples/cairo/scripts/remove_duplicates/src/lib.cairo @@ -0,0 +1 @@ +pub mod remove_duplicates; diff --git a/examples/cairo/scripts/remove_duplicates/src/remove_duplicates.cairo b/examples/cairo/scripts/remove_duplicates/src/remove_duplicates.cairo new file mode 100644 index 0000000..1d6695d --- /dev/null +++ b/examples/cairo/scripts/remove_duplicates/src/remove_duplicates.cairo @@ -0,0 +1,94 @@ +use core::array::ArrayTrait; + +/// Removes duplicates from a sorted array and returns the number of unique elements. +/// +/// # Arguments +/// * `ref nums` - A reference to the sorted array of integers to be modified +/// +/// # Returns +/// * The number of unique elements in the array +/// +/// # Cairo-specific considerations +/// Since Cairo arrays are immutable by design, this implementation simulates +/// in-place modification by creating a new array of unique elements and then +/// replacing the original array's content with these unique elements. +pub fn remove_duplicate(ref nums: Array) -> u32 { + if nums.len() == 0 { + return 0; + } + + let mut unique_elements: Array = ArrayTrait::new(); + + unique_elements.append(*nums.at(0)); + + let mut i: u32 = 1; + while i < nums.len() { + if *nums.at(i) != *unique_elements.at(unique_elements.len() - 1) { + unique_elements.append(*nums.at(i)); + } + i += 1; + } + + let unique_count = unique_elements.len(); + + // Create a new empty array and replace nums with the unique elements + // This is a workaround since we can't directly modify the original array in Cairo + let mut result: Array = ArrayTrait::new(); + + let mut j: u32 = 0; + while j < unique_elements.len() { + result.append(*unique_elements.at(j)); + j += 1; + } + + loop { + match nums.pop_front() { + Option::Some(_) => {}, + Option::None => { break; }, + }; + } + + let mut k: u32 = 0; + while k < result.len() { + nums.append(*result.at(k)); + k += 1; + } + + unique_count +} + +/// An alternative implementation that might be more gas-efficient +/// but doesn't simulate true in-place modification as in traditional languages. +pub fn remove_duplicates_optimized(ref nums: Array) -> u32 { + if nums.len() == 0 { + return 0; + } + + let mut result: Array = ArrayTrait::new(); + result.append(*nums.at(0)); + + let mut i: u32 = 1; + while i < nums.len() { + if *nums.at(i) != *result.at(result.len() - 1) { + result.append(*nums.at(i)); + } + i += 1; + } + + let unique_count = result.len(); + + loop { + match nums.pop_front() { + Option::Some(_) => {}, + Option::None => { break; }, + }; + } + + let mut j: u32 = 0; + while j < result.len() { + nums.append(*result.at(j)); + j += 1; + } + + unique_count +} diff --git a/examples/cairo/scripts/remove_duplicates/tests/test_remove_duplicates.cairo b/examples/cairo/scripts/remove_duplicates/tests/test_remove_duplicates.cairo new file mode 100644 index 0000000..04a449e --- /dev/null +++ b/examples/cairo/scripts/remove_duplicates/tests/test_remove_duplicates.cairo @@ -0,0 +1,122 @@ +// examples/cairo/scripts/remove_duplicate/tests/test_remove_duplicates.cairo + +use core::array::ArrayTrait; +use remove_duplicates::remove_duplicates::{remove_duplicate, remove_duplicates_optimized}; + + +#[test] +fn test_remove_duplicates_empty_array() { + let mut nums: Array = ArrayTrait::new(); + let result = remove_duplicate(ref nums); + assert(result == 0, 'Should return 0 for empty array'); +} + +#[test] +fn test_remove_duplicates_no_duplicates() { + let mut nums: Array = ArrayTrait::new(); + nums.append(1); + nums.append(2); + nums.append(3); + + let result = remove_duplicate(ref nums); + + assert(result == 3, 'Should return 3 unique elements'); + assert(*nums.at(0) == 1, 'First element should be 1'); + assert(*nums.at(1) == 2, 'Second element should be 2'); + assert(*nums.at(2) == 3, 'Third element should be 3'); +} + +#[test] +fn test_remove_duplicates_example1() { + // Example 1: nums = [1,1,2] + let mut nums: Array = ArrayTrait::new(); + nums.append(1); + nums.append(1); + nums.append(2); + + let result = remove_duplicate(ref nums); + + assert(result == 2, 'Should return 2 unique elements'); + assert(*nums.at(0) == 1, 'First element should be 1'); + assert(*nums.at(1) == 2, 'Second element should be 2'); +} + +#[test] +fn test_remove_duplicates_example2() { + // Example 2: nums = [0,0,1,1,1,2,2,3,3,4] + let mut nums: Array = ArrayTrait::new(); + nums.append(0); + nums.append(0); + nums.append(1); + nums.append(1); + nums.append(1); + nums.append(2); + nums.append(2); + nums.append(3); + nums.append(3); + nums.append(4); + + let result = remove_duplicate(ref nums); + + assert(result == 5, 'Should return 5 unique elements'); + assert(*nums.at(0) == 0, 'First element should be 0'); + assert(*nums.at(1) == 1, 'Second element should be 1'); + assert(*nums.at(2) == 2, 'Third element should be 2'); + assert(*nums.at(3) == 3, 'Fourth element should be 3'); + assert(*nums.at(4) == 4, 'Fifth element should be 4'); +} + +#[test] +fn test_remove_duplicates_all_duplicates() { + let mut nums: Array = ArrayTrait::new(); + nums.append(1); + nums.append(1); + nums.append(1); + nums.append(1); + + let result = remove_duplicate(ref nums); + + assert(result == 1, 'Should return 1 unique element'); + assert(*nums.at(0) == 1, 'First element should be 1'); +} + +// Tests for the optimized version +#[test] +fn test_remove_duplicates_optimized_example1() { + // Example 1: nums = [1,1,2] + let mut nums: Array = ArrayTrait::new(); + nums.append(1); + nums.append(1); + nums.append(2); + + let result = remove_duplicates_optimized(ref nums); + + assert(result == 2, 'Should return 2 unique elements'); + assert(*nums.at(0) == 1, 'First element should be 1'); + assert(*nums.at(1) == 2, 'Second element should be 2'); +} + +#[test] +fn test_remove_duplicates_optimized_example2() { + // Example 2: nums = [0,0,1,1,1,2,2,3,3,4] + let mut nums: Array = ArrayTrait::new(); + nums.append(0); + nums.append(0); + nums.append(1); + nums.append(1); + nums.append(1); + nums.append(2); + nums.append(2); + nums.append(3); + nums.append(3); + nums.append(4); + + let result = remove_duplicates_optimized(ref nums); + + assert(result == 5, 'Should return 5 unique elements'); + assert(*nums.at(0) == 0, 'First element should be 0'); + assert(*nums.at(1) == 1, 'Second element should be 1'); + assert(*nums.at(2) == 2, 'Third element should be 2'); + assert(*nums.at(3) == 3, 'Fourth element should be 3'); + assert(*nums.at(4) == 4, 'Fifth element should be 4'); +}