Skip to content

Commit

Permalink
Fix #20306: Add new yii\helpers\ArrayHelper::flatten() method
Browse files Browse the repository at this point in the history
  • Loading branch information
xcopy authored Jan 6, 2025
1 parent 3fc7e71 commit f94017c
Show file tree
Hide file tree
Showing 6 changed files with 452 additions and 49 deletions.
137 changes: 137 additions & 0 deletions docs/guide-ru/helper-array.md
Original file line number Diff line number Diff line change
Expand Up @@ -348,3 +348,140 @@ ArrayHelper::isIn('a', new(ArrayObject['a']));
ArrayHelper::isSubset(new(ArrayObject['a', 'c']), new(ArrayObject['a', 'b', 'c'])

```

## Преобразование многомерных массивов <span id="flattening-arrays"></span>

Метод `ArrayHelper::flatten()` позволяет преобразовать многомерный массив в одномерный, объединяя ключи.

### Основное использование

Чтобы преобразовать вложенный массив, просто передайте массив в метод `flatten()`:

```php
$array = [
'a' => [
'b' => [
'c' => 1,
'd' => 2,
],
'e' => 3,
],
'f' => 4,
];

$flattenedArray = ArrayHelper::flatten($array);
// Результат:
// [
// 'a.b.c' => 1,
// 'a.b.d' => 2,
// 'a.e' => 3,
// 'f' => 4,
// ]
```

### Пользовательский разделитель

Вы можете указать пользовательский (т.е. отличный от значения по умолчанию: `.`) разделитель для объединения ключей:

```php
$array = [
'a' => [
'b' => [
'c' => 1,
'd' => 2,
],
'e' => 3,
],
'f' => 4,
];

$flattenedArray = ArrayHelper::flatten($array, '_');
// Результат:
// [
// 'a_b_c' => 1,
// 'a_b_d' => 2,
// 'a_e' => 3,
// 'f' => 4,
// ]
```

### Обработка специальных символов в ключах

Метод `flatten()` может обрабатывать ключи со специальными символами:

```php
$array = [
'a.b' => [
'c.d' => 1,
],
'e.f' => 2,
];

$flattenedArray = ArrayHelper::flatten($array);
// Результат:
// [
// 'a.b.c.d' => 1,
// 'e.f' => 2,
// ]
```

### Смешанные типы данных

Метод `flatten()` работает с массивами, содержащими различные типы данных:

```php
$array = [
'a' => [
'b' => 'string',
'c' => 123,
'd' => true,
'e' => null,
],
'f' => [1, 2, 3],
];

$flattenedArray = ArrayHelper::flatten($array);
// Результат:
// [
// 'a.b' => 'string',
// 'a.c' => 123,
// 'a.d' => true,
// 'a.e' => null,
// 'f.0' => 1,
// 'f.1' => 2,
// 'f.2' => 3,
// ]
```

### Краевые случаи

Метод `flatten()` обрабатывает различные краевые случаи, такие как пустые массивы и значения, не являющиеся массивами:

```php
// Пустой массив
$array = [];
$flattenedArray = ArrayHelper::flatten($array);
// Результат: []

// Значение, не являющееся массивом
$array = 'string';
$flattenedArray = ArrayHelper::flatten($array);
// Результат:
// yii\base\InvalidArgumentException: Argument $array must be an array or implement Traversable
```

### Коллизии ключей

Когда ключи совпадают, метод `flatten()` перезапишет предыдущее значение:

```php
$array = [
'a' => [
'b' => 1,
],
'a.b' => 2,
];

$flattenedArray = ArrayHelper::flatten($array);
// Результат: ['a.b' => 2]
```
137 changes: 137 additions & 0 deletions docs/guide/helper-array.md
Original file line number Diff line number Diff line change
Expand Up @@ -483,3 +483,140 @@ ArrayHelper::isIn('a', new ArrayObject(['a']));
// true
ArrayHelper::isSubset(new ArrayObject(['a', 'c']), new ArrayObject(['a', 'b', 'c']));
```

## Flattening Arrays <span id="flattening-arrays"></span>

The `ArrayHelper::flatten()` method allows you to convert a multi-dimensional array into a single-dimensional array by concatenating keys.

### Basic Usage

To flatten a nested array, simply pass the array to the `flatten()` method:

```php
$array = [
'a' => [
'b' => [
'c' => 1,
'd' => 2,
],
'e' => 3,
],
'f' => 4,
];

$flattenedArray = ArrayHelper::flatten($array);
// Result:
// [
// 'a.b.c' => 1,
// 'a.b.d' => 2,
// 'a.e' => 3,
// 'f' => 4,
// ]
```

### Custom Separator

You can specify a custom separator to use when concatenating keys:

```php
$array = [
'a' => [
'b' => [
'c' => 1,
'd' => 2,
],
'e' => 3,
],
'f' => 4,
];

$flattenedArray = ArrayHelper::flatten($array, '_');
// Result:
// [
// 'a_b_c' => 1,
// 'a_b_d' => 2,
// 'a_e' => 3,
// 'f' => 4,
// ]
```

### Handling Special Characters in Keys

The `flatten()` method can handle keys with special characters:

```php
$array = [
'a.b' => [
'c.d' => 1,
],
'e.f' => 2,
];

$flattenedArray = ArrayHelper::flatten($array);
// Result:
// [
// 'a.b.c.d' => 1,
// 'e.f' => 2,
// ]
```

### Mixed Data Types

The `flatten()` method works with arrays containing different data types:

```php
$array = [
'a' => [
'b' => 'string',
'c' => 123,
'd' => true,
'e' => null,
],
'f' => [1, 2, 3],
];

$flattenedArray = ArrayHelper::flatten($array);
// Result:
// [
// 'a.b' => 'string',
// 'a.c' => 123,
// 'a.d' => true,
// 'a.e' => null,
// 'f.0' => 1,
// 'f.1' => 2,
// 'f.2' => 3,
// ]
```

### Edge Cases

The `flatten()` method handles various edge cases, such as empty arrays and non-array values:

```php
// Empty array
$array = [];
$flattenedArray = ArrayHelper::flatten($array);
// Result: []

// Non-array value
$array = 'string';
$flattenedArray = ArrayHelper::flatten($array);
// Result:
// yii\base\InvalidArgumentException: Argument $array must be an array or implement Traversable
```

### Key Collisions

When keys collide, the `flatten()` method will overwrite the previous value:

```php
$array = [
'a' => [
'b' => 1,
],
'a.b' => 2,
];

$flattenedArray = ArrayHelper::flatten($array);
// Result: ['a.b' => 2]
```
1 change: 1 addition & 0 deletions framework/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ Yii Framework 2 Change Log
- Enh #20295: Add an ability to have wildcards in `yii\log\Target::$maskVars` array (xcopy)
- Bug #20296: Fix broken enum test (briedis)
- Bug #20300: Clear stat cache in `FileCache::setValue()` (rob006)
- Enh #20306: Add new `yii\helpers\ArrayHelper::flatten()` method (xcopy)

2.0.51 July 18, 2024
--------------------
Expand Down
57 changes: 57 additions & 0 deletions framework/helpers/BaseArrayHelper.php
Original file line number Diff line number Diff line change
Expand Up @@ -1043,4 +1043,61 @@ public static function recursiveSort(array &$array, $sorter = null)

return $array;
}

