IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

Collection et Stream Java Discussion :

Générics et découpage de collections


Sujet :

Collection et Stream Java

  1. #1
    Membre averti
    Profil pro
    Inscrit en
    Mars 2009
    Messages
    42
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mars 2009
    Messages : 42
    Par défaut Générics et découpage de collections
    bonjour à tous,

    je voudrais créer une fonction qui découpe une collection en en plusieurs sous collection de taille fixe, du style :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
     
    List<String> list = new ArrayList<String>();
     
    //opérations sur la listes (add, ...)
     
     
    List<List<String> listeDecoupee= decoupage(list, 5);
     
    //parcours pour afficher tous les elements
    for(List<String> subList : list) {
        for(String str : subList) 
           sysout(str)
    }
    pour l'instant si je n'utilise que des List ça fonctionne impec avec ça :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    public static <T> List<List<T>> splitIntoChunks(List<T> list, int chunkSize) {
    		if (chunkSize <= 0)
    			throw new IllegalArgumentException("chunkSize must be greater than 0.");
     
    		List<List<T>> retVal = new ArrayList<List<T>>();
     
    		int index = 0;
     
    		while (index < list.size()) {
    			int count = list.size() - index > chunkSize ? chunkSize : list.size() - index;
    			retVal.add(list.subList(index, index+count));
     
    			index += chunkSize;
    		}
     
    		return retVal;
    	}
    j'aimerais donc généraliser ça pour tout type de collection genre

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    Set<UUID> set = new HashSet<UUID>();
     
    //opérations quelconques ( ...)
     
     
    Set<Set<UUID> decoupee= decoupage(set, 20);

  2. #2
    Modérateur
    Avatar de Alkhan
    Homme Profil pro
    ingénieur full stack
    Inscrit en
    Octobre 2006
    Messages
    1 232
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Haute Garonne (Midi Pyrénées)

    Informations professionnelles :
    Activité : ingénieur full stack

    Informations forums :
    Inscription : Octobre 2006
    Messages : 1 232
    Par défaut
    bonjour,

    Je ne comprend pas vraiment le problème ?
    Il suffit de remplacer List par Collection et voila !
    Il n'y a pas de problème, il n'y a que des solutions.
    Cependant, comme le disaient les shadoks, s'il n'y a pas de solution, c'est qu'il n'y a pas de problème.
    Si toutefois le problème persiste, la seule solution restante est de changer le périphérique qui se trouve entre la chaise et l'écran

    Mes Articles : Mon premier article est sur le language D
    N'oubliez pas de consulter les FAQ Java et les cours et tutoriels Java

  3. #3
    Membre averti
    Profil pro
    Inscrit en
    Mars 2009
    Messages
    42
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mars 2009
    Messages : 42
    Par défaut
    justement je voudrais garder le type de collection passé en argument.

    si on passe une List<String> ça renvoi une List<List<String>

  4. #4
    Membre chevronné Avatar de billynirvana
    Homme Profil pro
    Architecte technique
    Inscrit en
    Décembre 2004
    Messages
    472
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 44
    Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Architecte technique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Décembre 2004
    Messages : 472
    Par défaut
    Passer en Collection ne suffira pas car la méthode list.subList() est propre aux java.util.List.

    De même, il y a pas de subList pour les Set ^^.

    Par ces arguments il est donc impossible de généraliser. Et je doute que ce soit réalisable même en modifiant le contenu de splitIntoChunks.

  5. #5
    Modérateur
    Avatar de Alkhan
    Homme Profil pro
    ingénieur full stack
    Inscrit en
    Octobre 2006
    Messages
    1 232
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Haute Garonne (Midi Pyrénées)

    Informations professionnelles :
    Activité : ingénieur full stack

    Informations forums :
    Inscription : Octobre 2006
    Messages : 1 232
    Par défaut
    en fait, j'avais pas fait attention, mais je pense que tu va avoir du mal à généraliser.
    La cause est ceci :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
    list.subList(index, index+count)
    Le sublist est un peu particulier et en plus n'existe pas sur les collections mais uniquement sur les List. Et je doute que tu arrives a avoir équivalant sur les "Set" et autres collections.

    Edit : ah grillé de peu
    Il n'y a pas de problème, il n'y a que des solutions.
    Cependant, comme le disaient les shadoks, s'il n'y a pas de solution, c'est qu'il n'y a pas de problème.
    Si toutefois le problème persiste, la seule solution restante est de changer le périphérique qui se trouve entre la chaise et l'écran

    Mes Articles : Mon premier article est sur le language D
    N'oubliez pas de consulter les FAQ Java et les cours et tutoriels Java

  6. #6
    Membre éclairé
    Inscrit en
    Février 2010
    Messages
    38
    Détails du profil
    Informations forums :
    Inscription : Février 2010
    Messages : 38
    Par défaut
    Et si tu fais un truc du genre

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
     
    public class Splitter<T extends Collection<V>, V extends Collection<String>> {
     
    	public T decoupage(V list,int chunkSize){
                    //balbla
    		return null;
    	}
     
    }
    par contre tu peux pas utiliser des fonctions statiques pour ça

  7. #7
    Membre chevronné Avatar de Mobius
    Profil pro
    none
    Inscrit en
    Avril 2005
    Messages
    463
    Détails du profil
    Informations personnelles :
    Localisation : France, Isère (Rhône Alpes)

    Informations professionnelles :
    Activité : none

    Informations forums :
    Inscription : Avril 2005
    Messages : 463
    Par défaut
    J'ai pondu du code rapidement sans tester mais rien ne me semble impossible :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    	public static <T> Collection<Collection<T>> splitIntoChunks(Collection<T> collection, int chunkSize) {
    		if (chunkSize <= 0)
    			throw new IllegalArgumentException(
    					"chunkSize must be greater than 0.");
     
    		Collection<Collection<T>> retVal = new ArrayList<Collection<T>>();
    		Collection<T> col = null;
     
    		int index = 0;
     
    		for (T t : collection) {
    			if(index%chunkSize == 0){
    				col = collection.getClass().newInstance();
    				retVal.add(col);
    			}
    			col.add(t);
    			index++;
    		}
     
    		return retVal;
    	}
    Pas forcement ce qu'il y a de plus performant mais ca doit marcher

  8. #8
    Modérateur
    Avatar de Alkhan
    Homme Profil pro
    ingénieur full stack
    Inscrit en
    Octobre 2006
    Messages
    1 232
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Haute Garonne (Midi Pyrénées)

    Informations professionnelles :
    Activité : ingénieur full stack

    Informations forums :
    Inscription : Octobre 2006
    Messages : 1 232
    Par défaut
    Citation Envoyé par Mobius Voir le message
    Pas forcement ce qu'il y a de plus performant mais ca doit marcher
    Eh non ca ne marche pas, car ce ne sont pas des vues de la collection d'origine. Par conséquent, si tu modifie la collection d'origine ca ne sera pas répercuté dans la collection découpé, et inversement bien sur.
    Il n'y a pas de problème, il n'y a que des solutions.
    Cependant, comme le disaient les shadoks, s'il n'y a pas de solution, c'est qu'il n'y a pas de problème.
    Si toutefois le problème persiste, la seule solution restante est de changer le périphérique qui se trouve entre la chaise et l'écran

    Mes Articles : Mon premier article est sur le language D
    N'oubliez pas de consulter les FAQ Java et les cours et tutoriels Java

  9. #9
    Membre chevronné Avatar de Mobius
    Profil pro
    none
    Inscrit en
    Avril 2005
    Messages
    463
    Détails du profil
    Informations personnelles :
    Localisation : France, Isère (Rhône Alpes)

    Informations professionnelles :
    Activité : none

    Informations forums :
    Inscription : Avril 2005
    Messages : 463
    Par défaut
    Citation Envoyé par Alkhan Voir le message
    Eh non ca ne marche pas, car ce ne sont pas des vues de la collection d'origine. Par conséquent, si tu modifie la collection d'origine ca ne sera pas répercuté dans la collection découpé, et inversement bien sur.
    Effectivement j'ai lu un peu trop vite.

    Dans ce cas, je rejoins l'avis que ce n'est pas faisable. Pour moi ca n'a même pas vraiment de sens pour les Set notamment.

    Si on cherche a faire des vues pour les Set, on pourrait chercher a rajouter un element dans un sous-ensemble. Que se passe il si l'élément est présent dans l'ensemble principal ? Si l'élément n'est pas présent dans l'ensemble principal, tout va bien. Si l'élément est présent mais qu'il ne l'ai pas dans le sous ensemble, on a un problème...

  10. #10
    Membre éclairé
    Inscrit en
    Février 2010
    Messages
    38
    Détails du profil
    Informations forums :
    Inscription : Février 2010
    Messages : 38
    Par défaut
    Je sais pas si c'était la problématique initiale.

    Mais totalement d'accord, une modif n'impactera pas la liste d'orgine (a moins que les sous Collections soient codées à la main et aient la référence sur la collection d'origine. Mais là c'est moche).

  11. #11
    Membre averti
    Profil pro
    Inscrit en
    Mars 2009
    Messages
    42
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mars 2009
    Messages : 42
    Par défaut
    ça, ça à l'air de marcher :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    	public static <T> Collection<? extends Collection<T>> chunk(Collection<T> target, int chunkSize) throws InstantiationException, IllegalAccessException {
    		if (chunkSize <= 0)
    			throw new IllegalArgumentException("chunk size must be greater than 0.");
     
    		Collection<Collection<T>> filler = new ArrayList<Collection<T>>();
    		Iterator<T> itTarget = target.iterator();
    		Collection<T> sub = null;
    		int index = 0;
     
    		while(itTarget.hasNext()) {
    			if(index%chunkSize == 0) {
    				sub = target.getClass().newInstance();
    				filler.add(sub);
    			}
     
    			while(itTarget.hasNext() && index++ < chunkSize) 
    				sub.add(itTarget.next());
     
    			index = 0;
    		}
     
    		return filler;
    	}
    oui forcément le subList pouvait pas marché mais mon problème demeure car ça retourne une Collection et pas le même type de collection que l'argument.

    d'ailleurs
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    sub = target.getClass().newInstance();
    sort un warning.


    @toinou : je pense pas que ça change quelque chose car le paramètrage ce fait sur la méthode et toi c'est au niveau de la classe.

  12. #12
    Membre averti
    Profil pro
    Inscrit en
    Mars 2009
    Messages
    42
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mars 2009
    Messages : 42
    Par défaut
    sinon il y a ça (la collection qui sera remplie est en 2e paramètre :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    public static <T, U extends Collection<T>, V extends Collection<U>> void chunk(U target, V filler, int chunkSize) throws InstantiationException, IllegalAccessException {
    		if (chunkSize <= 0)
    			throw new IllegalArgumentException("chunk size must be greater than 0");
     
    		Iterator<T> itTarget = target.iterator();
    		U sub = null;
    		int index = 0;
     
    		while(itTarget.hasNext()) {
    			if(index%chunkSize == 0) {
    				sub = (U) target.getClass().newInstance();
    				filler.add(sub);
    			}
     
    			while(itTarget.hasNext() && index++ < chunkSize) 
    				sub.add(itTarget.next());
     
    			index = 0;
    		}
    	}
    mais toujours un warning sur le newInstance()

  13. #13
    Modérateur

    Profil pro
    Inscrit en
    Septembre 2004
    Messages
    12 585
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Septembre 2004
    Messages : 12 585
    Par défaut
    Le warning sera toujours là, à cause de la nature des génériques en Java.

    En résumé le compilateur, trop généraliste, ne peut pas garantir que target.getClass().newInstance() va bel et bien produire un U. Il sait que ça va produire un objet qui étend Collection, mais ne sait pas si le type de cet objet sera qualifiable comme U.
    D'ailleurs, il est possible de faire qu'il ne le soit pas.

    Un truc que tu pourrais faire, c'est définir une méthode statique :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    public static <T, U extends Collection<T>> U newCollection(U col) throws InstantiationException, IllegalAccessException {
      @SuppressWarnings("unchecked")
      U c = (U)col.getClass().newInstance();
      if(!c.isEmpty()) {
        throw new IllegalArgumentException(
          "Collection class " + col.getClass().getName() + " builds non-empty instances with default constructor. " +
          "This violates type-safety on the Collection parameter, we therefore fail here instead of randomly anywhere.");
      }
      return c;
    }
    et t'en servir pour construire une nouvelle collection de même type qu'une collection donnée.

    Cette méthode s'occupe de vérifier les garanties de type que le compilateur se plaint de ne pas pouvoir vérifier. (Au prix d'échouer chaque fois qu'on lui demande de créer une Collection dont le constructeur par défaut construit une Collection qui contient déjà des éléments.)
    N'oubliez pas de consulter les FAQ Java et les cours et tutoriels Java

  14. #14
    Membre averti
    Profil pro
    Inscrit en
    Mars 2009
    Messages
    42
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mars 2009
    Messages : 42
    Par défaut
    oui ça à l'air d'être une bonne façon, mais ce que je comprends pas c'est le fait qu'une nouvelle instance ne soit pas vide.

    ça fonctionnerai pas avec un try catch de classcastexception ou même exception tout court??

  15. #15
    Modérateur

    Profil pro
    Inscrit en
    Septembre 2004
    Messages
    12 585
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Septembre 2004
    Messages : 12 585
    Par défaut
    Citation Envoyé par Spidy Voir le message
    oui ça à l'air d'être une bonne façon, mais ce que je comprends pas c'est le fait qu'une nouvelle instance ne soit pas vide.
    Les Collection fournies avec Java sont toujours vides quand construites avec le constructeur par défaut.
    Mais rien n'empêche d'en implémenter de nouvelles, qui font autrement. Dans ce cas-là, elles ont leur propre logique de type-safety, qui ne correspond pas à ce qu'on attend.

    Citation Envoyé par Spidy Voir le message
    ça fonctionnerai pas avec un try catch de classcastexception ou même exception tout court??
    Non. Le problème avec la violation de type-safety, c'est qu'elle produit des ClassCastException ailleurs que là où elle est créée. À un moment plus tard.
    Et cela complique pas mal le débuggage. C'est pourquoi on essaie autant que possible de forcer le lancement de l'Exception là où l'erreur arrive. C'est encore mieux quand une erreur ne peut pas arriver, bien sûr.
    N'oubliez pas de consulter les FAQ Java et les cours et tutoriels Java

  16. #16
    Expert éminent
    Avatar de adiGuba
    Homme Profil pro
    Développeur Java/Web
    Inscrit en
    Avril 2002
    Messages
    13 938
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Développeur Java/Web
    Secteur : Transports

    Informations forums :
    Inscription : Avril 2002
    Messages : 13 938
    Billets dans le blog
    1
    Par défaut
    Salut,


    Quelques remarques :
    • Dans le tout premier code on utilise subList(). Il faut faire très attention au fait que la liste ainsi créée est très lié à la liste d'origine, et surtout qu'il s'agit d'une vue temporaire qui sera invalide si on modifie la liste d'origine par la suite...
    • Le newInstance() peut sembler correct, mais posent d'autres en plus des problèmes déjà signalés.
      En effet cela marche bien avec les collections de base (ArrayList, HashSet, ...), mais même dans l'API on retrouve plusieurs collections qui ne possède pas de constructeur vide. C'est ainsi le cas de la plupart des collection crée via les fabriques de la classe Collections/Arrays ou de ceux retournées via les méthodes subList() ou autres...
      Par exemple ce code pourtant banal génère une exception :
      Code : Sélectionner tout - Visualiser dans une fenêtre à part
      1
      2
      	List<String> list = Arrays.asList("a","b","c","d","e","f","g","h","i");
      	Collection<? extends Collection<String>> chunks = chunk(list, 5);
      Car Arrays.asList() retourne un type privé sans constructeur vide.



    A mon avis une version retournant un type fixe est amplement suffisant (après je n'ai pas vraiment compris les besoins exact de faire tous cela donc cela peut m'échapper).
    Bref cela donnerais quelque chose comme cela :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    	public static <E> List<List<E>> splitIntoChunks(Collection<E> coll, int chunkSize) {
    		if (chunkSize <= 0)
    			throw new IllegalArgumentException(
    					"chunk size must be greater than 0.");
    		final List<List<E>> result = new ArrayList<List<E>>();
    		List<E> current = null;
    		int count = 0;
    		for (E element : coll) {
    			if (count==0) {
    				current = new ArrayList<E>(chunkSize);
    				result.add(current);
    			}
    			current.add(element);
    			count = (count + 1) % chunkSize;
    		}
    		return result;
    	}

    a++

  17. #17
    Membre averti
    Profil pro
    Inscrit en
    Mars 2009
    Messages
    42
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mars 2009
    Messages : 42
    Par défaut
    le fait d'avoir des warning (ou de bidouiller le code pour pas en avoir) me plait pas du tout donc je pense que je vais prendre ta solution.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    new ArrayList<E>(chunkSize);
    pas con du tout d'initialiser à la bonne taille

    pour subList() ça fonctionne qu'avec des list donc de toute façon j'aurais pas pu l'utiliser.

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. System collections généric list
    Par Plano dans le forum VB.NET
    Réponses: 2
    Dernier message: 30/10/2009, 19h35
  2. collection généric VS tableau
    Par djoao dans le forum Framework .NET
    Réponses: 5
    Dernier message: 29/04/2008, 11h28
  3. [VB6] la collection controls
    Par tomnie dans le forum VB 6 et antérieur
    Réponses: 3
    Dernier message: 30/04/2003, 17h03
  4. Comment créér une collection sous Delphi
    Par PsyKroPack dans le forum Langage
    Réponses: 6
    Dernier message: 11/02/2003, 13h20
  5. [VB6] Modifier la clé d'un élément d'une collection
    Par Ricou13 dans le forum VB 6 et antérieur
    Réponses: 3
    Dernier message: 21/11/2002, 14h49

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo