Laravel 集合:使用全键名称展平
Laravel collections: Flatten with full key name
有没有办法使用 Laravel 集合来展平具有键 "namespace" 的数组。类似于:
$a = collect([
'id' => 1,
'data' => [
'a' => 2,
'b' => 3
]
]);
$a = $a->flattenWithKeysNamespace(); // <-- this does not exists
// Should returns:
// ['a' => 1, 'data.b' => 2, 'data.c' => 3]; // <-- I would like this.
我知道我可以在原始 PHP 中或使用一些集合函数的集合来做到这一点,但有时我会遗漏 Laravel 集合文档中的某些内容。那么有没有一种简单的方法可以使用 Collection 函数来做到这一点?
我认为你是对的,没有 "Laravel way" 可以做到这一点。如果您愿意将 Collection
转换为数组,this 之类的答案在 PHP 中显示了这样做的方法,但是由于您提到了原始 PHP 我假设您已经找到了这种解决方案。
我认为使用 Collection
方法的最佳选择是编写与我链接的函数类似的函数,但使用 flatMap()
之类的函数并在元素为也是合集
如果您不关心转换的深度级别,我认为对您来说最简单的选择就是 array_dot
辅助函数。如果您想更精细地控制递归的深度,以及是否使用点分隔的数组键,我已经编写了一个可以执行此操作的集合宏。通常 collect($array)->collapse()
维护字符串键,但非增量数字键仍然会丢失,即使类型强制为字符串也是如此。我最近需要维护它们。
将其放入您的 AppServiceProvider::boot()
方法中:
/**
* Flatten an array while keeping it's keys, even non-incremental numeric ones, in tact.
*
* Unless $dotNotification is set to true, if nested keys are the same as any
* parent ones, the nested ones will supersede them.
*
* @param int $depth How many levels deep to flatten the array
* @param bool $dotNotation Maintain all parent keys in dot notation
*/
Collection::macro('flattenKeepKeys', function ($depth = 1, $dotNotation = false) {
if ($depth) {
$newArray = [];
foreach ($this->items as $parentKey => $value) {
if (is_array($value)) {
$valueKeys = array_keys($value);
foreach ($valueKeys as $key) {
$subValue = $value[$key];
$newKey = $key;
if ($dotNotation) {
$newKey = "$parentKey.$key";
if ($dotNotation !== true) {
$newKey = "$dotNotation.$newKey";
}
if (is_array($value[$key])) {
$subValue = collect($value[$key])->flattenKeepKeys($depth - 1, $newKey)->toArray();
}
}
$newArray[$newKey] = $subValue;
}
} else {
$newArray[$parentKey] = $value;
}
}
$this->items = collect($newArray)->flattenKeepKeys(--$depth, $dotNotation)->toArray();
}
return collect($this->items);
});
然后您可以调用 collect($a)->flattenKeepKeys(1, true);
并返回您所期望的结果。
有没有办法使用 Laravel 集合来展平具有键 "namespace" 的数组。类似于:
$a = collect([
'id' => 1,
'data' => [
'a' => 2,
'b' => 3
]
]);
$a = $a->flattenWithKeysNamespace(); // <-- this does not exists
// Should returns:
// ['a' => 1, 'data.b' => 2, 'data.c' => 3]; // <-- I would like this.
我知道我可以在原始 PHP 中或使用一些集合函数的集合来做到这一点,但有时我会遗漏 Laravel 集合文档中的某些内容。那么有没有一种简单的方法可以使用 Collection 函数来做到这一点?
我认为你是对的,没有 "Laravel way" 可以做到这一点。如果您愿意将 Collection
转换为数组,this 之类的答案在 PHP 中显示了这样做的方法,但是由于您提到了原始 PHP 我假设您已经找到了这种解决方案。
我认为使用 Collection
方法的最佳选择是编写与我链接的函数类似的函数,但使用 flatMap()
之类的函数并在元素为也是合集
如果您不关心转换的深度级别,我认为对您来说最简单的选择就是 array_dot
辅助函数。如果您想更精细地控制递归的深度,以及是否使用点分隔的数组键,我已经编写了一个可以执行此操作的集合宏。通常 collect($array)->collapse()
维护字符串键,但非增量数字键仍然会丢失,即使类型强制为字符串也是如此。我最近需要维护它们。
将其放入您的 AppServiceProvider::boot()
方法中:
/**
* Flatten an array while keeping it's keys, even non-incremental numeric ones, in tact.
*
* Unless $dotNotification is set to true, if nested keys are the same as any
* parent ones, the nested ones will supersede them.
*
* @param int $depth How many levels deep to flatten the array
* @param bool $dotNotation Maintain all parent keys in dot notation
*/
Collection::macro('flattenKeepKeys', function ($depth = 1, $dotNotation = false) {
if ($depth) {
$newArray = [];
foreach ($this->items as $parentKey => $value) {
if (is_array($value)) {
$valueKeys = array_keys($value);
foreach ($valueKeys as $key) {
$subValue = $value[$key];
$newKey = $key;
if ($dotNotation) {
$newKey = "$parentKey.$key";
if ($dotNotation !== true) {
$newKey = "$dotNotation.$newKey";
}
if (is_array($value[$key])) {
$subValue = collect($value[$key])->flattenKeepKeys($depth - 1, $newKey)->toArray();
}
}
$newArray[$newKey] = $subValue;
}
} else {
$newArray[$parentKey] = $value;
}
}
$this->items = collect($newArray)->flattenKeepKeys(--$depth, $dotNotation)->toArray();
}
return collect($this->items);
});
然后您可以调用 collect($a)->flattenKeepKeys(1, true);
并返回您所期望的结果。