From c53c05e5b2a6f8213fff81a783f648bdbae71f56 Mon Sep 17 00:00:00 2001 From: epriestley Date: Tue, 30 Jun 2020 06:35:27 -0700 Subject: [PATCH] Introduce "phutil_partition()" and natural case sorting for "msortv(...)" Summary: Ref T13546. Pull some small utility changes out of the deeper stack of "land/markers" changes. "phutil_partition()" makes it easier to write code that loops over a list grouping elements, then acts on each group. This kind of code is not terribly common, but often feels awkward when implemented with raw primitives. "msortv()" can support "natural" sorting, which sorts "feature1", "feature2", ..., "feature10" in a more human-readable order. Test Plan: Ran unit tests, used new behaviors elsewhere in "arc markers" workflows. Maniphest Tasks: T13546 Differential Revision: https://secure.phabricator.com/D21371 --- src/__phutil_library_map__.php | 3 ++ src/utils/__tests__/PhutilUtilsTestCase.php | 34 ++++++++++++++++++ src/utils/utils.php | 39 ++++++++++++++++++++- 3 files changed, 75 insertions(+), 1 deletion(-) diff --git a/src/__phutil_library_map__.php b/src/__phutil_library_map__.php index 493f83d1..a4d2faed 100644 --- a/src/__phutil_library_map__.php +++ b/src/__phutil_library_map__.php @@ -925,6 +925,8 @@ phutil_register_library_map(array( 'mpull' => 'utils/utils.php', 'msort' => 'utils/utils.php', 'msortv' => 'utils/utils.php', + 'msortv_internal' => 'utils/utils.php', + 'msortv_natural' => 'utils/utils.php', 'newv' => 'utils/utils.php', 'nonempty' => 'utils/utils.php', 'phlog' => 'error/phlog.php', @@ -979,6 +981,7 @@ phutil_register_library_map(array( 'phutil_loggable_string' => 'utils/utils.php', 'phutil_microseconds_since' => 'utils/utils.php', 'phutil_parse_bytes' => 'utils/viewutils.php', + 'phutil_partition' => 'utils/utils.php', 'phutil_passthru' => 'future/exec/execx.php', 'phutil_person' => 'internationalization/pht.php', 'phutil_register_library' => 'init/lib/core.php', diff --git a/src/utils/__tests__/PhutilUtilsTestCase.php b/src/utils/__tests__/PhutilUtilsTestCase.php index e1bade52..75fe4692 100644 --- a/src/utils/__tests__/PhutilUtilsTestCase.php +++ b/src/utils/__tests__/PhutilUtilsTestCase.php @@ -966,4 +966,38 @@ final class PhutilUtilsTestCase extends PhutilTestCase { } } + public function testArrayPartition() { + $map = array( + 'empty' => array( + array(), + array(), + ), + 'unique' => array( + array('a' => 'a', 'b' => 'b', 'c' => 'c'), + array(array('a' => 'a'), array('b' => 'b'), array('c' => 'c')), + ), + 'xy' => array( + array('a' => 'x', 'b' => 'x', 'c' => 'y', 'd' => 'y'), + array( + array('a' => 'x', 'b' => 'x'), + array('c' => 'y', 'd' => 'y'), + ), + ), + 'multi' => array( + array('a' => true, 'b' => true, 'c' => false, 'd' => true), + array( + array('a' => true, 'b' => true), + array('c' => false), + array('d' => true), + ), + ), + ); + + foreach ($map as $name => $item) { + list($input, $expect) = $item; + $actual = phutil_partition($input); + $this->assertEqual($expect, $actual, pht('Partition of "%s"', $name)); + } + } + } diff --git a/src/utils/utils.php b/src/utils/utils.php index 0bb1b4f8..4c44d7b7 100644 --- a/src/utils/utils.php +++ b/src/utils/utils.php @@ -433,6 +433,14 @@ function msort(array $list, $method) { * @return list Objects ordered by the vectors. */ function msortv(array $list, $method) { + return msortv_internal($list, $method, SORT_STRING); +} + +function msortv_natural(array $list, $method) { + return msortv_internal($list, $method, SORT_NATURAL | SORT_FLAG_CASE); +} + +function msortv_internal(array $list, $method, $flags) { $surrogate = mpull($list, $method); $index = 0; @@ -455,7 +463,7 @@ function msortv(array $list, $method) { $surrogate[$key] = (string)$value; } - asort($surrogate, SORT_STRING); + asort($surrogate, $flags); $result = array(); foreach ($surrogate as $key => $value) { @@ -1966,3 +1974,32 @@ function phutil_glue(array $list, $glue) { return array_select_keys($tmp, $keys); } + +function phutil_partition(array $map) { + $partitions = array(); + + $partition = array(); + $is_first = true; + $partition_value = null; + + foreach ($map as $key => $value) { + if (!$is_first) { + if ($partition_value === $value) { + $partition[$key] = $value; + continue; + } + + $partitions[] = $partition; + } + + $is_first = false; + $partition = array($key => $value); + $partition_value = $value; + } + + if ($partition) { + $partitions[] = $partition; + } + + return $partitions; +}