Java 8 Streams FlatMap méthode exemple


J'ai vérifié le prochain Java update, à savoir: Java 8 or JDK 8. Oui, je suis impatient, il y a beaucoup de nouvelles choses, mais, il y a quelque chose que je ne comprends pas, du code simple:

final Stream<Integer>stream = Stream.of(1,2,3,4,5,6,7,8,9,10);
stream.flatMap();

Les javadocs sont

public <R> Stream<R> flatMap(Function<? super T,? extends Stream<? extends R>> mapper)

Renvoie un flux constitué des résultats du remplacement de chaque élément de ce flux par le contenu d'un flux mappé produit en appliquant la fonction de mappage fournie à chaque élément. Chaque flux mappé est fermé après que son contenu a été placé dans ce flux. (Si un flux mappé est null, un flux vide est utilisé à la place.) C'est un intermédiaire en opération.

J'apprécierais que quelqu'un crée des exemples simples de la vie réelle sur flatMap, comment vous pouvez le coder dans les versions Java précédentes Java[6,7] et comment vous pouvez coder les mêmes routines en utilisant Java 8.

Author: Tagir Valeev, 2014-03-13

7 answers

Cela n'a pas de sens de flatMapun Stream qui est déjà plat, comme le Stream<Integer> que vous avez montré dans votre question.

Cependant, si vous aviez un Stream<List<Integer>> alors cela aurait du sens et vous pourriez faire ceci:

Stream<List<Integer>> integerListStream = Stream.of(
  Arrays.asList(1, 2), 
  Arrays.asList(3, 4), 
  Arrays.asList(5)
);

Stream<Integer> integerStream = integerListStream .flatMap(Collection::stream);
integerStream.forEach(System.out::println);

Qui imprimerait:

1
2
3
4
5

Pour ce faire pré-Java 8, vous avez juste besoin d'une boucle:

List<List<Integer>> integerLists = Arrays.asList(
  Arrays.asList(1, 2), 
  Arrays.asList(3, 4), 
  Arrays.asList(5)
)

List<Integer> flattened = new ArrayList<>();

for (List<Integer> integerList : integerLists)
{
  flattened.addAll(integerList);
}

for (Integer i : flattened)
{
  System.out.println(i);
}
 147
Author: Nick Holt, 2015-07-31 07:23:56

Exemple composé

, Imaginez que vous souhaitez créer la séquence suivante: 1, 2, 2, 3, 3, 3, 4, 4, 4, 4 etc. (en d'autres termes: 1x1, 2x2, 3x3 etc.)

Avec {[3] } cela pourrait ressembler à:

IntStream sequence = IntStream.rangeClosed(1, 4)
                          .flatMap(i -> IntStream.iterate(i, identity()).limit(i));
sequence.forEach(System.out::println);

Où:

  • IntStream.rangeClosed(1, 4) crée un flux de int de 1 à 4 inclusivement
  • IntStream.iterate(i, identity()).limit(i) crée un flux de longueur i de int i - ainsi appliquée à i = 4, il crée un flux: 4, 4, 4, 4
  • flatMap "aplatit" le flux et le "concatène" à l'origine flux

Avec Java

List<Integer> list = new ArrayList<>();
for (int i = 1; i <= 4; i++) {
    for (int j = 0; j < i; j++) {
        list.add(i);
    }
}

Exemple du monde réel

Disons que j'ai un List<TimeSeries>, où chaque TimeSeries est essentiellement un Map<LocalDate, Double>. Je veux obtenir une liste de toutes les dates pour lesquelles au moins une des séries chronologiques a une valeur. flatMap à la rescousse:

list.stream().parallel()
    .flatMap(ts -> ts.dates().stream()) // for each TS, stream dates and flatmap
    .distinct()                         // remove duplicates
    .sorted()                           // sort ascending
    .collect(toList());

Non seulement il est lisible, mais si vous avez soudainement besoin de traiter des éléments 100k, le simple ajout de parallel() améliorera les performances sans que vous écriviez de code concurrent.

 105
Author: assylias, 2014-07-02 12:51:09

Extraire des mots uniques triés ASC à partir d'une liste de phrases:

List<String> phrases = Arrays.asList(
        "sporadic perjury",
        "confounded skimming",
        "incumbent jailer",
        "confounded jailer");

List<String> uniqueWords = phrases
        .stream()
        .flatMap(phrase -> Stream.of(phrase.split(" +")))
        .distinct()
        .sorted()
        .collect(Collectors.toList());
System.out.println("Unique words: " + uniqueWords);

... et la sortie:

Unique words: [confounded, incumbent, jailer, perjury, skimming, sporadic]
 16
Author: Igor Baiborodine, 2015-02-09 03:39:28

Suis-je le seul à trouver ennuyeux le déroulement des listes? ;-)

