9 Temmuz 2019 Salı

Java 8 Stream flatMap metodu

Giriş
flatMap() metodu içine bir stream alır ve stream'deki elemanları teker teker işler. Metodun parametre olarak stream aldığını görmek için şöyle yaparız.
collections
  .stream()
  .flatMap(collection -> loadKeys().stream())
  .collect(ImmutableSet.toImmutableSet());
Genel Kullanım Amacı
flatMap() genellikle
1. çok boyutlu veriyi düzleştirmek için kullanılır.
2. tek boyutlu verinin arasına bir şeyler eklemek (interleaving) için kullanılır. Araya bir şeyler eklemek şu anlama gelir. Elimizde şöyle bir dizi olsun. Araya bir şeyler ekleyince dizi büyür.
List<Integer> list = List.of(5,6,7,8);
// interleaved list = [5,1,6,1,7,1,8]
Stream'i kapatma
flatMap yeni bir stream döndürdüğü için parametre aldığı stream'i kapatır. Bu çok işe yarayan bir özellik değil ancak bilmekte fayda var.
Each mapped stream is closed after its contents have been placed into this stream.
Açıklaması şöyle.
if this stream is ordered, [returns] a stream consisting of the longest prefix of elements taken from this stream that match the given predicate.
if this stream is unordered, [returns] a stream consisting of a subset of elements taken from this stream that match the given predicate.
1. Düzleştirmek
Örnek - İki boyutlu Array
Elimizde iki boyutlu bir dizi varsa ve birleştirerek tek boyutlu hale getirmek istersek şöyle yaparız.
Foo[] concatenation = streamOfFooArrays.flatMap(Arrays::stream)
                                       .toArray(Foo[]::new);
Örnek - İki boyutlu Array
Elimizde iki boyutlu String teams[][] dizisi olsaydı ve bu dizide kaç eleman olduğunu öğrenmek isteseydik şöyle yapardık. İkinci boyuttaki her dizi flatMap ile stream'e çevrilir. Daha sonra tüm stream'le birleştirilerek eleman sayısı bulunur.
long players = Arrays.stream(teams).flatMap(team -> Arrays.stream(team)).count();
Örnek - List of Map
Elimizde List<Map<String, Long>> items = new ArrayList<>();  olsun. Her bir map elemanını şöyle dolaşırız. Aynı key değerlerine sahip elemanların toplamını elde ederiz.
import static java.util.stream.Collectors.toMap;

items.stream()
        .flatMap(m -> m.entrySet().stream())
        .collect(toMap(Map.Entry::getKey, Map.Entry::getValue, Long::sum));
Çıktı olarak
foo -> 5
bar -> 4 gibi bir şey alırız.

Örnek - Map of Map
Elimizde şöyle bir kod olsun.
Map<String, Map<String, String>> listMap = new HashMap<>();
Distinct key'leri liste olarak almak için şöyle yaparız.
List<String> distinct = 
    listMap.values() // Collection<Map<String,String>>
           .stream() // Stream<Map<String,String>>
           .flatMap(map -> map.keySet().stream()) // Stream<String>
           .distinct() // Stream<String>
           .collect(Collectors.toList()); // List<String>
Örnek - Map of List
Şöyle yaparız.
items.entrySet().stream().
  .flatMap(e -> e.getValue().stream.map(v ->
     new AbstractMap.SimpleEntry<Foo,Bar>(e.getKey(),v)))
  .foreach(simpleEntry -> ...);
2. Araya Eklemek (Interleaving)
Örnek
listeyi düzleştirdikten sonra araya b,r şeyler eklemek için şöyle yaparız. Örnekte 1,2,3 flatMap ile yeni bir stream'e çevriliyor.
System.out.println(
            "Result: " +
            Stream.of(1, 2, 3)
                    .flatMap(i -> Stream.of(i - 1, i, i + 1))
                    .flatMap(i -> Stream.of(i - 1, i, i + 1))
                    .filter(i -> {
                        System.out.println(i);
                        return true;
                    })
                    .findFirst()
                    .get()
    );
Çıktı olarak şunu alırız.
Result: 1
-----------
-1
0
1
0
1
2
1
2
3
Örnek
Listeyi iki defa çoklamak için şöyle yaparız.
stream.flatMap(e -> Stream.of(e,e))
Örnek
İki defa çoklayıp tekrar listeye çevirmek için şöyle yaparız.
List<People> peopleListClone = peopleList.stream()
    .flatMap(s -> Stream.of(s, s))
    .collect(Collectors.toList());
Örnek
Elimizde iki tane liste olsun.
List<Integer> list1 = Arrays.asList(1, 2, 3);
List<Integer> list2 = Arrays.asList(3, 4);
Tüm kombinasyonları almak için
[(1, 3), (1, 4), (2, 3), (2, 4), (3, 3), (3, 4)] 
Şöyle yaparız.
List<int[]> pairs =
  list1.stream().flatMap(i -> list2.stream().map(j -> new int[] { i, j }))
Örnek
Elimizde iki tane liste olsun.
int[] ar1 = {1,2,3};
int[] ar2 = {1,2,3};
 Kartezyen şekilde toplamı bulmak için şöyle yaparız.
System.out.println(Arrays.toString (
    IntStream.range(0,ar1.length)
             .flatMap(x -> IntStream.range(0,ar2.length).map(y -> ar1[x]+ar2[y]))
             .toArray ()));
Çıktı olarak şunu alırız
[2, 3, 4, 3, 4, 5, 4, 5, 6]

Hiç yorum yok:

Yorum Gönder