Cómo fusionar dos PHP Doctrine 2 ArrayCollection ()

82

¿Existe algún método de conveniencia que me permita concatenar dos Doctrine ArrayCollection()? algo como:

$collection1 = new ArrayCollection();
$collection2 = new ArrayCollection();

$collection1->add($obj1);
$collection1->add($obj2);
$collection1->add($obj3);

$collection2->add($obj4);
$collection2->add($obj5);
$collection2->add($obj6);

$collection1->concat($collection2);

// $collection1 now contains {$obj1, $obj2, $obj3, $obj4, $obj5, $obj6 }

Solo quiero saber si puedo ahorrarme iterando sobre la segunda colección y agregando cada elemento uno por uno a la primera colección.

¡Gracias!

Throoze
fuente
3
+1 porque es un método común y necesario
JavierIEH

Respuestas:

171

Mejor (y funcionando) variante para mí:

$collection3 = new ArrayCollection(
    array_merge($collection1->toArray(), $collection2->toArray())
);
pliashkou
fuente
La mejor respuesta, sin duda.
carles
Recomiendo esta solución
ioleo
Estoy tratando de hacer lo mismo pero en una matriz: array_merge ($ merged_arr, $ doct_collection-> toArray ()); pero no recibo un error o está funcionando ($ merged_arr está vacío). ¿Algunas ideas?
Guy
5
¿Quizás $ merged_arr = array_merge ($ merged_arr, $ doct_collection-> toArray ())?
pliashkou
12

Simplemente puede hacer:

$a = new ArrayCollection();
$b = new ArrayCollection();
...
$c = new ArrayCollection(array_merge((array) $a, (array) $b));
Daniel Ribeiro
fuente
6
No entiendo por qué esto recibe tantos votos a favor. Simplemente está mal. Lanzar un objeto a una matriz no llama toArray(). Vea lo que sucede
greg0ire
21
Si bien la mentalidad de la mafia siempre es divertida, ¿alguno de ustedes realmente intentó esto antes de rechazarlo? ArrayCollection implementa IteratorAggregate que le permite convertir la colección como una matriz y funcionará como se esperaba.
Lewis
5
¡Gracias a Dios, alguien inteligente!
Daniel Ribeiro
1
@Lewis: Ya lo había probado antes, no funcionó para mí (no tuve tiempo de entrar en eso). Es por eso que tuve que escribir otra variante
pliashkou
2
@Lewis: un poco tarde para la fiesta, pero vuelvo a ese problema, y ​​sí lo intenté, y no, no funciona, de ahí el voto negativo.
greg0ire
10

Si se le solicita que evite los duplicados, este fragmento podría ayudar. Utiliza un parámetro de función variadic para su uso con PHP5.6.

/**
 * @param array... $arrayCollections
 * @return ArrayCollection
 */
public function merge(...$arrayCollections)
{
    $returnCollection = new ArrayCollection();

    /**
     * @var ArrayCollection $arrayCollection
     */
    foreach ($arrayCollections as $arrayCollection) {
        if ($returnCollection->count() === 0) {
            $returnCollection = $arrayCollection;
        } else {
            $arrayCollection->map(function ($element) use (&$returnCollection) {
                if (!$returnCollection->contains($element)) {
                    $returnCollection->add($element);
                }
            });
        }
    }

    return $returnCollection;
}

Puede resultar útil en algunos casos.

Matthias Brock
fuente
1
O use$collection3 = new ArrayCollection(array_unique(array_merge($collection1->toArray(), $collection2->toArray())));
spdionis
Sí, pero esta y la otra respuesta popular que hace lo mismo convierte todo el objeto del modelo en matrices, lo que limita la funcionalidad adicional.
ceros y unos
3
$newCollection = new ArrayCollection((array)$collection1->toArray() + $collection2->toArray()); 

Esto debería ser más rápido que array_merge. Los nombres de clave duplicados de $collection1se mantienen cuando el mismo nombre de clave está presente en $collection2. No importa cuál sea el valor real

Kanariezwart
fuente
toArray()devuelve una matriz, seguramente no debería necesitar escribir una sugerencia de otra array?
Jimbo
@jimbo: tienes razón, pero si por algún motivo el primero $collection->toArray()vuelve nullo false. Terminas con un error fatal.
kanariezwart
Punto justo: aunque si Doctrine falla al convertir a una matriz, entonces algo está muy mal con el código base de Doctrine;)
Jimbo
2

