Newsgroup: it.comp.java
Titolo: ArrayList<ArrayList<Object>> non e' possibile?

In breve:
<CODE ON> -----------------------
 
import java.io.*;
import java.util.*;
 
public class GetPeriodArray {
 
	public ArrayList<Object> periodArray() throws IOException {
 
		ArrayList<Object> result = new ArrayList<Object>();
		ArrayList<Barra> chart = new ArrayList<Barra>();
		ArrayList<HistoBarra> histo = new ArrayList<HistoBarra>();
 
 
		//corpo del metodo...
 
		result.add(chart);
		result.add(histo);
		return result;
 
	}
 
	public static void main(String[] args)  throws IOException{
 
		GetPeriodArray P = new GetPeriodArray();
		ArrayList<Object> result = new ArrayList<Object>();
		result = P.periodArray();
		ArrayList<Barra> chart = (ArrayList<Barra>) result.get(0);
		ArrayList<HistoBarra> histo = (ArrayList<HistoBarra>) result.get(1);
 
		//resto del main.
 
	}
}
 
<CODE OFF> ------------------
 
Credo di poter risolvere semplicemente creando una nuova classe X che
funzioni sia come Barra che come HistoBarra, ma per curiosita' come si
puo' fare per ritornare due array ArrayList<MyData1> e
ArrayList<MyData2> da un metodo?
perche' ovviamente il metodo che ho provato qua sopra non funziona.
 
grazie in anticipo per rispondere alle mie contorte richieste
 
Sergio

 perche' ovviamente il metodo che ho provato qua sopra non funziona.
 
Perché gestire liste "eterogenee" (nel senso che il tipo d'un elemento è 
diverso dal tipo d'un altro elemento) è oltre le capacità del sistema dei 
tipi di java.
 
Quando lavoravo in java, e avevo bisogno di ritornare due dati, m'ero 
inventato una classe "Coppia"... semplificando era una cosa del genere:
 
import java.io.*;
import java.util.*;
 
public class GetPeriodArray {
	public Couple<List<Barra>, List<HistoBarra>> periodArray() throws 
IOException {
		List<Barra> chart = new ArrayList<Barra>();
		List<HistoBarra> histo = new ArrayList<HistoBarra>();
 
		//corpo del metodo...
 
		return new Couple<List<Barra>, List<HistoBarra>>(chart, 
histo);
	}
 
	public static void main(String[] args) throws IOException {
		GetPeriodArray P = new GetPeriodArray();
		Couple<List<Barra>, List<HistoBarra>> result = 
P.periodArray();
		List<Barra> chart = result.x;
		List<HistoBarra> histo = result.y;
	}
}
 
class Couple<X, Y> {
	public X x;
	public Y y;
	public Couple(X x, Y y) {
		this.x = x;
		this.y = y;
	}
}
 
 
Una cosa pero': dopo un po' Couple<> aveva "infettato" metà dei nostri 
metodi... è decisamente molto allettante, ma, se i campi da tornare sono più 
di due, è meglio (e più manutenibile) costruire una classe apposita!
 

 di due, è meglio (e più manutenibile) costruire una classe apposita!
quindi intendi che la cosa miglior sarebbe creare una classe unica che
fa le veci di Barra e HistoBarra?

 grazie in anticipo per rispondere alle mie contorte richieste
 
Innanzitutto il codice che hai scritto funziona, a parte il fatto che 
dovresti correggere:
 
< ArrayList<Object> result = new ArrayList<Object>();
< result = P.periodArray();
 
con:
ArrayList<Object> result = P.periodArray();
 
in quanto l'arraylist viene creata dento la funzione periodArray, non 
devi istanziarlo tu, non causa malfunzionamenti, e' semplicemente inutile.
 
Ti dimostro che funziona:
===============================================================
import java.util.ArrayList;
class demo {
     public static ArrayList<Object> periodArray() {
         ArrayList<Object> result = new ArrayList<Object>();
         ArrayList<String> strings = new ArrayList<String>();
         strings.add("uno");
         strings.add("due");
         ArrayList<Integer> ints = new ArrayList<Integer>();
         ints.add(3);
         ints.add(4);
         result.add(strings);
         result.add(ints);
         return result;
     }
 
     public static void main(String args[]) {
         int i;
         ArrayList<Object> result = periodArray();
         ArrayList<String> strings = (ArrayList<String>)result.get(0);
         ArrayList<Integer> ints = (ArrayList<Integer>)result.get(1);
         for (i = 0; i < strings.size(); i++)
              System.out.println(strings.get(i));
         for (i = 0; i < ints.size(); i++)
              System.out.println(ints.get(i));
      }
}
 
===============================================================
 
Detto questo fare una funzione che ritorna due valori si puo' fare in 
mille modi ma rimane una PORCATA. Rovini la leggibilita' del codice e il 
poveraccio che dovesse mettersi a usare quel codice non sarebbe felice. 
Puoi risolvere o:
- facendo una classe base da cui derivi sia Barra che HistoBarra e poi 
ritorni un arraylist della classe base
- oppure molto piu' semplicemente cosi':
 
===============================================================
public static void populateArrays(ArrayList<String> strings, 
ArrayList<Integer> ints) {
     strings.add("uno");
     strings.add("due");
     ints.add(3);
     ints.add(4);
}
 
... quando ti servono gli array fai:  ...
 
ArrayList<String> strings = new ArrayList<String>();
ArrayList<Integer> ints = new ArrayList<Integer>();
populateArrays(strings, ints);
===============================================================
 
Ciao.

grazi coder
 
hai ragione funzionava.... e' solo che nelle prove che ho fatto non
plottavo nulla e il compilatore invece di dire COMPLETED dava il
messaggio seguente:
 
Note: demo.java uses unchecked or unsafe operations.
Note: Recompile with -Xlint:unchecked for details.
 
cosi' ho dato per scontato che non funzionasse....
 
invece...
 
 
Dici che quel messaggio (che credo sia dovuto proprio al tipo di
classi dichiarate per gli ArrayList) puo' essere ignorato?
forse il suo vero significato e' "Stai facendo una porcata!"? come
dicevi tu... ^_^

 classi dichiarate per gli ArrayList) puo' essere ignorato?
 
