2010-03-07 4 views
11

J'écris une structure d'adaptateur dans laquelle je dois convertir une liste d'objets d'une classe à une autre. Je peux parcourir la liste des sources pour le faire comme dansJava: Conversion de listes d'un type d'élément en une liste d'un autre type

Java: Best way of converting List<Integer> to List<String>

Cependant, je me demande s'il y a une façon de le faire à la volée lorsque la liste cible est réitérée, donc je n » Je dois parcourir deux fois la liste.

Répondre

0

Cette question ne traverse pas la liste deux fois. Il ne fait que répéter une fois et de loin la seule méthode connue.

Aussi vous pouvez utiliser certaines classes de transformation dans commons-collections de google-collections, mais ils ont tous faire la même chose sous le capot :) ce qui suit étant une façon

CollectionUtils.collect(collectionOfIntegers, new org.apache.commons.collections.functors.StringValueTransformer()); 
+0

La liste n'est-elle pas répétée (au moins) deux fois? une fois sur la liste d'origine lorsque la conversion est effectuée, puis à nouveau lorsque la liste cible est itérée? –

0

Eh bien, vous pouvez créer votre propre classe wrapper itérateur pour ce faire. Mais je doute que vous économisiez beaucoup en faisant cela.

Voici un exemple simple qui encapsule n'importe quel itérateur à un itérateur de chaîne, en utilisant Object.toString() pour effectuer le mappage.

public MyIterator implements Iterator<String> { 

    private Iterator<? extends Object> it; 

    public MyIterator(Iterator<? extends Object> it) { 
     this.it = it; 
    } 

    public boolean hasNext() { 
     return it.hasNext(); 
    } 

    public String next() { 
     return it.next().toString(); 
    } 

    public void remove() { 
     it.remove(); 
    } 
} 
2

Vous pouvez écrire un itérateur de mappage qui décore un itérateur existant et y applique une fonction. Dans ce cas, la fonction transforme les objets d'un type à un autre "à la volée".

Quelque chose comme ceci:

import java.util.*; 

abstract class Transformer<T, U> implements Iterable<U>, Iterator<U> { 
    public abstract U apply(T object); 

    final Iterator<T> source;  
    Transformer(Iterable<T> source) { this.source = source.iterator(); } 

    @Override public boolean hasNext() { return source.hasNext(); } 
    @Override public U next()   { return apply(source.next()); } 
    @Override public void remove()  { source.remove(); } 

    public Iterator<U> iterator()  { return this; } 
} 

public class TransformingIterator { 
    public static void main(String args[]) { 
     List<String> list = Arrays.asList("1", "2", "3"); 
     Iterable<Integer> it = new Transformer<String, Integer>(list) { 
      @Override public Integer apply(String s) { 
       return Integer.parseInt(s); 
      } 
     }; 
     for (int i : it) { 
      System.out.println(i); 
     } 
    } 
} 
+0

Cela ressemble à ce que je cherche. Selon la réponse similaire, est-ce que cela me donne beaucoup d'avantages? –

+0

Honnêtement, je pense que la solution Google Collections (Ben Lings) pourrait être meilleure. Leur conception est beaucoup plus mature, et leur mise en œuvre est plus robuste. Franchement, je viens de fouetter ce code en 15 minutes sans trop y réfléchir. – polygenelubricants

+1

Je veux dire, la classe implémente 'Iterator ' et 'Iterable '. Je ne suis pas sûr que ce soit casher. – polygenelubricants

0

Je pense que vous devez soit créer une liste personnalisée (mise en œuvre de l'interface List) ou un itérateur personnalisé. Par exemple:

ArrayList<String> targetList = new ArrayList<String>(); 
ConvertingIterator<String> iterator = new ConvertingIterator<String>(targetList); 
// and here you would have to use a custom List implementation as a source List 
// using the Iterator created above 

Mais je doute que cette approche vous permettrait d'économiser beaucoup.

12

Mon answer à cette question s'applique à votre cas:

import com.google.common.collect.Lists; 
import com.google.common.base.Functions 

List<Integer> integers = Arrays.asList(1, 2, 3, 4); 

List<String> strings = Lists.transform(integers, Functions.toStringFunction()); 

La liste est transformé en vue de la collection originale, de sorte que la transformation se produit lorsque la destination List est accessible.

1

Lambdaj permet de le faire d'une manière très simple et lisible. Par exemple, supposons que vous ayez une liste d'entiers et que vous vouliez les convertir dans la représentation de chaîne correspondante, vous pourriez écrire quelque chose comme ça;

List<Integer> ints = asList(1, 2, 3, 4); 
Iterator<String> stringIterator = convertIterator(ints, new Converter<Integer, String> { 
    public String convert(Integer i) { return Integer.toString(i); } 
}); 

Lambdaj applique la fonction de conversion que lorsque nous parcourons le résultat. Il existe également une manière plus concise d'utiliser la même fonctionnalité. L'exemple suivant fonctionne en supposant que vous avez une liste de personnes avec une propriété de nom et que vous voulez convertir cette liste dans un itérateur des noms de personnes.

Iterator<String> namesIterator = convertIterator(persons, on(Person.class).getName()); 

Assez facile. N'est-ce pas?

8

Comme alternative au modèle de iterator, vous pouvez utiliser une classe abstraite mappeur générique, et seulement remplacer la méthode de transformation:

  1. créer une collection générique mappeur pour tout type de données
  2. [facultatif] créer une bibliothèque de méthodes de transformation entre les différents types de données (et substituer la méthode)
  3. utilisation de cette bibliothèque

la mise en œuvre:

// Generic class to transform collections 
public abstract class CollectionTransformer<E, F> { 

    abstract F transform(E e); 

    public List<F> transform(List<E> list) { 
     List<F> newList = new ArrayList<F>(); 
     for (E e : list) { 
      newList.add(transform(e)); 
     } 
     return newList; 
    } 
} 

// Method that transform Integer to String 
// this override the transform method to specify the transformation 
public static List<String> mapIntegerToStringCollection(List<Integer> list) { 

    CollectionTransformer transformer = new CollectionTransformer<Integer, String>() { 
     @Override 
     String transform(Integer e) { 
      return e.toString(); 
     } 
    }; 
    return transformer.transform(list); 
} 

// Example Usage 
List<Integer> integers = Arrays.asList(1,2); 
List<String> strings = mapIntegerToStringCollection(integers); 

Cela serait utile si vous devez utiliser des transformations à chaque fois, en encapsulant le processus. Vous pouvez donc créer une bibliothèque de mappeurs de collection très facilement.

7

Java 8 façon:

List<String> original = ...; 
List<Wrapper> converted = original.stream().map(Wrapper::new).collect(Collectors.toList()); 

en supposant Wrapper classe a un constructeur d'accepter un String.

Questions connexes