Aún necesita iterar sobre las Colecciones para agregar el contenido de una matriz a otra. Dado que ArrayCollection es una clase contenedora, puede intentar fusionar las matrices de elementos mientras mantiene las claves, las claves de matriz en $ collection2 anulan cualquier clave existente en $ collection1 utilizando una función auxiliar a continuación:

$combined = new ArrayCollection(array_merge_maintain_keys($collection1->toArray(), $collection2->toArray())); 

/**
 *  Merge the arrays passed to the function and keep the keys intact.
 *  If two keys overlap then it is the last added key that takes precedence.
 * 
 * @return Array the merged array
 */
function array_merge_maintain_keys() {
    $args = func_get_args();
    $result = array();
    foreach ( $args as &$array ) {
        foreach ( $array as $key => &$value ) {
            $result[$key] = $value;
        }
    }
    return $result;
}
Stephen Senkomago Musoke
fuente
¿Para qué es el &operador? es algo como en C? Bueno, por supuesto, esto es una solución, pero el comportamiento que esperaba era tener un ArrayCollectionque ya contenía algunos valores, y usar un método (de ArrayCollection, si existe, o un procedimiento aislado, como el suyo) para agregar los valores de otro existente ArrayCollection. Su solución requiere la creación de una nueva ArrayCollection, lo que dificulta el proceso. ¡Gracias de cualquier manera!
Throoze
El & es un paso por referencia, ya que no desea cambiar los argumentos. En su lugar, podría reescribir el método para iterar sobre las colecciones. No hay argumentos para este método, por lo que puede combinar tantas colecciones como desee.
Stephen Senkomago Musoke
La cuestión es que obtengo mis colecciones de fuentes de forma dinámica, por lo que no puedo realizar la llamada de la manera que sugieres ...
Throoze
Lo que quise decir es que puede escribir un método mergeCollections ($ collection1, $ collection2) que fusiona el contenido de $ collection2 en $ collection1; puede reutilizar la función mergeCollection en otro lugar de su aplicación
Stephen Senkomago Musoke
En su lugar, debería utilizar array_merge ().
Daniel Ribeiro
0

Agregue una colección a una matriz, según el comentario de Yury Pliashkou (sé que no responde directamente a la pregunta original, pero eso ya fue respondido, y esto podría ayudar a otros a aterrizar aquí):

function addCollectionToArray( $array , $collection ) {
    $temp = $collection->toArray();
    if ( count( $array ) > 0 ) {
        if ( count( $temp ) > 0 ) {
            $result = array_merge( $array , $temp );
        } else {
            $result = $array;
        }
    } else {
        if ( count( $temp ) > 0 ) {
            $result = $temp;
        } else {
            $result = array();
        }
    }
    return $result;
}

Quizás te guste ... quizás no ... Solo pensé en tirarlo por si acaso alguien lo necesita.

Manatax
fuente
Siempre es bueno tener algún tipo de diversidad en las posibles soluciones. Pero en comparación con los demás, no veo el beneficio de usar su solución. ¿Le importaría describirlo un poco más en detalle?
k00ni
1
Aterricé en esta pregunta cuando necesitaba agregar una colección a una matriz, como otras personas, pero mi caso de uso requería verificar una matriz / colección vacía, así que la compartí aquí.
Manatax
0

¡Atención! Evite el gran anidamiento de elementos recursivos. array_unique : tiene un límite de incrustación recursivo y provoca unPHP error Fatal error: Nesting level too deep - recursive dependency?

/**
 * @param ArrayCollection[] $arrayCollections
 *
 * @return ArrayCollection
 */
function merge(...$arrayCollections) {
    $listCollections = [];
    foreach ($arrayCollections as $arrayCollection) {
        $listCollections = array_merge($listCollections, $arrayCollection->toArray());
    }

    return new ArrayCollection(array_unique($listCollections, SORT_REGULAR));
}

// using
$a = new ArrayCollection([1,2,3,4,5,6]);
$b = new ArrayCollection([7,8]);
$c = new ArrayCollection([9,10]);

$result = merge($a, $b, $c);
Валентин Анохин
fuente
-1

Usando Clousures PHP5> 5.3.0

$a = ArrayCollection(array(1,2,3));
$b = ArrayCollection(array(4,5,6));

$b->forAll(function($key,$value) use ($a){ $a[]=$value;return true;});

echo $a.toArray();

array (size=6) 0 => int 1 1 => int 2 2 => int 3 3 => int 4 4 => int 5 5 => int 6
Juja
fuente
Pequeña pista : la pieza echo $a.toArray();seguramente arrojará un error, porque toArrayno es una función válida. Debe ser al menos echo $a->toArray();. Además, la salida al final debe formatearse como código.
k00ni