Reto PHP: los arrays y sus problematicas!

bLaKnI

Buenas a todos.
Llevo dos días cascandome la cabeza con lo que os plantearé, y aun no he encontrado una solución óptima, clara y concísa.

Solucionado está, pero no del modo que quisiera, ya que lo he resuelto via "strings".

Lo que quisiera peró, es resolverlo mediante arrays, y quiero ver si vosotros podeis sacar algo en claro.

Os presento al quebradero!

Tengo un array $original, y un array $nuevo.
Dentro de cada uno de ellos, tengo valores numéricos (podrian ser strings, no deberia importar, el método de resolución deberia ser genérico).

Quiero eliminar en ambos arrays las coincidencias, y dejar en cada uno de ellos, los valores que no coinciden tal cual, sin tocarlos.

Podriais pensar en una diferencia, pero PHP no dispone de una función que haga LO QUE QUIERO.

Estas te devuelven un array con la diferencia, y no puedo identificar que pertenece a que.

Visualmente, lo que quiero es lo siguiente:

$original = array(1,2,3);
$nuevo = array(2,3,4);

  • Restarlos de algun modo, eliminando coincidencias, y que quede lo siguiente:

$original = array(1);
$nuevo = array(4);

  • fijarse que se ha eliminado el 2 y el 3.
    Y lo quiero así, porque lo que queda en $original me indica que debo hacer X cosa con dichos números, y lo que queda en $nuevo, me indica que debo hacer Y otra cosa con los numeros restantes.

El diff (y sus variantes) de PHP, devolveria algo así:

$resultado = array(1,4);

y no me permitiria saber donde estaba el 1 ($original o $nuevo) y lo mismo con el 4.

Podria intentarse con arrays bidimensionales, para tenerlos marcados, y hacer una diferencia de PHP?

$original = array(1=>'org',2=>'org',3=>'org');
$nuevo = array(2=>'new',3=>'new',4=>'new');
$result = diff......() = array(1=>'org',4=>'new');

no me gusta demasiado la idea, quisiera una función que directamente hiciera la diferencia, dejando los arrays modificados, tal cual, sin devolver un resultado.

Entonces, ¿que se os ocurre gente?

Grácias, y a ver que sacamos en claro... :)

PD: he probado bucles recorriendo el $original, y haciendo unset() de los valores en ambos arrays cuando uno estuviera contenido en el otro, tanto por medio de for, foreach, while, current/next, etc...
Y nada, no hay manera. Si se modifica el contenido en cantidad en tiempo de loop, siempre hay problemas, porque los posicionadores no apuntan correctamente. Aunque no avances y solo lo hagas si no hay coincidencia. Dado que el size varia, siempre hay problemas...

bLaKnI

Madre mia...
Ya lo tengo! xD
Acaba de venirme como un tiro.

Teoria de conjuntos, vaya...

La inversa de la intersección, es basicamente lo que quiero, pero al querer dejarlo en dos grupos, sencillamente lo aplico en dos pasos mas un previo:

int=interseccion(A,B)
resA = diff(A,int)
resB = diff(B,int)

:)

bLaKnI

Para el que le interese, una pequeña demo.
Tiene chivatos, para la visualización, pero el "motor" son las 3 lineas centrales.

<?php
$original = array(1,2,3);
$nou = array(2,3,4);

var_dump($original);
echo "<br>";
var_dump($nou);
echo "<br><br>";

$intersect = array_values(array_intersect($original, $nou)); //C = A ^ B
$original = array_values(array_diff($original, $intersect)); //A' = A - C
$nou = array_values(array_diff($nou, $intersect)); //B' = B - C

var_dump($intersect);
echo "<br>";
var_dump($original);
echo "<br>";
var_dump($nou);
?>

Parece mentira cuando uno se ofusca... :\
Demasiadas horas diarias... xD

Saharabbey

Uhhh... estaba haciéndote un sistema largo y complejo a base de 2 bucles, ya no sé si postearlo siquiera xD.

Este era el post:

Recorre los 2 arrays, comprobando, y cuando encuentres uno que no coincide (que no tienen repetido ambos arrays) lo guardas en el array correspondiente.

No sé si me explico, es decir, sé que me explico fatal, pero no recuerdo nada de PHP (me miro la sintaxis de cada lenguaje cuando voy a usarlo, sorry).