/**
* Flattens a multidimensional array into a one-dimensional array.
*
* This method recursively traverses the input array and concatenates the keys
* in a dot format to form a new key in the resulting array.
*
* Example:
*
* ```php
* $array = [
* 'A' => [1, 2],
* 'B' => [
* 'C' => 1,
* 'D' => 2,
* ],
* 'E' => 1,
* ];
* $result = \yii\helpers\ArrayHelper::flatten($array);
* // $result will be:
* // [
* // 'A.0' => 1
* // 'A.1' => 2
* // 'B.C' => 1
* // 'B.D' => 2
* // 'E' => 1
* // ]
* ```
*
* @param array $array the input array to be flattened in terms of name-value pairs.
* @param string $separator the separator to use between keys. Defaults to '.'.
*
* @return array the flattened array.
* @throws InvalidArgumentException if `$array` is neither traversable nor an array.
*/
public static function flatten($array, $separator = '.'): array
{
if (!static::isTraversable($array)) {
throw new InvalidArgumentException('Argument $array must be an array or implement Traversable');
}

$result = [];

foreach ($array as $key => $value) {
$newKey = $key;
if (is_array($value)) {
$flattenedArray = self::flatten($value, $separator);
foreach ($flattenedArray as $subKey => $subValue) {
$result[$newKey . $separator . $subKey] = $subValue;
}
} else {
$result[$newKey] = $value;
}
}

return $result;
}
}
Loading

0 comments on commit f94017c

Please sign in to comment.