Modificar partes de objetos en ArrayList

B

Tengo una duda con ArrayList.

Yo tengo hecho por ejemplo en una ArrayList que almacena objetos de 3 parametros(string A, string B, int C por ejemplo), métodos para buscar en la lista en funcion del valor de un parámetro ke kiero de los objetos(porke ejemplo los objectos ke B=dulce) y si los encuentra cambiar el valor de otro parametro (el mismo o no, ejemplo: los objetos que B=dulce, entonces C=8)

Ahora bien no hay una forma de no tener que especificar nada? Es decir un método que al invocarlo tu decides sobre la marcha que parametro buscar en la lista de objectos del arraylist y también eliges que parámetro modificar en el momento, sin que este predefinido (Ejemplo busca en la coleccion X, y si vale a, cambia el valor de Y por b, por ahora X, y Y ya tienen que estar predifinidos en el metodo de antemano y solo puedes introducir los valores de a y b).
Eso es pedirle demasiado a los ArrayList o es posible? He ido haciendo pruebas pero no se me ha ocurrido si es siquiera posible.

Grise

Sin indicar el lenguaje complicado poder ayudar. Suponiendo que sea Java creo que el ArrayList no tiene ningún método que haga lo que tú quieres de manera directa, pero la implementación es trivial y lo puedes hacer implementando un List en lugar de un ArrayList, a no ser que lo necesites por algún motivo especial.

1 respuesta
B

#2 Si es java, y no no necesito arraylist, puedo usar List. Pero como seria?

Yo ahora he hecho metodos con este, pero tengo que hacer uno para cada cosa(si cada objecto tiene 20 parametros la cosa se complica):

spoiler
1 respuesta
m4andg4

1º un objeto no tiene parametros, tiene atributos. Parámetros son lo que se les pasa a las funciones.
2º ArrayList no trae nada de eso, solo metodos para añadir, borrar, y acceder a posiciones del array. Como todos los TDA contenedores.

En base a esto, la solución es simple: Recorre el array y ve accediendo posición por posicion y comprobando cada objeto a mano.

1 respuesta
Martita-

Creo que se refiere a modificar el objeto dentro de la posicion del array usando el set. Hace mucho tiempo que no toco java, pero vamos, algo al estilo fooArray[posicion].setParametro(whatever).

B

#4 cierto me referia a los atributos, por eso he puesto ejemplos, que explicarse vas facil liarla, y tambien he añadido codigo de un metodo de ejemplo de los que tengo.
Y si eso ya lo hago, me recorre toda la lista, me busca los objectos con el atributo A que le pido que tengan el valor x, y a esos objetos le cambia el atributo C, por el valor z.

El tema que al invocar el metodo tu solo puedes poner x, z. Lo que quiero esque al invocar el metodo puedas introducir los 4 (A, x, C, z), asi un solo metodo me valdria para toda la lista con todos los atributos (ejemplo lista de 100 objectos con 20 atributos cada uno).

Ranthas

#3 Si estás con Java 8, define un predicado para reemplazar el valor (por ejemplo, un predicado del tipo reemplaza A por B), y luego recorre la lista hasta encontrar un match y aplicarle el predicado.

Pero como creo que estás aprendiendo, toma estos consejos:

-> Si necesitas el index de la lista, no la recorras con un foreach; usa una estructura normal de for.
-> Fijate que capturas el indice unicamente si hay un match. Con esto estas machacando elementos no deseados.
-> Desglosa el problema en cachitos, y crea un método que se ocupe de cada cachito. PE, necesitas ver si el atributo A de una fruta "contiene" la cadena x, necesitas reemplazar esa fruta con una nueva cuyo atributo B es igual a la cadena Z.

En pseudocodigo te queda algo asi:

for (inicio = 0 hasta longitud(listaFrutas incrementa) {
   if compruebaAtributoA(listaFrutas.get(indice)) then
      listaFrutas.set(new Fruta(), indice);
   end if
}
1 respuesta
m4andg4
metodoAxCz(int x, int z){
    foreach(Objeto objeto : tuLista){
		if(objeto.A == x){
			objeto.C=z;
		}
    }
}

Simple y elegante.

2 respuestas
B

Repasando mejor el codigo que habeis puesto:

#8 Si asi es mas elegante, pero hace lo mismo que el mio, tienes que tener predefinido A y C, y solo puedes introducir x y z, lo que quiero esque introduzcas todo (X, x, Y, z) X puede ser A, B o H, y Y lo mismo.
#7 Muchas gracias por los consejos pero lo mismo, aunque se ve muy interesante el codigo, no veo como implementarlo a partir de ese para que en el metodo me de la opcion de introducir los 4 valores al empezar (X, x, Y, z), siendo X y Y atributos de los objectos de la lista. x,z, siendo el valor de esos atributos.

m4andg4

Lo que tu quieres es crear atributos en tiempo de ejecucion?

Grise

#8 A parte de no ser lo que necesita (busca un método al que se le pasen 4 parámetros) ese fragmento de código tiene una mala práctica grave que es hacer un acceso a un atributo de manera directa.

Te recomiendo que ahora que estás aprendiendo no te quedes en la mera funcionalidad e intenta entender lo que estás haciendo:

Una lista es una estructura de datos basada en nodos y un puntero, cada nodo contiene un objeto y una referencia al nodo siguiente, como podrás ver en la imagen. Gracias a la posición del puntero puedes obtener la información del nodo y recorrer la lista.

Ahora, el ArrayList es una implementación de un List basado en un Array:

Es una estructura de datos con la que a priori te sentirás más familiarizado porque seguro que ya has jugado con arrays antes, pero por en realidad es bastante más compleja y cerrada que un List normal.

Si quieres aprender te recomiendo que intentes primero implementar el método que nos has preguntado con el List, y una vez que lo tengas pases al ArrayList y lo harás en tres patadas.

1 respuesta
m4andg4

A cojones, no acababa de entender el problema. Mil disculpas. Voy a cenar, luego hago algo.

B

#11 La verdad que geniales las explicaciones, gracias por los esquemas.
Aunque el tema de recorrer las listas yo lo veo muy facil, eso no creo que sea el problema, a pesar de que era un claro error usar un for-each en mi ejemplo,(tienes for-each que te aseguras que la recorre entera de principio a fin, eso si no tienes indice y no puedes borrar elementos. Luego tienes Iterator, que es como for-each, pero puedes borrar, el for normal, que ahi si que tienes tu indice...) en fin que recorrer la lista no es problema creo yo.
Sino la complejidad de lo que le pido, que basicamente me da fallos de compilación porque no se expresarme bien en el lenguaje.

1 respuesta
afhn

Yo haría algo en plan, con un if para buscar el contenido, y después con un switch/case, para elegir el atributo que quieras modificar.
Osea, yo por lo menos sé más o menos qué es lo que quieres, pero ahora mismo tengo mi mente en el examen que tengo mañana y no puedo ayudarte mucho. Pero si no es urgente, mañana te hago un ejemplo del código que buscas más o menos.

1 respuesta
B

#14 No, no especialmente urgente, ademas yo lo tengo hecho de todas formas, pero de una manera que yo creo que es "cutre", un metodo para cada cosa que quiera(uno para que si cualquier objeto de ArrayList que su atributo A valga x, entonces C pase a valer z, otro para que si D valga h, entonces B pase a valer t, etc etc etc...(tu introduces al invocar el metodo los valores x,z o h,t)), pero gracias de todas formas.

Y la verdad esque me parece que tiene que ser algo "basico" de java, manejar tus colecciones y poder modificarlas de manera eficiente (yo esta claro aun no se xD).

1 respuesta
Grise

#13 Si te he entendido bien tienes un ArrayList con objetos tipo (perdón si me equivoco en cosas de sintaxis, hace bastante que no toco Java):

class miObjeto{
  private string a = "hola", b = "adios";
  private int c = 1;
  ...
   //Y aquí la interfaz del método que pides
  private void cambiarValores(String nombreVariableCentinela, Object valorVariableCentinela, String nombreVariableAModificar, Object nuevoValorVariableAModificar){
    ...
  }
}

Para hacer lo que quieres hacer vas a tener que usar la reflexión (obtener y modificar el valor de un atributo en función a su nombre) y no creo que sea algo a considerar cuando estás empezando a aprender un lenguaje:
http://stackoverflow.com/questions/276555/setting-variables-by-name-in-java

La aproximación más simple a lo que quieres hacer sería un Map poniendo en la clave el nombre de la variable y descartar las variables, pero si necesitas hacer lo que has preguntado tienes que usar impepinablemente reflexión.

afhn

#15 Si no he entendido mal, le pasas un valor y a través de ese valor buscas en el arraylist y si coincide cambian todos a algo, no?
public static void cambiarValores(String valorA,ArrayList<loquesea> loquesea){
  for(Loquesea l: loquesea){
    if(l.equalsignorecase("valorA"))
      l.setValorA("");
      l.setValorB("");
      I.setValorC(0);

Debería ser algo similar a esto, así de sencillo. No sé... Es que creo que no te he entendido xd. Aunque tengo que mirarlo, creo que algo esta mal, es que no puedo ni mirar el eclipse xd.

B

Mira, os voy a poner un ejemplo mas exacto de lo que estoy haciendo, a ver si me explico mejor. Tengo una clase que se llama Vehiculo y ahi creo objectos vehiculo que contienen los datos de un cliente y de un vehiculo(ejemplo con unos pocos atributos)

spoiler

Y luego en la clase principal que coje metodos de esta una ArrayList<Vehiculo> listaVehiculos en la que los que cada objecto es un objecto Vehiculo obviamente.
Entonces por ejemplo un metodo de varios que tengo para cambiar datos

spoiler

ya cambie el tiplo de bucle a for normal, pero como ves solo vale para lo que tengo predefinido.
Por ejemplo me gustaria un metodo
"public void BuscaAtributoAconValoraYCambiaValorAtributoBaValorb(String A, String a, String B, string b)"

PD: #13 no se ni lo que es reflexión, asi que suena complicado xD
PD2: porque no se ven los "}" los corchetes para cerrar, cuando pego el codigo? xD

3 respuestas
Grise

#18 Lo que quieres hacer necesita hacer uso de reflexión obligatoriamente. Olvídate de ello de momento.

1 respuesta
B

#19 /cry :cry:

Eso si, gracias por todas las respuestas ^^

1 respuesta
Mubris

#20 Me parece que se ha mezclado que hasta #18 no te has explicado muy bien con que hay gente que tiene más ganas de hacerse la lista que de ayudar.

He entendido lo que tienes en la cabeza. En abstracto, que es como se tiene que razonar en programación, la operación que haces es el recorrido de una lista que modifica los objetos que cumplen cierta condición. Tu problema es que, como con buen criterio observas, de la manera que lo has enfocado acabarías con n2 métodos si quisieras que funcionara con los n atributos de Vehículo, y tú quieres que funcione con uno. Quieres generalizarlo. ¿Se puede? Sí.

Tienes que pasar la condición y la operación que le aplicas al objeto por parámetro. Sé que estás acostumbrado a que las funciones manejen objetos, pero afortunadamente también pueden recibir (y devolver) otras funciones. De esta manera sólo necesitas un método con tres parámetros: la lista, la operación a realizar y la condición, podría llamarse algo así como "for_each_if", y será en la llamada a la función cuando especifiques con qué condición y qué operacion quieres realizar. Esto es algo que no se ve hasta segundo de carrera, si te atreves con ello busca información sobre "funciones de orden superior" o pregunta por aquí y seguro que podemos guiarte.

1 respuesta
B

#21 Gracias
Aunque la verdad que como lo veia muy complicado al final lo he hecho es, olvidarme de ArrayList.

He hecho un HashMap, pones la key con el metodo HashMap.get(key) (eso si solo puedes buscar los objectos por un parametro, el que has establecido en la key), te devuelve el objecto entero con todos sus parametros con un metodo sencillito que he implementado en la clase del objecto. Y luego con un switch eliges y modificas el que quieras.

Lo otro era demasiado simplificado y bonito, con lo cual quiere decir que al final era lo mas dificil xD

1 respuesta
Mubris

#22 Jajaja dios. Has cambiado un código cuyo número de métodos dependía cuadráticamente del número de atributos de una clase, por otro que depende linealmente a cambio de no resolver el problema inicial y alterar una estructura de datos que en cualquier caso no debería ser asunto de la función escoger.

Está bien porque te das cuenta intuitivamente de problemas de escalabilidad que tiene tu código pero no tienes las herramientas aún para resolverlos. Quédate con la idea de que se puede resolver tu problema con tres líneas, un sólo método, funcional para cualquier estructura de datos que el usuario quiera utilizar y sin alterar la interfaz de tus clases (eso es lo peor de tu solución, tener que modificar la interfaz pública de tu clase para que un algoritmo externo funcione como deseas debería chirriarte).

varuk

#18 Es que estás enfocando mal el ejercicio (no sé si es que te piden eso en algún lado que justo sea así el método) pero yo no lo haría así:

La gracia de la programación orientado a objetos es trabajar sobre el mismo objeto y no andar pasando parámetros a lo loco en los métodos. Es decir, tú quieres hacer esto:

BuscaAtributoAconValoraYCambiaValorAtributoBaValorb(String A, String a, String B, string b)

Tú quieres buscar un atributo... Mi solución sería que no hagas eso. Que hagas métodos específicos y no métodos tan generales. Es decir, métodos así:

cambioDNI(String dniActual, String dniNuevo);

cambioNombre(String nombreActual, String nombreNuevo);

cambioMatricula(String matriculaActual, String matriculaNueva);

cambioTitularDelVehiculo(String matriculaActual, String nuevoNombre);

Y haces tantos métodos como hagan falta, sin pasar tantos parámetros en los métodos (que por cierto se escriben con la primera letra en minúscula). De esta forma el código es mucho más mantenible para cambios futuros, para trabajar en equipo y que cada uno haga distintos métodos, etc.

Usuarios habituales