Quel warning e' dovuto al fatto che stai facendo upcasting da Object a 
Generics e che io sappia non puoi evitare in questo specifico caso il 
warning.
 
Si tratta delle 2 righe:
ArrayList<Barra> chart = (ArrayList<Barra>) result.get(0);
ArrayList<HistoBarra> histo = (ArrayList<HistoBarra>) result.get(1);
 
result.get ti ritorna un Object che poi tu vuoi castare a 
ArrayList<Barra> nella prima riga e ArrayList<HistoBarra> nella seconda.
 
Che io sappia quello specifico warning (il cast da Object a Generics) 
puoi solo sopprimerlo aggiungendo queste 2 righe:
 
@SuppressWarnings("unchecked")
ArrayList<Barra> chart = (ArrayList<Barra>) result.get(0);
@SuppressWarnings("unchecked")
ArrayList<HistoBarra> histo = (ArrayList<HistoBarra>) result.get(1);
 
oppure mettendo @SuppressWarnings("unchecked") prima della definizione 
della funzione in cui le fai, ma nel modo in cui ti ho mostrato io 
almeno ne riduci l'effetto alle sole 2 righe in cui ti serve.
 
Ciao

> Ciao
 
Comunque io mi dissocio da questo modo di programmare :))
 
Ti consiglierei vivamente (se puoi), come ti dicevo prima, di 
trasformare la tua funzione in:
 
public void periodArray(ArrayList<Barra> chart, ArrayList<HistoBarra> 
histo) {
    ... qui riempi chart e histo come ti pare...
}
 
e quando la chiami fai:
ArrayList<Barra> chart = new ArrayList<Barra>();
ArrayList<HistoBarra> histo = new ArrayList<HistoBarra>();
periodArray(chart, histo);
 
Ciao.

 populateArrays(strings, ints);
 
Stai dicendo che il metodo *pulito* è avere una funzione che *modifica* il 
contenuto referenziato dai parametri?
 
 
Il metodo *pulito* è *abbandonare* l'ereditarietà, e costruire un oggetto 
che contenga i vari valori di ritorno
 
class Arrays {
    List<...> l1
    List<...> l2
}
 
