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; +}