Funciones para arrays

Esta página trata las clases Nette\Utils\Arrays, ArrayHash y ArrayList, relacionadas con los arrays.

Instalación:

composer require nette/utils

Arrays

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

Los ejemplos siguientes suponen que está definido el siguiente alias de clase:

use Nette\Utils\Arrays;

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

Esta función transforma con flexibilidad el array $array en un array asociativo o en objetos, según la ruta indicada $path. La ruta puede ser una cadena o un array. Se compone de los nombres de las claves del array de entrada y de operadores como [], ->, = y |. Lanza Nette\InvalidArgumentException si la ruta no es válida.

// convierte en un array asociativo usando 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]]
// asigna los valores de una clave a otra con el operador =
$result = Arrays::associate($arr, 'name=age'); // o ['name', '=', 'age']
// $result = ['John' => 11, 'Mary' => null, ...]
// crea un objeto con el operador ->
$result = Arrays::associate($arr, '->name'); // o ['->', 'name']
// $result = (object) ['John' => ['name' => 'John', 'age' => 11], 'Mary' => ['name' => 'Mary', 'age' => null]]
// agrupa en dos niveles con el operador |
$result = Arrays::associate($arr, 'name|age'); // o ['name', '|', 'age']
// $result: ['John' => [11 => ['name' => 'John', 'age' => 11]], 'Mary' => ['' => ['name' => 'Mary', 'age' => null]], ...]
// añade a un array con []
$result = Arrays::associate($arr, 'name[]'); // o ['name', '[]']
// $result: ['John' => [['name' => 'John', 'age' => 11]], 'Mary' => [['name' => 'Mary', 'age' => null]], ...]

contains (array $array, $value)bool

Comprueba si un array contiene un valor. Usa comparación estricta (===).

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

every (array $array, callable $predicate)bool

Comprueba si todos los elementos del array pasan la prueba implementada por la función $predicate indicada, de 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

Vea some().

filter (array $array, callable $predicate)array

Devuelve un array nuevo con todas las parejas clave-valor que encajan con el $predicate dado. 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,
);
// devuelve ['a' => 1, 'b' => 2]

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

Devuelve el primer elemento (el primero que encaje con el predicado, si se indica). Si no existe tal elemento, devuelve el resultado de invocar $else o null. El $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

Vea last().

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

Devuelve la clave del primer elemento (el primero que encaje con el predicado, si se indica), o null si no existe tal elemento. El $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

Vea lastKey().

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

Aplana un array de varios niveles en uno solo. Las claves se pueden conservar si $preserveKeys se pone a true.

$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 Nette\InvalidArgumentException, a menos que se indique un valor predeterminado como tercer argumento, que es entonces el que se 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 puede ser también un array que representa una ruta dentro de un array anidado.

$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 indicado del array. Si el elemento no existe, se crea con el valor null.

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

Funciona con arrays multidimensionales igual que get().

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

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

Devuelve solo los elementos del array cuyo valor encaja con la expresión regular $pattern. Si $invert es true, devuelve los elementos que no encajan. Un error de compilación o de ejecución en la expresión lanza 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 $array inmediatamente después del elemento de clave $key. Si $key es null (o no existe 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 $array antes del elemento de clave $key. Si $key es null (o no existe 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 del iterable y devuelve un array con los 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

Invoca un método en cada objeto de un iterable y devuelve un array con los 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 (mixed $value): bool

Comprueba si el array está indexado con claves numéricas ascendentes desde cero, es decir, si es una 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 (el último que encaje con el predicado, si se indica). Si no existe tal elemento, devuelve el resultado de invocar $else o null. El $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

Vea first().

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

Devuelve la clave del último elemento (el último que encaje con el predicado, si se indica), o null si no existe tal elemento. El $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

Vea firstKey().

map (array $array, callable $transformer)array

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

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

mapWithKeys (array $array, callable $transformer)array

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

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

Este método resulta útil cuando necesita cambiar la estructura de un array (claves y valores a la vez) o filtrar elementos durante la transformación (devolviendo null para los no deseados).

mergeTree (array $array1, array $array2)array

Fusiona recursivamente dos arrays. Resulta útil, por ejemplo, para fusionar estructuras de árbol. Sigue las mismas reglas que el operador + aplicado a arrays, es decir, añade al primero las parejas clave/valor del segundo y, en caso de colisión de claves, conserva el valor del primero.

$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 se añaden siempre al final del primero. Que el valor 10 del segundo array desaparezca puede resultar algo confuso. Es importante darse cuenta de que a ese valor, igual que al valor 5 del primer array, se le asigna la misma clave numérica 0. Por eso, el array resultante contiene para esa clave solo el elemento del primer array.

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

Normaliza un array en un array asociativo. Las claves numéricas se sustituyen por sus valores, y el nuevo valor pasa a 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 del array el valor del elemento de clave $key. Si el elemento no existe, lanza una excepción, o devuelve $default si se ha indicado.

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

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

Renombra una clave del array. Devuelve true si la clave se encontró 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, indexada desde cero, de la clave dada del array. Devuelve null si no se encuentra la clave.

$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

Comprueba si al menos un elemento del array pasa la prueba implementada por el callback $predicate indicado, de firma function ($value, $key, array $array): bool.

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

Vea every().

toKey (mixed $value): string|int

Convierte un valor en clave de array, es decir, en un entero o una cadena. Los números en coma flotante se truncan, los booleanos se convierten en 0 o 1, null pasa a ser una cadena vacía y los objetos lanzan una excepción.

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

toObject (iterable $array, object $object)object

Copia los elementos del iterable $array en el objeto $object y devuelve después el objeto.

$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 a cadena cada elemento del array y lo envuelve con $prefix y $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 amplía con la posibilidad de tratarlo como un array, por ejemplo accediendo a sus miembros con corchetes:

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

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

Puede iterar sobre el objeto como si fuera un array, incluso por referencia:

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

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

Los arrays existentes se pueden transformar en un ArrayHash con el método estático from():

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

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

La conversión es recursiva: los eventuales subarrays se convierten también en objetos ArrayHash.

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

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

Este comportamiento recursivo se puede desactivar con el segundo parámetro:

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

Transformación inversa a array mediante la conversión (array):

$array = (array) $hash;

ArrayList

Nette\Utils\ArrayList representa un array lineal cuyos índices son solo números enteros ascendentes desde 0.

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

Los arrays existentes se pueden transformar en ArrayList con el método estático from():

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

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

Puede iterar sobre el objeto como si fuera un array, incluso por referencia:

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

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

Acceder a claves fuera del rango permitido (de 0 a count-1) o intentar fijar claves no enteras lanza Nette\OutOfRangeException:

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

Eliminar una clave hace que los elementos se renumeren:

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

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

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