Solo che creare una classe solo per creare un'unica volta un valore 
temporaneo che verrà subito dopo scompattato è una noia mortale, e da qui è 
nata la classe Couple.
 

 nata la classe Couple.
 
Se non sai dare un nome significativo ad una classe, significa che stai sbagliando approccio.
Una classe deve rappresentare UNA SOLA informazione logica. Se devi rappresentarne 2 con una sola classe, stai sicuramente sbagliando.
 
-- 
SoulSpirit

 Ti ricordo che è necessario ritornare quoziente e resto.
 
Non ho specificato bene, il mio "porcata" era riferito proprio al fatto 
di ritornare il risultato come arraylist di object. E poi di doverli 
distinguere per la posizione (posizione 0 e 1).
 
Riguardo al al quoziente e resto, sicuramenti i risultati vanno 
impacchettati e poi spacchettati (magari con metodi, come la classe 
IntegerDivisionResult di soulspirit).
 
In questo caso (1) non era chiaro cosa faceva la funzione e a cosa 
servissero i dati, (2) l'op mi sembra un po' alle prime armi => ho 
preferito rimanere sul sano "Keep It Simple, Stupid", passando gli array 
come argomenti.

grazie a tutti, i suggerimenti mi torneranno sicuramente di aiuto in
futuro.
 
Ma al momento me la sono cavata dichiarando gli array all'esterno del
metodo e creando due metodi per il ritorno di ognuno di loro. Il
metodo che popolava gli array e' diventato il costruttore.
 
La facevo piu complicata di quello che era
 
alla prossima

 sbagliando.
 
 
Buon Map.Entry a tutti.
 
-- 
-riko
http://www.enrico-franchi.org/
 
http://rik0-techtemple.blogspot.com/
 

 Buon Map.Entry a tutti.
 
Se non argomenti, la tua dubbia ironia dimostra solo la tua infantilita'.
 
-- 
SoulSpirit

 Se non argomenti, la tua dubbia ironia dimostra solo la tua infantilita'.
 
Quanta aggressivita' repressa... 
 
Cosa c'e' da argomentare? E' un constro-esempio. Classi generiche (non
nel senso dei generics) saltano fuori in tutti i contesti in cui la
struttura dei dati e' prevalente sul loro valore semantico nella tua
applicazione. Come minimo.
 
In particolare, io trovo dubbio che sia una feature il fatto che non sia
possibile ritornare valori multipli se non creando una classe ad hoc per
tali valori: classe che tipicamente rischia di essere un one trick pony
e, per come la vedo io, non e' necessariamente una soluzione superiore
dovere creare classi con un obiettivo estremamente ristretto vs. avere
classi piu' generiche che risolvono classi (pun not intended) di
problemi similari.
 
Aggiungo poi che progetti come Functional vanno appunto in una direzione
simile (anche se, nello specifico, non danno soluzione al problema del
ritorno di valori multipli).


 ritorno di valori multipli).
 
Non so cosa sia..
 
-- 
SoulSpirit

 rappresentarli con una classe che ne descrive meglio l'interdipendenza?
 
ha il senso che classi e tuple sono due strutture dati diverse e quindi 
fai fare alle classi un mestiere che non è il suo. peraltro il legame fra 
questi valori è strettamente legato al metodo che li ritorna, ergo 
secondo quello che dici dovresti ogni volta definire un tipo. ha senso? 
secondo me no, infatti in java preferisco non tentare nemmeno di 
avvicinarmi a questo approccio.

 avvicinarmi a questo approccio.
 
Non so, non mi vengono in mente casi in cui ci sia la necessita di avere questa grossa quantita' di oggetti fittizi che sarebbero invece piu' semplicemente definiti tramite /tuple/.
 
Quando si sviluppa business logic le tuple non hanno senso, perche' il modello di classi deve risolvere un problema reale, dove ad ogni entita' e' possibile dare un nome e un significato preciso.
Nello sviluppo general purpose potrebbero servire, ma il piu' delle volte hanno senso solo all'interno della classe che si sta creando: non vengono esposte all'esterno ed il loro utilizzo e' estremamente localizzato.
 
Se un metodo deve tornare 2 valori disgiunti, allora e' forse il caso di creare 2 metodi separati.
Se un metodo deve tornare 2 valori correlati, e' comodo e sensato dare un nome a questa correlazione, creando una classe che contenga i 2 valori.
 
