Trabajo con arrays

Esta página se dedica a las clases Nette\Utils\Arrays, ArrayHash y ArrayList, que se refieren a los arrays.

Instalación:

composer require nette/utils

Arrays

Nette\Utils\Arrays es una clase estática que contiene funciones útiles para trabajar con arrays. Su equivalente para iteradores es Nette\Utils\Iterables.

Los siguientes ejemplos asumen que se ha creado un alias:

use Nette\Utils\Arrays;

associate (array $array, mixed $path): array|\stdClass

La función transforma flexiblemente el array $array en un array asociativo u objetos según la ruta especificada $path. La ruta puede ser una cadena o un array. Está formada por los nombres de las claves del array de entrada y operadores como ‘[]’, ‘->’, ‘=’, y ‘|’. Lanza Nette\InvalidArgumentException en caso de que la ruta sea inválida.

// conversión a array asociativo según una clave simple
$arr = [
    ['name' => 'John', 'age' => 11],
    ['name' => 'Mary', 'age' => null],
    // ...
];
$result = Arrays::associate($arr, 'name');
// $result = ['John' => ['name' => 'John', 'age' => 11], 'Mary' => ['name' => 'Mary', 'age' => null]]
// asignación de valores de una clave a otra usando el operador =
$result = Arrays::associate($arr, 'name=age'); // o ['name', '=', 'age']
// $result = ['John' => 11, 'Mary' => null, ...]
// creación de un objeto usando el operador ->
$result = Arrays::associate($arr, '->name'); // o ['->', 'name']
// $result = (object) ['John' => ['name' => 'John', 'age' => 11], 'Mary' => ['name' => 'Mary', 'age' => null]]
// combinación de claves mediante el operador |
$result = Arrays::associate($arr, 'name|age'); // o ['name', '|', 'age']
// $result: ['John' => ['name' => 'John', 'age' => 11], 'Paul' => ['name' => 'Paul', 'age' => 44]]
// adición a un array usando []
$result = Arrays::associate($arr, 'name[]'); // o ['name', '[]']
// $result: ['John' => [['name' => 'John', 'age' => 22], ['name' => 'John', 'age' => 11]]]

contains (array $array, $value)bool

Prueba si un array contiene un valor. Utiliza una comparación estricta (===).

Arrays::contains([1, 2, 3], 1);    // true
Arrays::contains(['1', false], 1); // false

every (array $array, callable $predicate)bool

Prueba si todos los elementos del array pasan la prueba implementada en $predicate con la firma function ($value, $key, array $array): bool.

$array = [1, 30, 39, 29, 10, 13];
$isBelowThreshold = fn($value) => $value < 40;
$res = Arrays::every($array, $isBelowThreshold); // true

Ver some().

filter (array $array, callable $predicate)array

Devuelve un nuevo array que contiene todos los pares clave-valor que coinciden con el predicado especificado. El callback tiene la firma function ($value, int|string $key, array $array): bool.

Arrays::filter(
	['a' => 1, 'b' => 2, 'c' => 3],
	fn($v) => $v < 3,
);
// ['a' => 1, 'b' => 2]

first (array $array, ?callable $predicate=null, ?callable $else=null)mixed

Devuelve el primer elemento (que coincide con el predicado, si se especifica). Si tal elemento no existe, devuelve el resultado de llamar a $else o null. El parámetro $predicate tiene la firma function ($value, int|string $key, array $array): bool.

No cambia el puntero interno a diferencia de reset(). Los parámetros $predicate y $else existen desde la versión 4.0.4.

Arrays::first([1, 2, 3]);                   // 1
Arrays::first([1, 2, 3], fn($v) => $v > 2); // 3
Arrays::first([]);                          // null
Arrays::first([], else: fn() => false);     // false

Ver last().

firstKey (array $array, ?callable $predicate=null): int|string|null

Devuelve la clave del primer elemento (que coincide con el predicado, si se especifica) o null si tal elemento no existe. El predicado $predicate tiene la firma function ($value, int|string $key, array $array): bool.

Arrays::firstKey([1, 2, 3]);                   // 0
Arrays::firstKey([1, 2, 3], fn($v) => $v > 2); // 2
Arrays::firstKey(['a' => 1, 'b' => 2]);        // 'a'
Arrays::firstKey([]);                          // null