pseudocódigo:

$contador= Array (Lo usaremos para almacenar el número de coincidencias para cada índice del Array)
$nuevo = Array
$viejo = Array

$nuevo2 = Array
$viejo2 = Array

#Bucle iterando sobre todos los valores de $nuevo
para i en $nuevo{

#Bucle iterando sobre todos los valores de $viejo, para compararlos con $nuevo
para j en $viejo{

#Comparamos el valor de $j con el de $i
si $i == $j{
#Si coinciden, sumamos 1 al contador para el índice $i del Array
$contador($i)+=1
}

}

#Al final del primer bucle, comprobamos si hubo coincidencias entre $nuevo y $viejo para el indice $i de $nuevo.

#Si no hubo coincidencias (el valor no está repetido en los dos Arrays)
si $contador($i) != 0{
#Asignamos al nuevo Array $nuevo2 el valor del viejo $nuevo que no está en el otro Array $viejo.
$nuevo2{$i} = $nuevo{$i}

}

Y ahí lo dejé a medias cuando me dió por volver a ver el hilo y descubrí que ya lo habías solucionado de una manera mucho más elegante. Estoy amongolao a estas horas xD

K

puf vaya marron... suerte xD

NeB1

en php no vas a tener problemas con esas cosas. mira en http://es2.php.net/manual/en/book.array.php la cantidad de funciones implementadas para los arrays.

Sacar la intersección, resta, elementos repetidos, porciones, intersección de claves, intersección de valores...

Ahora ves a Offtopic y dile al chico que dice que las matemáticas no sirven pa nada en informática, que se lo miren bien xD (o en este caso algebra :P)

bLaKnI

Gente, os cuelgo la función que he preparado. Esta realiza las modificaciones de los arrays por referencia.
Quizas a alguien mas pueda irle bien alguna vez!

function array_diff_ANT_NOU(&$org, &$nou, $tipus='VALUES'){
	switch($tipus){
		case 'VALUES':
			$int = array_values(array_intersect($org, $nou)); //C = A ^ B
			$org = array_values(array_diff($org, $int)); //A' = A - C
			$nou = array_values(array_diff($nou, $int)); //B' = B - C
			break;
		case 'KEYS':
			$int = array_values(array_intersect_key($org, $nou)); //C = A ^ B
			$org = array_values(array_diff_key($org, $int)); //A' = A - C
			$nou = array_values(array_diff_key($nou, $int)); //B' = B - C
			break;
	}
}


//Ejemplo de uso:

$original = array(1,2,3);
$nou = array(2,3,4);

array_diff_ANT_NOU($original, $nou, 'VALUES');

//aquí $original y $nou, ya tienen los valores como queria, osea, 1 y 4 respectivamente.

Lo chulo de esto es que yo lo uso para lo siguiente:

  • Tengo un evento X que se comparte con unos usuarios.
  • Los usuarios se seleccionan de un <select> por así decirlo y se almacena en una tabla complementaria algo tal que así:

idEvento --- idUsuario
1 ................... 3
1 ................... 15
2 ................... 4
2 ................... 7
2 ................... 23
52 ................. 20

...

Entonces, esta función la uso cuando quiero modificar un evento.
Dado que puede seleccionar nuevos usuarios con los que compartir dicho evento, o quitar usuarios, acabo pudiendo tener un array con los IDs de los usuarios tal como lo he cargado de la BBDD al ir a modificar y un array con los IDs tal y como quedan para ser salvados en la BBDD.

Como se que inserto y que elimino?
Pues con lo presentado aquí.

$original = 1,2,3
$nuevo = 2,3,4

Diferencia y queda:

$original = 1
$nuevo = 4

  • Lo de original, debo borrarlo de la BBDD. Borrar las filas de la tabla de antes con los ids en original.
  • Lo de nuevo, debo insertarlo en la tabla.

Lo que queda en original, es que ya no está en nuevo, y por lo tanto significa que lo hemos quitado (desmarcado usuarios). Entonces lo que queremos es borrarlo, porque como digo, no está en nuevo.
Y lo que queda en nuevo, no estaba en original y por lo tanto, es que lo hemos añadido (marcado nuevos usuarios). Así que lo que queremos, es insertarlo.

Y esto es todo! ^^

Saludos y gracias! :)

Usuarios habituales