From 9460883cbf3a4f8406b849ce0e7346653571fe1a Mon Sep 17 00:00:00 2001 From: akhercha Date: Thu, 28 Sep 2023 16:49:31 +0200 Subject: [PATCH 1/5] feat(array_drop_duplicates): Added drop_duplicated & its unit tests --- src/data_structures/src/array_ext.cairo | 28 +++++++ .../src/tests/array_ext_test.cairo | 79 ++++++++++++++++++- 2 files changed, 106 insertions(+), 1 deletion(-) diff --git a/src/data_structures/src/array_ext.cairo b/src/data_structures/src/array_ext.cairo index a1420a3c..e5cc6148 100644 --- a/src/data_structures/src/array_ext.cairo +++ b/src/data_structures/src/array_ext.cairo @@ -22,6 +22,7 @@ trait ArrayTraitExt { self: @Array ) -> Option; fn dedup>(self: @Array) -> Array; + fn drop_duplicates>(self: @Array) -> Array; } trait SpanTraitExt { @@ -45,6 +46,7 @@ trait SpanTraitExt { self: Span ) -> Option; fn dedup>(self: Span) -> Array; + fn drop_duplicates>(self: Span) -> Array; } impl ArrayImpl, impl TDrop: Drop> of ArrayTraitExt { @@ -141,6 +143,10 @@ impl ArrayImpl, impl TDrop: Drop> of ArrayTraitExt fn dedup>(mut self: @Array) -> Array { self.span().dedup() } + + fn drop_duplicates>(mut self: @Array) -> Array { + self.span().drop_duplicates() + } } impl SpanImpl, impl TDrop: Drop> of SpanTraitExt { @@ -385,4 +391,26 @@ impl SpanImpl, impl TDrop: Drop> of SpanTraitExt { ret } + + fn drop_duplicates>(mut self: Span) -> Array { + let mut ret = array![]; + loop { + match self.pop_front() { + Option::Some(v) => { + let shortest: Span = if (self.len() <= 1) || (ret.len() <= self.len()) { + ret.span() + } else { + self + }; + if !shortest.contains(*v) { + ret.append(*v); + } + }, + Option::None => { + break; + } + }; + }; + ret + } } diff --git a/src/data_structures/src/tests/array_ext_test.cairo b/src/data_structures/src/tests/array_ext_test.cairo index e4f95426..dd864213 100644 --- a/src/data_structures/src/tests/array_ext_test.cairo +++ b/src/data_structures/src/tests/array_ext_test.cairo @@ -1,6 +1,5 @@ use core::option::OptionTrait; use array::{ArrayTrait, SpanTrait}; - use alexandria_data_structures::array_ext::{ArrayTraitExt, SpanTraitExt}; // dedup @@ -1068,6 +1067,84 @@ fn index_of_max_last_span() { assert(arr.len() == 3, 'arr should not be consummed'); } +// drop_duplicates + +#[test] +#[available_gas(2000000)] +fn drop_duplicates() { + let mut arr = array![32_u128, 256_u128, 128_u128, 256_u128, 1024_u128]; + let mut out_arr = arr.drop_duplicates(); + assert(out_arr.len() == 4, 'Duplicates should be dropped'); + assert(*out_arr[0] == 32_u128, 'Should be 32'); + assert(*out_arr[1] == 256_u128, 'Should be 256'); + assert(*out_arr[2] == 128_u128, 'Should be 128'); + assert(*out_arr[3] == 1024_u128, 'Should be 1024'); +} + +#[test] +#[available_gas(2000000)] +fn drop_duplicates_all() { + let mut arr = array![84_u128, 84_u128, 84_u128]; + let mut out_arr = arr.drop_duplicates(); + assert(out_arr.len() == 1, 'Duplicates should be dropped'); + assert(*out_arr[0] == 84_u128, 'Should be 128'); +} + +#[test] +#[available_gas(2000000)] +fn drop_duplicates_middle() { + let mut arr = array![128_u128, 256_u128, 84_u128, 84_u128, 84_u128, 1_u128]; + let mut out_arr = arr.drop_duplicates(); + assert(out_arr.len() == 4, 'Duplicates should be dropped'); + assert(*out_arr[0] == 128_u128, 'Should be 128'); + assert(*out_arr[1] == 256_u128, 'Should be 256'); + assert(*out_arr[2] == 84_u128, 'Should be 84'); + assert(*out_arr[3] == 1_u128, 'Should be 1'); +} + +#[test] +#[available_gas(2000000)] +fn drop_duplicates_start() { + let mut arr = array![16_u128, 16_u128, 16_u128, 128_u128, 64_u128, 32_u128]; + let mut out_arr = arr.drop_duplicates(); + assert(out_arr.len() == 4, 'Duplicates should be dropped'); + assert(*out_arr[0] == 16_u128, 'Should be 16'); + assert(*out_arr[1] == 128_u128, 'Should be 128'); + assert(*out_arr[2] == 64_u128, 'Should be 64'); + assert(*out_arr[3] == 32_u128, 'Should be 32'); +} + +#[test] +#[available_gas(2000000)] +fn drop_duplicates_end() { + let mut arr = array![32_u128, 16_u128, 64_u128, 128_u128, 128_u128, 128_u128]; + let mut out_arr = arr.drop_duplicates(); + assert(out_arr.len() == 4, 'Duplicates should be dropped'); + assert(*out_arr[0] == 32_u128, 'Should be 32'); + assert(*out_arr[1] == 16_u128, 'Should be 16'); + assert(*out_arr[2] == 64_u128, 'Should be 64'); + assert(*out_arr[3] == 128_u128, 'Should be 128'); +} + +#[test] +#[available_gas(2000000)] +fn drop_duplicates_without_duplicates() { + let mut arr = array![42_u128, 84_u128, 21_u128]; + let mut out_arr = arr.drop_duplicates(); + assert(out_arr.len() == 3, 'No values should drop'); + assert(*out_arr[0] == 42_u128, 'Should be 42'); + assert(*out_arr[1] == 84_u128, 'Should be 84'); + assert(*out_arr[2] == 21_u128, 'Should be 21'); +} + +#[test] +#[available_gas(2000000)] +fn drop_duplicates_empty() { + let mut arr: Array = array![]; + let mut out_arr = arr.drop_duplicates(); + assert(out_arr.len() == 0, 'out_arr should be empty'); +} + // Utility fn From 4ca789bd8fcb060aaeeec4c6664d6cd79bbb0eb0 Mon Sep 17 00:00:00 2001 From: akhercha Date: Thu, 28 Sep 2023 16:55:23 +0200 Subject: [PATCH 2/5] feat(array_drop_duplicates): Less gaz --- src/data_structures/src/array_ext.cairo | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/data_structures/src/array_ext.cairo b/src/data_structures/src/array_ext.cairo index e5cc6148..bd574589 100644 --- a/src/data_structures/src/array_ext.cairo +++ b/src/data_structures/src/array_ext.cairo @@ -395,13 +395,13 @@ impl SpanImpl, impl TDrop: Drop> of SpanTraitExt { fn drop_duplicates>(mut self: Span) -> Array { let mut ret = array![]; loop { + let shortest: Span = if (self.len() <= 1) || (ret.len() <= self.len()) { + ret.span() + } else { + self + }; match self.pop_front() { Option::Some(v) => { - let shortest: Span = if (self.len() <= 1) || (ret.len() <= self.len()) { - ret.span() - } else { - self - }; if !shortest.contains(*v) { ret.append(*v); } From 8dae75bd4a4c8272faa87b293f5997323cc125dc Mon Sep 17 00:00:00 2001 From: akhercha Date: Thu, 28 Sep 2023 17:30:17 +0200 Subject: [PATCH 3/5] feat(array_drop_duplicates): Quick update for unit tests names --- .../src/tests/array_ext_test.cairo | 34 +++++++++---------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/src/data_structures/src/tests/array_ext_test.cairo b/src/data_structures/src/tests/array_ext_test.cairo index dd864213..ba348e41 100644 --- a/src/data_structures/src/tests/array_ext_test.cairo +++ b/src/data_structures/src/tests/array_ext_test.cairo @@ -1092,19 +1092,15 @@ fn drop_duplicates_all() { #[test] #[available_gas(2000000)] -fn drop_duplicates_middle() { - let mut arr = array![128_u128, 256_u128, 84_u128, 84_u128, 84_u128, 1_u128]; +fn drop_duplicates_none() { + let mut arr: Array = array![]; let mut out_arr = arr.drop_duplicates(); - assert(out_arr.len() == 4, 'Duplicates should be dropped'); - assert(*out_arr[0] == 128_u128, 'Should be 128'); - assert(*out_arr[1] == 256_u128, 'Should be 256'); - assert(*out_arr[2] == 84_u128, 'Should be 84'); - assert(*out_arr[3] == 1_u128, 'Should be 1'); + assert(out_arr.len() == 0, 'out_arr should be empty'); } #[test] #[available_gas(2000000)] -fn drop_duplicates_start() { +fn drop_duplicates_at_start() { let mut arr = array![16_u128, 16_u128, 16_u128, 128_u128, 64_u128, 32_u128]; let mut out_arr = arr.drop_duplicates(); assert(out_arr.len() == 4, 'Duplicates should be dropped'); @@ -1116,7 +1112,19 @@ fn drop_duplicates_start() { #[test] #[available_gas(2000000)] -fn drop_duplicates_end() { +fn drop_duplicates_at_middle() { + let mut arr = array![128_u128, 256_u128, 84_u128, 84_u128, 84_u128, 1_u128]; + let mut out_arr = arr.drop_duplicates(); + assert(out_arr.len() == 4, 'Duplicates should be dropped'); + assert(*out_arr[0] == 128_u128, 'Should be 128'); + assert(*out_arr[1] == 256_u128, 'Should be 256'); + assert(*out_arr[2] == 84_u128, 'Should be 84'); + assert(*out_arr[3] == 1_u128, 'Should be 1'); +} + +#[test] +#[available_gas(2000000)] +fn drop_duplicates_at_end() { let mut arr = array![32_u128, 16_u128, 64_u128, 128_u128, 128_u128, 128_u128]; let mut out_arr = arr.drop_duplicates(); assert(out_arr.len() == 4, 'Duplicates should be dropped'); @@ -1137,14 +1145,6 @@ fn drop_duplicates_without_duplicates() { assert(*out_arr[2] == 21_u128, 'Should be 21'); } -#[test] -#[available_gas(2000000)] -fn drop_duplicates_empty() { - let mut arr: Array = array![]; - let mut out_arr = arr.drop_duplicates(); - assert(out_arr.len() == 0, 'out_arr should be empty'); -} - // Utility fn From 730121272acd68b996b13c79d99db9fbe77bfa4f Mon Sep 17 00:00:00 2001 From: akhercha Date: Fri, 29 Sep 2023 08:50:11 +0200 Subject: [PATCH 4/5] feat(array_drop_duplicates): Updated drop_duplicates() name to unique() --- src/data_structures/src/array_ext.cairo | 10 +++--- .../src/tests/array_ext_test.cairo | 31 +++++++++---------- 2 files changed, 20 insertions(+), 21 deletions(-) diff --git a/src/data_structures/src/array_ext.cairo b/src/data_structures/src/array_ext.cairo index bd574589..867f321a 100644 --- a/src/data_structures/src/array_ext.cairo +++ b/src/data_structures/src/array_ext.cairo @@ -22,7 +22,7 @@ trait ArrayTraitExt { self: @Array ) -> Option; fn dedup>(self: @Array) -> Array; - fn drop_duplicates>(self: @Array) -> Array; + fn unique>(self: @Array) -> Array; } trait SpanTraitExt { @@ -46,7 +46,7 @@ trait SpanTraitExt { self: Span ) -> Option; fn dedup>(self: Span) -> Array; - fn drop_duplicates>(self: Span) -> Array; + fn unique>(self: Span) -> Array; } impl ArrayImpl, impl TDrop: Drop> of ArrayTraitExt { @@ -144,8 +144,8 @@ impl ArrayImpl, impl TDrop: Drop> of ArrayTraitExt self.span().dedup() } - fn drop_duplicates>(mut self: @Array) -> Array { - self.span().drop_duplicates() + fn unique>(mut self: @Array) -> Array { + self.span().unique() } } @@ -392,7 +392,7 @@ impl SpanImpl, impl TDrop: Drop> of SpanTraitExt { ret } - fn drop_duplicates>(mut self: Span) -> Array { + fn unique>(mut self: Span) -> Array { let mut ret = array![]; loop { let shortest: Span = if (self.len() <= 1) || (ret.len() <= self.len()) { diff --git a/src/data_structures/src/tests/array_ext_test.cairo b/src/data_structures/src/tests/array_ext_test.cairo index ba348e41..63c2178b 100644 --- a/src/data_structures/src/tests/array_ext_test.cairo +++ b/src/data_structures/src/tests/array_ext_test.cairo @@ -1067,13 +1067,13 @@ fn index_of_max_last_span() { assert(arr.len() == 3, 'arr should not be consummed'); } -// drop_duplicates +// unique #[test] #[available_gas(2000000)] -fn drop_duplicates() { +fn unique() { let mut arr = array![32_u128, 256_u128, 128_u128, 256_u128, 1024_u128]; - let mut out_arr = arr.drop_duplicates(); + let mut out_arr = arr.unique(); assert(out_arr.len() == 4, 'Duplicates should be dropped'); assert(*out_arr[0] == 32_u128, 'Should be 32'); assert(*out_arr[1] == 256_u128, 'Should be 256'); @@ -1083,26 +1083,26 @@ fn drop_duplicates() { #[test] #[available_gas(2000000)] -fn drop_duplicates_all() { +fn unique_all() { let mut arr = array![84_u128, 84_u128, 84_u128]; - let mut out_arr = arr.drop_duplicates(); + let mut out_arr = arr.unique(); assert(out_arr.len() == 1, 'Duplicates should be dropped'); assert(*out_arr[0] == 84_u128, 'Should be 128'); } #[test] #[available_gas(2000000)] -fn drop_duplicates_none() { +fn unique_none() { let mut arr: Array = array![]; - let mut out_arr = arr.drop_duplicates(); + let mut out_arr = arr.unique(); assert(out_arr.len() == 0, 'out_arr should be empty'); } #[test] #[available_gas(2000000)] -fn drop_duplicates_at_start() { +fn unique_at_start() { let mut arr = array![16_u128, 16_u128, 16_u128, 128_u128, 64_u128, 32_u128]; - let mut out_arr = arr.drop_duplicates(); + let mut out_arr = arr.unique(); assert(out_arr.len() == 4, 'Duplicates should be dropped'); assert(*out_arr[0] == 16_u128, 'Should be 16'); assert(*out_arr[1] == 128_u128, 'Should be 128'); @@ -1112,9 +1112,9 @@ fn drop_duplicates_at_start() { #[test] #[available_gas(2000000)] -fn drop_duplicates_at_middle() { +fn unique_at_middle() { let mut arr = array![128_u128, 256_u128, 84_u128, 84_u128, 84_u128, 1_u128]; - let mut out_arr = arr.drop_duplicates(); + let mut out_arr = arr.unique(); assert(out_arr.len() == 4, 'Duplicates should be dropped'); assert(*out_arr[0] == 128_u128, 'Should be 128'); assert(*out_arr[1] == 256_u128, 'Should be 256'); @@ -1124,9 +1124,9 @@ fn drop_duplicates_at_middle() { #[test] #[available_gas(2000000)] -fn drop_duplicates_at_end() { +fn unique_at_end() { let mut arr = array![32_u128, 16_u128, 64_u128, 128_u128, 128_u128, 128_u128]; - let mut out_arr = arr.drop_duplicates(); + let mut out_arr = arr.unique(); assert(out_arr.len() == 4, 'Duplicates should be dropped'); assert(*out_arr[0] == 32_u128, 'Should be 32'); assert(*out_arr[1] == 16_u128, 'Should be 16'); @@ -1136,16 +1136,15 @@ fn drop_duplicates_at_end() { #[test] #[available_gas(2000000)] -fn drop_duplicates_without_duplicates() { +fn unique_without_duplicates() { let mut arr = array![42_u128, 84_u128, 21_u128]; - let mut out_arr = arr.drop_duplicates(); + let mut out_arr = arr.unique(); assert(out_arr.len() == 3, 'No values should drop'); assert(*out_arr[0] == 42_u128, 'Should be 42'); assert(*out_arr[1] == 84_u128, 'Should be 84'); assert(*out_arr[2] == 21_u128, 'Should be 21'); } - // Utility fn fn get_felt252_array() -> Array { From 3c4203e6561447efed6af952a7fbfe11a3ef4039 Mon Sep 17 00:00:00 2001 From: akhercha Date: Fri, 29 Sep 2023 11:47:18 +0200 Subject: [PATCH 5/5] Update src/data_structures/src/array_ext.cairo No longer use the shortest span for the check of the element to append. Co-authored-by: gaetbout --- src/data_structures/src/array_ext.cairo | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/src/data_structures/src/array_ext.cairo b/src/data_structures/src/array_ext.cairo index 867f321a..aa022d3d 100644 --- a/src/data_structures/src/array_ext.cairo +++ b/src/data_structures/src/array_ext.cairo @@ -395,14 +395,9 @@ impl SpanImpl, impl TDrop: Drop> of SpanTraitExt { fn unique>(mut self: Span) -> Array { let mut ret = array![]; loop { - let shortest: Span = if (self.len() <= 1) || (ret.len() <= self.len()) { - ret.span() - } else { - self - }; match self.pop_front() { Option::Some(v) => { - if !shortest.contains(*v) { + if !ret.contains(*v) { ret.append(*v); } },