Ver lastKey().

flatten (array $array, bool $preserveKeys=false)array

Unifica un array multinivel en uno plano.

$array = Arrays::flatten([1, 2, [3, 4, [5, 6]]]);
// $array = [1, 2, 3, 4, 5, 6];

get (array $array, string|int|array $key, ?mixed $default=null)mixed

Devuelve el elemento $array[$key]. Si no existe, lanza una excepción Nette\InvalidArgumentException, o si se especifica el tercer parámetro $default, lo devuelve.

// si $array['foo'] no existe, lanza una excepción
$value = Arrays::get($array, 'foo');

// si $array['foo'] no existe, devuelve 'bar'
$value = Arrays::get($array, 'foo', 'bar');

La clave $key también puede ser un array.

$array = ['color' => ['favorite' => 'red'], 5];

$value = Arrays::get($array, ['color', 'favorite']);
// devuelve 'red'

getRef (array &$array, string|int|array $key)mixed

Obtiene una referencia al elemento especificado del array. Si el elemento no existe, se creará con el valor null.

$valueRef = & Arrays::getRef($array, 'foo');
// devuelve una referencia a $array['foo']

Al igual que la función get(), puede trabajar con arrays multidimensionales.

$value = & Arrays::getRef($array, ['color', 'favorite']);
// devuelve una referencia a $array['color']['favorite']

grep (array $array, string $pattern, bool $invert=false)array

Devuelve solo aquellos elementos del array cuyo valor coincide con la expresión regular $pattern. Si $invert es true, devuelve por el contrario los elementos que no coinciden. Un error durante la compilación o procesamiento de la expresión lanza una excepción Nette\RegexpException.

$filteredArray = Arrays::grep($array, '~^\d+$~');
// devuelve solo los elementos del array formados por dígitos

insertAfter (array &$array, string|int|null $key, array $inserted)void

Inserta el contenido del array $inserted en el array $array justo después del elemento con la clave $key. Si $key es null (o no está en el array), se inserta al final.

$array = ['first' => 10, 'second' => 20];
Arrays::insertAfter($array, 'first', ['hello' => 'world']);
// $array = ['first' => 10, 'hello' => 'world', 'second' => 20];

insertBefore (array &$array, string|int|null $key, array $inserted)void

Inserta el contenido del array $inserted en el array $array antes del elemento con la clave $key. Si $key es null (o no está en el array), se inserta al principio.

$array = ['first' => 10, 'second' => 20];
Arrays::insertBefore($array, 'first', ['hello' => 'world']);
// $array = ['hello' => 'world', 'first' => 10, 'second' => 20];

invoke (iterable $callbacks, …$args)array

Invoca todos los callbacks y devuelve un array de resultados.

$callbacks = [
	'+' => fn($a, $b) => $a + $b,
	'*' => fn($a, $b) => $a * $b,
];

$array = Arrays::invoke($callbacks, 5, 11);
// $array = ['+' => 16, '*' => 55];

invokeMethod (iterable $objects, string $method, …$args)array

Llama al método en cada objeto del array y devuelve un array de resultados.

$objects = ['a' => $obj1, 'b' => $obj2];

$array = Arrays::invokeMethod($objects, 'foo', 1, 2);
// $array = ['a' => $obj1->foo(1, 2), 'b' => $obj2->foo(1, 2)];

isList (array $array): bool

Verifica si el array está indexado según una serie ascendente de claves numéricas desde cero, alias lista.

Arrays::isList(['a', 'b', 'c']); // true
Arrays::isList([4 => 1, 2, 3]); // false
Arrays::isList(['a' => 1, 'b' => 2]); // false

last (array $array, ?callable $predicate=null, ?callable $else=null)mixed

Devuelve el último elemento (que coincide con el predicado, si se especifica). Si tal elemento no existe, devuelve el resultado de llamar a $else o null. El parámetro $predicate tiene la firma function ($value, int|string $key, array $array): bool.

No cambia el puntero interno a diferencia de end(). Los parámetros $predicate y $else existen desde la versión 4.0.4.

