[Generics] Esercizio metodo generico

di il
7 risposte

[Generics] Esercizio metodo generico

S'implementi un metodo generico che presa in pasto una lista di oggetti in input, stampi secondo il loro ordine naturale stabilito, gli oggetti contenuti nella lista insieme alla frequenza con cui un oggetto appare.
Che modifica dovremmo apportare al metodo per stampare gli oggetti in un ordine non definito?

Es:

freq(Arrays.asList("oh","capitano","mio","capitano"));

Stamperà:
capitano 2
mio 1
oh 1
SOLUZIONE

public static <T extends Comparable< ? super T>> void freq(List<T> lst){
		
		Map<T,Integer> m = new TreeMap<>();
			
		for(T t : lst){
			if(m.get(t)==null){
				m.put(t, 1);
			}
			else m.put(t, m.get(t).intValue()+1);
		}
		
		for(T t : m.keySet()){
			System.out.println(t+" "+m.get(t));
		}	
	}
Per stampare gli oggetti in un ordine indefinito, basterebbe utilizzare un HashMap e non un TreeMap che utilizza l'ordinamento naturale.
Esiste qualche meccanismo meno ridondante magari utilizzando gli stream?? Ho sbagliato qualcosa??

Ciao e buona serata

7 Risposte

  • Re: [Generics] Esercizio metodo generico

    Paolovox ha scritto:


    Per stampare gli oggetti in un ordine indefinito, basterebbe utilizzare un HashMap
    Sì, esatto.

    Paolovox ha scritto:


    Esiste qualche meccanismo meno ridondante magari utilizzando gli stream??
    Con gli stream la differenza tra HashMap e TreeMap la puoi replicare con:

    List<String> list = ........

    poi
    Map<String,Long> mappaFreq = list.stream().collect(
        Collectors.groupingBy(s -> s, HashMap::new, Collectors.counting())
    );
    oppure
    Map<String,Long> mappaFreq = list.stream().collect(
        Collectors.groupingBy(s -> s, TreeMap::new, Collectors.counting())
    );
    cambia solo il Supplier che in un caso è il costruttore di HashMap e nell'altro di TreeMap.
  • Re: [Generics] Esercizio metodo generico

    Grazie mille.
    GroupingBy di Collectors ancora non mi è chiaro. Lo trovo poco intuitivo e ne esistono un sacco di versioni.

    Però lo stream non mi funziona per ritornare una mappa con chiavi generiche Map<T,Integer>
  • Re: [Generics] Esercizio metodo generico

    Paolovox ha scritto:


    GroupingBy di Collectors ancora non mi è chiaro. Lo trovo poco intuitivo e ne esistono un sacco di versioni.
    Sì, non sono facilissime... vanno capite un pochino.

    Prova questo e vedrai:
    List<String> nomiFrutti = Arrays.asList("mela", "banana", "ciliegia", "pera", "arancia", "ananas", "cedro", "pesca");
    
    Map<Integer,List<String>> nomiFruttiPerLunghezza = nomiFrutti.stream().collect(
            Collectors.groupingBy(s -> s.length())
    );
    
    System.out.println(nomiFruttiPerLunghezza);
    
    Map<Character,List<String>> nomiFruttiPerIniziale = nomiFrutti.stream().collect(
            Collectors.groupingBy(s -> s.charAt(0))
    );
    
    System.out.println(nomiFruttiPerIniziale);
    
    Map<Character,String> nomiFruttiPerIniziale2 = nomiFrutti.stream().collect(
            Collectors.groupingBy(s -> s.charAt(0), Collectors.joining("/"))
    );
    
    System.out.println(nomiFruttiPerIniziale2);

    Paolovox ha scritto:


    Però lo stream non mi funziona per ritornare una mappa con chiavi generiche Map<T,Integer>
    Puoi chiarire meglio?
  • Re: [Generics] Esercizio metodo generico

    Chiedo scusa funziona benissimo.
    Sbagliavo ad usare come valore della chiave un Integer mentre, Collectors.counting() colleziona tipi Long.
    
    public static <T extends Comparable <? super T>> void freq2(List<T> lst){
    		
    		Map<T,Long> m = 
    				lst.stream().collect(Collectors.groupingBy(s->s, TreeMap::new, Collectors.counting()));
    		
    		for(T t : m.keySet()){
    			System.out.println(t+" "+m.get(t));
    		}
    	}
    
    Ok adesso gli do un'occhiata.
  • Re: [Generics] Esercizio metodo generico

    === I groupingBy ===
    
    groupingBy(Function)
    
    E' il più semplice: gli elementi dello stream vengono mappati a qualche chiave tramite il valore di ritorno della Function.
    Ritorna una Map<K, List<T>> dove le chiavi sono i valori di ritorno della Function applicata agli elementi in input dello stream, mentre i corrispondenti valori sono Lists contenenti gli elementi in input la quale mappatura è associata ad una chiave della mappa.

    E' sempre più facile a farsi che a dirsi.
    
    List<String> lst = Arrays.asList("qui", "quo", "qua", "pluto", "pippo", "galaca", "goku", "lamu");
    
    		Map<Integer,List<String>> m = lst.stream().collect(
    		        Collectors.groupingBy(String::length)
    		);
    
    		System.out.println(m);
    

    === II groupingBy ===
    
    groupingBy(Function, Collector)
    
    La Function mappa gli elementi dello stream ad una chiave K, mentre il downstream collector opera sugli elementi e produce
    un risultato di tipo D. Il risultato sarà una Map<K,D>
    
    List<String> nomiFrutti = Arrays.asList("qui", "quo", "qua", "pluto", "pippo", "galaca", "goku", "lamu");
    
    		Map<Character,Set<String>> m= nomiFrutti.stream().collect(
    		        Collectors.groupingBy(s->s.charAt(0) , Collectors.mapping(s->s+" "+s.length(), toSet()))
    		);
    
    		System.out.println(m);
    
    === III groupingBy ===
    
    groupingBy(Function, Suppliet, Collector)
    
    Il terzo groupingBy è facile da comprendere se capiti bene i precedenti.
    La Function mappa sempre gli elementi in input dello stream in key della mappa.
    Il Collector opera sempre sugli elementi dello stream producento un risultato di tipo D che sarà il valore della chiave dell'elemento.
    Il Supplier produce una nuova mappa vuota del tipo desiderato.
    
    //imposta le chiavi nel loro ordinamento naturale
    Map<Character,String> m= lst.stream().collect(
    		        Collectors.groupingBy(s -> s.charAt(0), TreeMap::new ,  Collectors.joining("/"))
    		);
    		
    //imposta le chiavi in un ordinamento casuale
    Map<Character,String> m= lst.stream().collect(
    		        Collectors.groupingBy(s -> s.charAt(0), HashMap::new ,  Collectors.joining("/"))
    		);
    
    Quindi volendo è possibile creare un Comparator per effettuare un desiderato ordinamento e farlo ritornare dal Supplier
    
    Map<Character,String> m= lst.stream().collect(
    		        Collectors.groupingBy(s -> s.charAt(0), ()->{return new TreeMap(MioComparatore);} ,  Collectors.joining("/"))
    		);
    

    Adesso mi è leggermente più chiaro, anche se tanti meccanismi di base sugli stream mi sembrano ancora esoterici.
    Perchè hanno inventato gli stream? Rispecchia molto il pattern Build.
    Si pensa che sia più facile da comprendere?? Saranno molto utilizzati da ora in avanti??
    Fatto sta che sono geniali
  • Re: [Generics] Esercizio metodo generico

    Paolovox ha scritto:


    Perchè hanno inventato gli stream? Rispecchia molto il pattern Build.
    Si pensa che sia più facile da comprendere?? Saranno molto utilizzati da ora in avanti??
    Sicuramente con il passare del tempo saranno utilizzati di più. A livello lavorativo ("aziendale") Java 8 è ancora poco sentito e utilizzato. Io personalmente non ho ancora avuto modo di lavorare in progetti con Java 8 (al max. Java 7 e giusto solo per usare il "diamond" e poco altro ). Anzi, qualche anno fa ho lavorato in un progetto ancora in Java 1.4 !

    Se hai "domande" particolari su lambda/stream, puoi vedere: .
    Se il nome Maurice Naftalin non ti dice niente, sappi che è il coautore di un importante e interessante libro O'Reilly "Java Generics and Collections", su cui avevo studiato già diversi anni fa.
  • Re: [Generics] Esercizio metodo generico

    Grazie per la risorsa importante poi i libri dell'O'Reilly sono divertenti e insegnano molto.
    Anche le servlet ancora utilizzano Java 1.6 e tra meno di un anno http://www.java9countdown.xyz Java 9.
    Credo la sua portabilità e la sua continua evoluzione, facciano di Java un linguaggio immortale. E' un linguaggio proprietario giusto?
Devi accedere o registrarti per scrivere nel forum
7 risposte