-- 
SoulSpirit

 con una classe che ne descrive meglio l'interdipendenza?
 
Ma sono il primo e il secondo valore a rappresentare l'informazione, ad 
avere diritto - eventualmente - ad una classe ognuno, non il fatto che siano 
legati tra di loro.
 

 Non so cosa sia..
 
http://functionaljava.org/
 


 classe che contenga i 2 valori.
 
Questo rischia di far proliferare le classi in modo abnorme. 
E inoltre complica il codice perche' Java e' molto legato. Tipicamente
algoritmi identici che lavorano su queste "diverse" correlazioni devono
essere riscritti (oppure suddette correlazioni devono essere fatte
derivate da un antenato comune). Antenato che, guarda caso, rischierebbe
di essere proprio Tupla, visto che non necessariamente le relazioni sono
fra loro imparentate.


 avvicinarmi a questo approccio.
 
Ahahah, non trovo più il blog ma una volta ho letto in internet di un 
tizio che si gallava di aver scoperto un nuovo modo di programmare in 
Java: definiva un tipo per ogni campo della classe...ad esempio:
 
class ... {
 
     Year years;
 
     Name name;
 
     ...
 
}
 
invece di usare i tipi predefiniti dove possibile. Molto meglio diceva. Mah.
 
Nella fattispecie, io sono solito definire una classe Pair<S,T> una 
volta in tutto il progetto e buona notte. Map.Entry fa pensare alle 
mappe, quindi lo evito.

 essere riscritti 
 
"Tipicamente"? Chi e' che riscrive piu' volte algoritmi identici?
Cosa centra "Tupla" in tutto questo?
 
Uno spunto di riflessione per concludere:
Tupla<String,String> nomeCognome = getNomeCognome();
Tupla<String,String> coordinate = getCoordinate();
if(nomeCognome.equals(coordinate))
  throw new ParadoxException();
 
-- 
SoulSpirit

   throw new ParadoxException();
 
Solito vecchio problema della programmazione ad oggetti in generale e in
particolare di Java. In realta' con l'equals la cosa e' relativamente
"semplice"... 
 
In questo caso il problema e', dal mio punto di vista, molto piu'
analogo a:
 
f.getAddress().equals(f.getSurname())
 
"Piazza Giordani"
 
(l'idea e' che la persona si chiami di cognome Piazza Giordani, che
potrebbe anche essere il nome dell'indirizzo -- ok, manca il civico,
aggiustare a piacere). 
 
se abbiamo memorizzato entrambi come stringhe. Sono lo stesso tipo che
rappresenta oggetti semanticamente diversi. Purtroppo il modello ad
oggetti di Java (e tutto il "program to an interface") non si presta
bene a meno *davvero* di non creare classi con la sola funzione di dare
significato semantico ai campi. E piuttosto allora andare di asserzioni
e apt. ;)


 mappe, quindi lo evito.
 
Infatti non lo ho mai suggerito come "classe coppia general purpose", ma
come "esempio di una classe il cui unico scopo e' ritornare, in essenza,
due valori". E, personalmente, mi sarebbe piaciuto molto di piu' potere
scrivere una cosa tipo:
 
for(String name, Something feat : myHash) {
  ...


 supertipo Pair). 
 
Esattamente.
Se hanno tipi diversi, hanno funzioni diverse.
 
Immagino che il tuo punto di vista sia troppo influenzato dalla tua visione troppo a basso livello dei problemi di progettazione.
 
Comunque sia, ti auguro tutta la felicita' del mondo con le tuple.
Spero solo di non dover mai fare manutenzione ad un tuo progetto Java!
 
Al prossimo flame.
 
-- 
SoulSpirit

nessun dato, e anche solo tentare di darle un nome diventa un esercizio.
 
 
potresti farne un esempio?
 
thanks
ciao, Jasmine

 non dover mai fare manutenzione ad un tuo progetto Java!
 
Sei partito con l'insulto personale, bravo. Comunque e' una cosa che mi
scivola abbastanza: quando avrai un po' piu' di esperienza e di
capacita' di astrazione capirai quello di cui si parlava.