Arrays::last([1, 2, 3]);                   // 3
Arrays::last([1, 2, 3], fn($v) => $v < 3); // 2
Arrays::last([]);                          // null
Arrays::last([], else: fn() => false);     // false

Ver first().

lastKey (array $array, ?callable $predicate=null): int|string|null

Devuelve la clave del último elemento (que coincide con el predicado, si se especifica) o null si tal elemento no existe. El predicado $predicate tiene la firma function ($value, int|string $key, array $array): bool.

Arrays::lastKey([1, 2, 3]);                    // 2
Arrays::lastKey([1, 2, 3], fn($v) => $v < 3);  // 1
Arrays::lastKey(['a' => 1, 'b' => 2]);         // 'b'
Arrays::lastKey([]);                           // null

Ver firstKey().

map (array $array, callable $transformer)array

Llama a $transformer en todos los elementos del array y devuelve un array de los valores devueltos. El callback tiene la firma function ($value, $key, array $array): bool.

$array = ['foo', 'bar', 'baz'];
$res = Arrays::map($array, fn($value) => $value . $value);
// $res = ['foofoo', 'barbar', 'bazbaz']

mapWithKeys (array $array, callable $transformer)array

Crea un nuevo array transformando los valores y claves del array original. La función $transformer tiene la firma function ($value, $key, array $array): ?array{$newKey, $newValue}. Si $transformer devuelve null, el elemento se omite. Para los elementos conservados, el primer elemento del array devuelto se usa como nueva clave y el segundo elemento como nuevo valor.

$array = ['a' => 1, 'b' => 2, 'c' => 3];
$result = Arrays::mapWithKeys($array, fn($v, $k) => $v > 1 ? [$v * 2, strtoupper($k)] : null);
// [4 => 'B']

Este método es útil en situaciones donde necesitas cambiar la estructura del array (claves y valores simultáneamente) o filtrar elementos durante la transformación (devolviendo null para elementos no deseados).

mergeTree (array $array1, array $array2)array

Fusiona recursivamente dos arrays. Es útil, por ejemplo, para fusionar estructuras de árbol. Durante la fusión, sigue las mismas reglas que el operador + aplicado a arrays, es decir, añade pares clave/valor del segundo array al primer array y en caso de colisión de claves, conserva el valor del primer array.

$array1 = ['color' => ['favorite' => 'red'], 5];
$array2 = [10, 'color' => ['favorite' => 'green', 'blue']];

$array = Arrays::mergeTree($array1, $array2);
// $array = ['color' => ['favorite' => 'red', 'blue'], 5];

Los valores del segundo array siempre se añaden al final del primero. Puede parecer un poco confuso la desaparición del valor 10 del segundo array. Hay que darse cuenta de que este valor, así como el valor 5 en el primer array, tienen asignada la misma clave numérica 0, por lo tanto, en el array resultante solo está el elemento del primer array.

normalize (array $array, ?string $filling=null)array

Normaliza un array a un array asociativo. Reemplaza las claves numéricas con sus valores, el nuevo valor será $filling.

$array = Arrays::normalize([1 => 'first', 'a' => 'second']);
// $array = ['first' => null, 'a' => 'second'];
$array = Arrays::normalize([1 => 'first', 'a' => 'second'], 'foobar');
// $array = ['first' => 'foobar', 'a' => 'second'];

pick (array &$array, string|int $key, ?mixed $default=null)mixed

Devuelve y elimina el valor de un elemento del array. Si no existe, lanza una excepción, o devuelve el valor $default si se especifica.

$array = [1 => 'foo', null => 'bar'];
$a = Arrays::pick($array, null);
// $a = 'bar'
$b = Arrays::pick($array, 'not-exists', 'foobar');
// $b = 'foobar'
$c = Arrays::pick($array, 'not-exists');
// throws Nette\InvalidArgumentException

renameKey (array &$array, string|int $oldKey, string|int $newKey)bool

Renombra una clave en el array. Devuelve true si la clave fue encontrada en el array.

$array = ['first' => 10, 'second' => 20];
Arrays::renameKey($array, 'first', 'renamed');
// $array = ['renamed' => 10, 'second' => 20];

getKeyOffset (array $array, string|int $key)?int

Devuelve la posición de la clave dada en el array. La posición se numera desde 0. En caso de que la clave no sea encontrada, la función devuelve null.

$array = ['first' => 10, 'second' => 20];
$position = Arrays::getKeyOffset($array, 'first'); // devuelve 0
$position = Arrays::getKeyOffset($array, 'second'); // devuelve 1
$position = Arrays::getKeyOffset($array, 'not-exists'); // devuelve null

some (array $array, callable $predicate)bool

Prueba si al menos un elemento del array pasa la prueba implementada en $predicate con la firma function ($value, $key, array $array): bool.

$array = [1, 2, 3, 4];
$isEven = fn($value) => $value % 2 === 0;
$res = Arrays::some($array, $isEven); // true

Ver every().

toKey (mixed $key): string|int

Convierte un valor a una clave de array, que es un entero o una cadena.

Arrays::toKey('1');  // 1
Arrays::toKey('01'); // '01'

toObject (iterable $array, object $object)object

Copia los elementos del array $array al objeto $object, que luego devuelve.

$obj = new stdClass;
$array = ['foo' => 1, 'bar' => 2];
Arrays::toObject($array, $obj); // establece $obj->foo = 1; $obj->bar = 2;

wrap (array $array, string $prefix='', string $suffix='')array

Convierte cada elemento del array a una cadena y lo envuelve con el prefijo $prefix y el sufijo $suffix.

$array = Arrays::wrap(['a' => 'red', 'b' => 'green'], '<<', '>>');
// $array = ['a' => '<<red>>', 'b' => '<<green>>'];

ArrayHash

El objeto Nette\Utils\ArrayHash es un descendiente de la clase genérica stdClass y la extiende con la capacidad de tratarlo como un array, es decir, por ejemplo, acceder a los miembros a través de corchetes:

$hash = new Nette\Utils\ArrayHash;
$hash['foo'] = 123;
$hash->bar = 456; // al mismo tiempo funciona la notación de objeto
$hash->foo; // 123

Se puede usar la función count($hash) para obtener el número de elementos.

Se puede iterar sobre el objeto igual que en el caso de un array, incluso con referencia:

foreach ($hash as $key => $value) {
	// ...
}

foreach ($hash as $key => &$value) {
	$value = 'new value';
}

Un array existente podemos transformarlo a ArrayHash con el método from():

$array = ['foo' => 123, 'bar' => 456];

$hash = Nette\Utils\ArrayHash::from($array);
$hash->foo; // 123
$hash->bar; // 456

La conversión es recursiva:

$array = ['foo' => 123, 'inner' => ['a' => 'b']];

$hash = Nette\Utils\ArrayHash::from($array);
$hash->inner; // objeto ArrayHash
$hash->inner->a; // 'b'
$hash['inner']['a']; // 'b'

Esto se puede prevenir con el segundo parámetro:

$hash = Nette\Utils\ArrayHash::from($array, false);
$hash->inner; // array

Transformación de vuelta a array:

$array = (array) $hash;

ArrayList

Nette\Utils\ArrayList representa un array lineal, donde los índices son solo números enteros ascendentemente desde 0.

$list = new Nette\Utils\ArrayList;
$list[] = 'a';
$list[] = 'b';
$list[] = 'c';
// ArrayList(0 => 'a', 1 => 'b', 2 => 'c')
count($list); // 3

Un array existente podemos transformarlo a ArrayList con el método from():

$array = ['foo', 'bar'];
$list = Nette\Utils\ArrayList::from($array);

Se puede usar la función count($list) para obtener el número de elementos.

Se puede iterar sobre el objeto igual que en el caso de un array, incluso con referencia:

foreach ($list as $key => $value) {
	// ...
}

foreach ($list as $key => &$value) {
	$value = 'new value';
}

El acceso a claves fuera de los valores permitidos lanza una excepción Nette\OutOfRangeException:

echo $list[-1]; // lanza Nette\OutOfRangeException
unset($list[30]); // lanza Nette\OutOfRangeException

La eliminación de una clave causa la renumeración de los elementos:

unset($list[1]);
// ArrayList(0 => 'a', 1 => 'c')

Se puede añadir un nuevo elemento al principio con el método prepend():

$list->prepend('d');
// ArrayList(0 => 'd', 1 => 'a', 2 => 'c')
versión: 4.0