Essayons avec des objets. Exemple du monde réel au fait.

Given: Objet représentant une tâche répétitive. À propos des champs de tâches importants: les rappels commencent à sonner à start et se répètent tous les repeatPeriod repeatUnit(par exemple 5 HEURES) et il y aura repeatCount rappels au total(y compris le démarrage d'un).

Objectif: obtenir une liste de copies de tâches, une pour chaque rappel de tâche invocation.

List<Task> tasks =
            Arrays.asList(
                    new Task(
                            false,//completed sign
                            "My important task",//task name (text)
                            LocalDateTime.now().plus(2, ChronoUnit.DAYS),//first reminder(start)
                            true,//is task repetitive?
                            1,//reminder interval
                            ChronoUnit.DAYS,//interval unit
                            5//total number of reminders
                    )
            );

tasks.stream().flatMap(
        x -> LongStream.iterate(
                x.getStart().toEpochSecond(ZoneOffset.UTC),
                p -> (p + x.getRepeatPeriod()*x.getRepeatUnit().getDuration().getSeconds())
        ).limit(x.getRepeatCount()).boxed()
        .map( y -> new Task(x,LocalDateTime.ofEpochSecond(y,0,ZoneOffset.UTC)))
).forEach(System.out::println);

Sortie:

Task{completed=false, text='My important task', start=2014-10-01T21:35:24, repeat=false, repeatCount=0, repeatPeriod=0, repeatUnit=null}
Task{completed=false, text='My important task', start=2014-10-02T21:35:24, repeat=false, repeatCount=0, repeatPeriod=0, repeatUnit=null}
Task{completed=false, text='My important task', start=2014-10-03T21:35:24, repeat=false, repeatCount=0, repeatPeriod=0, repeatUnit=null}
Task{completed=false, text='My important task', start=2014-10-04T21:35:24, repeat=false, repeatCount=0, repeatPeriod=0, repeatUnit=null}
Task{completed=false, text='My important task', start=2014-10-05T21:35:24, repeat=false, repeatCount=0, repeatPeriod=0, repeatUnit=null}

PS: J'apprécierais que quelqu'un suggère une solution plus simple, je ne suis pas un pro après tout.

MISE À JOUR: @RBz a demandé des explications détaillées, alors le voici. Fondamentalement, flatMap place tous les éléments des flux à l'intérieur d'un autre flux dans le flux de sortie. Beaucoup de flux ici:). Ainsi, pour chaque tâche dans le flux initial, lambda expression x -> LongStream.iterate... crée un flux de valeurs longues qui représentent les moments de début de la tâche. Ce le flux est limité à x.getRepeatCount() instances. Ses valeurs commencent à partir de x.getStart().toEpochSecond(ZoneOffset.UTC) et chaque valeur suivante est calculée en utilisant lambda p -> (p + x.getRepeatPeriod()*x.getRepeatUnit().getDuration().getSeconds(). boxed() renvoie le flux avec chaque valeur longue en tant qu'instance de wrapper longue. Ensuite, chaque Long de ce flux est mappé à une nouvelle instance de tâche qui n'est plus répétitive et contient l'heure d'exécution exacte. Cet exemple ne contient qu'une seule tâche dans la liste d'entrée. Mais imaginez que vous en avez mille. Vous aurez alors un flux de 1000 flux d'objets de tâche. Et que fait flatMap ici met toutes les tâches de tous les flux sur le même flux de sortie. C'est tout ce que je comprends. Merci pour votre question!

 11
Author: Aleksandr Kravets, 2016-05-20 09:40:30

Un exemple très simple: Diviser une liste de noms complets pour obtenir une liste de noms, indépendamment du premier ou du dernier

 List<String> fullNames = Arrays.asList("Barry Allen", "Bruce Wayne", "Clark Kent");

 fullNames.stream()
            .flatMap(fullName -> Pattern.compile(" ").splitAsStream(fullName))
            .forEach(System.out::println);

Ceci imprime:

Barry
Allen
Bruce
Wayne
Clark
Kent
 2
Author: Somaiah Kumbera, 2018-05-23 07:43:09

Étant donné ceci:

  public class SalesTerritory
    {
        private String territoryName;
        private Set<String> geographicExtents;

        public SalesTerritory( String territoryName, Set<String> zipCodes )
        {
            this.territoryName = territoryName;
            this.geographicExtents = zipCodes;
        }

        public String getTerritoryName()
        {
            return territoryName;
        }

        public void setTerritoryName( String territoryName )
        {
            this.territoryName = territoryName;
        }

        public Set<String> getGeographicExtents()
        {
            return geographicExtents != null ? Collections.unmodifiableSet( geographicExtents ) : Collections.emptySet();
        }

        public void setGeographicExtents( Set<String> geographicExtents )
        {
            this.geographicExtents = new HashSet<>( geographicExtents );
        }

        @Override
        public int hashCode()
        {
            int hash = 7;
            hash = 53 * hash + Objects.hashCode( this.territoryName );
            return hash;
        }

        @Override
        public boolean equals( Object obj )
        {
            if ( this == obj ) {
                return true;
            }
            if ( obj == null ) {
                return false;
            }
            if ( getClass() != obj.getClass() ) {
                return false;
            }
            final SalesTerritory other = (SalesTerritory) obj;
            if ( !Objects.equals( this.territoryName, other.territoryName ) ) {
                return false;
            }
            return true;
        }

        @Override
        public String toString()
        {
            return "SalesTerritory{" + "territoryName=" + territoryName + ", geographicExtents=" + geographicExtents + '}';
        }

    }

Et ceci:

public class SalesTerritories
{
    private static final Set<SalesTerritory> territories
        = new HashSet<>(
            Arrays.asList(
                new SalesTerritory[]{
                    new SalesTerritory( "North-East, USA",
                                        new HashSet<>( Arrays.asList( new String[]{ "Maine", "New Hampshire", "Vermont",
                                                                                    "Rhode Island", "Massachusetts", "Connecticut",
                                                                                    "New York", "New Jersey", "Delaware", "Maryland",
                                                                                    "Eastern Pennsylvania", "District of Columbia" } ) ) ),
                    new SalesTerritory( "Appalachia, USA",
                                        new HashSet<>( Arrays.asList( new String[]{ "West-Virgina", "Kentucky",
                                                                                    "Western Pennsylvania" } ) ) ),
                    new SalesTerritory( "South-East, USA",
                                        new HashSet<>( Arrays.asList( new String[]{ "Virginia", "North Carolina", "South Carolina",
                                                                                    "Georgia", "Florida", "Alabama", "Tennessee",
                                                                                    "Mississippi", "Arkansas", "Louisiana" } ) ) ),
                    new SalesTerritory( "Mid-West, USA",
                                        new HashSet<>( Arrays.asList( new String[]{ "Ohio", "Michigan", "Wisconsin", "Minnesota",
                                                                                    "Iowa", "Missouri", "Illinois", "Indiana" } ) ) ),
                    new SalesTerritory( "Great Plains, USA",
                                        new HashSet<>( Arrays.asList( new String[]{ "Oklahoma", "Kansas", "Nebraska",
                                                                                    "South Dakota", "North Dakota",
                                                                                    "Eastern Montana",
                                                                                    "Wyoming", "Colorada" } ) ) ),
                    new SalesTerritory( "Rocky Mountain, USA",
                                        new HashSet<>( Arrays.asList( new String[]{ "Western Montana", "Idaho", "Utah", "Nevada" } ) ) ),
                    new SalesTerritory( "South-West, USA",
                                        new HashSet<>( Arrays.asList( new String[]{ "Arizona", "New Mexico", "Texas" } ) ) ),
                    new SalesTerritory( "Pacific North-West, USA",
                                        new HashSet<>( Arrays.asList( new String[]{ "Washington", "Oregon", "Alaska" } ) ) ),
                    new SalesTerritory( "Pacific South-West, USA",
                                        new HashSet<>( Arrays.asList( new String[]{ "California", "Hawaii" } ) ) )
                }
            )
        );

    public static Set<SalesTerritory> getAllTerritories()
    {
        return Collections.unmodifiableSet( territories );
    }

    private SalesTerritories()
    {
    }

}

Nous pouvons alors faire ceci:

System.out.println();
System.out
    .println( "We can use 'flatMap' in combination with the 'AbstractMap.SimpleEntry' class to flatten a hierarchical data-structure to a set of Key/Value pairs..." );
SalesTerritories.getAllTerritories()
    .stream()
    .flatMap( t -> t.getGeographicExtents()
        .stream()
        .map( ge -> new SimpleEntry<>( t.getTerritoryName(), ge ) )
    )
    .map( e -> String.format( "%-30s : %s",
                              e.getKey(),
                              e.getValue() ) )
    .forEach( System.out::println );
 1
Author: G Butler, 2016-11-05 01:11:34

Cette méthode prend une fonction comme argument, cette fonction accepte un paramètre T comme argument d'entrée et renvoie un flux de paramètre R comme valeur de retour. Lorsque cette fonction est appliquée sur chaque élément de ce courant, il produit un flux de nouvelles valeurs. Tous les éléments de ces nouveaux flux générés par chaque élément sont ensuite copiés dans un nouveau flux, qui sera une valeur de retour de cette méthode.

Http://codedestine.com/java-8-stream-flatmap-method/

 0
Author: lalitbhagtani, 2017-02-10 10:41:25