스트림의 종류, 필터링, 매핑, 정렬, 루핑, 수집

dejeong·2024년 9월 25일
0

JAVA

목록 보기
20/24
post-thumbnail

필터링 - distinct, filter

스트림의 3가지 순서 (생성 → 가공 → 결과) 중 가공에 해당하는 부분이며, 원하는 결과를 얻기 위해 필요한 데이터만 걸러내는 방법이다.

  1. 생성 : 스트림 인스턴스 생성 (배열이나 컬렉션을 스트림 인스턴스로 변환)
  2. 가공 : 원하는 결과를 만들어가는 중간 작업
  3. 결과 : 최종 결과를 만들어내는 작업

distinct

중복을 제거하기 위해 사용한다.

Stream : “Object.equals(Object)”가 true 일 경우에 동일한 객체로 판단하여 중복 제거

IntStream, LongStream, DoubleStream: 값이 동일한 경우 중복 제거

  List<String> list = Arrays.asList("a","b","b","c","c","a");
  list.stream()
          .distinct()
          .forEach(System.out::print);

filter

조건이 참이면 true, 거짓이면 false를 리턴하며, true인 것만 필터링 한다.

 List<String> sentences = Arrays.asList("김밥", "김밥", "김치", "나비", "나방");
sentences.stream()
        .filter(str -> str.startsWith("김")) // 구현체가 true 일 경우에만 출력 (앞글자가 김일 경우에만)
        .distinct() // 중복 제거
        .forEach(System.out::println);
        
System.out.println("=============");
Set<String> set = sentences.stream()
                .filter(x -> x.startsWith("김"))
                .collect(Collectors.toSet());
System.out.println(set);

System.out.println("=============");

distinct, filter 동시 사용

String[] dupArray = {"김밥", "김밥", "김치", "나비", "나방"};

Set<String> hashSet = Arrays
        .stream(dupArray)
        .collect(Collectors.toSet());
        
List<String> arrayList = 
        Arrays.stream(dupArray)
                .distinct()
                .toList();
System.out.println(hashSet);
System.out.println(arrayList);

매핑 - map, flatMap

가공에 해당하는 부분

map

스트림의 요소를 하나씩 특정 값으로 변환, 변환된 값은 새로운 스트림으로 만들어진다. 어떤 값으로 변환할지는 map 메소드에 정의할 수 있다.

 List<String> list = Arrays.asList("a", "b", "c", "d", "e");
list.stream()
        .map(element -> element.toUpperCase())
        .forEach(System.out::println);

flatmap

스트림의 요소들을 다른 값으로 대체하지만, 대체하는 값이 스트림일 경우에 사용한다. 스트림 안에 또 다른 스트림이 있는 2차원 배열과 유사한 구조이다. flatMap 을 사용하여 중첩 구조를 한 단계 제거하는 것을 flattening이라고 한다. → 2차원 배열을 나열하여 1차월 배열처럼 출력할 수 있다.

// flatmap 2차원 -> 1차원
Integer [][] array = {{1,2}, {3,4}};
Arrays.stream(array)
        .flatMap(element -> Arrays.stream(element))
        .forEach(System.out::println);
1
2
3
4

split을 사용하여 배열에서 특정 문자를 기준으로 나눌 수도 있다. collect를 사용하면 나눈 단어들을 다시 리스트에 넣을 수 있다.

// flatmap
List<String> sentences = Arrays.asList("Hello World","Java stream");
sentences.stream()
        .flatMap(element -> Arrays.stream(element.split(" ")))
        .forEach(System.out::println);
Hello
World
Java
stream
// flatmap
List<String> sentences2 = Arrays.asList("Hello World","Java stream");
List<String> collect = sentences2.stream()
        .flatMap(element -> Arrays.stream(element.split(" ")))
        .collect(Collectors.toList());
System.out.println(collect);
[Hello, World, Java, stream]

정렬 - sorted

가공에 해당하는 부분

sorted

스트림의 요소들을 정렬하기 위해 사용하며, 아무 옵션도 주지 않으면 오름차순으로 정렬한다. Comparator을 사용하면 원하는 방식으로 정렬도 가능하다.

 List<String> list = Arrays.asList("e", "a", "c", "z", "d");

List<String> sortedList = list.stream()
        .sorted()   // 오름차순 정렬
        .toList();
System.out.println(sortedList);

System.out.println("=============");

List<String> sortedList2 = list.stream()
        .sorted(Comparator.reverseOrder()) // **Comparator 사용 (역순 정렬)**
        .toList();
System.out.println(sortedList2); // 내림차순 정렬

루핑 - peek, forEach

요소 전체를 반복하여 어떠한 작업을 수행하는 것을 말한다.

peek

가공 단계에서 사용하는 메소드이다. 확인해본다는 의미이며, 특정 결과를 반환하지는 않는다. 작업을 처리하는 중간에 결과를 확인해볼 때 사용할 수 있다. → 결과를 집계하는 메소드를 호출하지 않으면 적용되지 않는다.

List<Integer> list = Arrays.asList(1,2,3,4,5);
        
// 짝수를 걸러내서 총 합 구하기 / 가공 단계에서 사용할 수 있는 peek 사용
// Integer 타입이라 sum 연산을 할 수 없어서 primitive 타입으로 변환 후 sum 연산을 해야한다.
// Stream<Integer> -> IntStream 으로 변환
int sum = list.stream()
        .mapToInt(element -> element) // 타입 변환
        .filter(element -> element % 2 == 0)
        .peek(System.out::println)
        .sum();
System.out.println("짝수들의 총 합 : " + sum);

// IntStream -> Stream<Integer> primitive 타입 stream을 wrraper 타입 stream 으로 변환 시에는 boxing 메소드 사용

forEach

결과에서 사용하는 메소드이다. 위 코드에서 sum과 같은 결과 메소드와 중복해서 사용할 수 없다.

// forEach 사용해서 필터링된 stream 요소 출력 / 결과 단계에서 사용
List<Integer> list2 = Arrays.asList(1,2,3,4,5);
list2.stream()
        .filter(element -> element % 2 == 0)
        .forEach(element -> System.out.println(element)); // = System.out::println

수집 - collect()

결과 단계에서 사용한다.

collect

스트림 최종 단계에서 사용하는 메소드이며, 어떤 요소를 어떤 컬렉션에 수집할 지 결정할 수 있다. 스트림으로 가공한 데이터를 최종적으로 컬렉션에 변환한다.

// 홀수만 골라내어 새로운 집합을 만드는 예제
List<Integer> list = Arrays.asList(1, 2, 3, 4, 5);

Set<Integer> set = list.stream()
							.filter(n -> n % 2 == 1)
							.collect(Collectors.toCollection(HashSet::new));
							
set.stream().forEach(System.out::println);  // {1, 3, 5}

Collectors.toCollection 을 사용하여 HashSet이라는 컬렉션에 데이터를 수집

Collectors에서 제공하는 메소드

Collectors 정적 메소드설명
toList요소를 List에 저장
toSet요소를 Set에 저장
toCollection요소를 특정 컬렉션에 저장
toMap요소를 Map에 저장

그루핑하여 수집

collect 메소드를 사용하여 컬렉션 요소들을 그룹핑해서 Map 객체를 생성하는 기능, Collectors의 groupingBy를 사용

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

Map<Integer, Long> collected = list.stream()
        .collect(
                Collectors.groupingBy(
                        n -> n, // 요소 그대로 키값으로
                        Collectors.counting() // 그룹핑 요소 각각 카운팅
                )
        );
collected.forEach((key, value) -> System.out.println(key + " : " + value + "개"));
1 : 22 : 33 : 14 : 15 : 3

활용 문제 풀이

// List<Integer>가 주어졌을 때, 각 숫자를 제곱한 값의 리스트로 변환하세요

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

// 결과 예시 [1, 4, 9, 16, 25]
List<Integer> numbers = Arrays.asList(1,2,3,4,5);
List<Integer> result = numbers.stream()
        .map(x -> x * x)
        .collect(Collectors.toList());
System.out.println(result);
//ist<String>의 문장들을 단어로 나누어(‘:’구분자) 하나의 List<String>로 변환하세요.

List<String> sentences = Arrays.asList("Hello:world", "Java:stream:flatMap", "Functional:programming");

// 결과 [Hello, world, Java, stream, flatMap, Functional, programming]
List<String> sentences = Arrays.asList("Hello:world","Java:stream:flatMap","Functional:programming");
List<String> collect = sentences.stream()
        .flatMap(x -> Arrays.stream(x.split(":")))
        .collect(Collectors.toList());
System.out.println(collect);
// 이차원 컬렉션에 들어있는 정수들을 하나의 컬렉션으로 변환해주세요

List<List<Integer>> numbers = Arrays.asList(
			Arrays.asList(1, 2, 3),
			Arrays.asList(4, 5, 6),
			Arrays.asList(7, 8, 9)
);

// 결과 [1, 2, 3, 4, 5, 6, 7, 8, 9]
List<List<Integer>> numbers2 = Arrays.asList(
        Arrays.asList(1, 2, 3),
        Arrays.asList(4, 5, 6),
        Arrays.asList(7, 8, 9)
);
List<Integer> result2 =
        numbers2.stream()
        .flatMap(x -> x.stream())
        .toList();
System.out.println(result2);
// Person 클래스의 리스트가 주어졌을 때, 각 객체의 이름만 추출하여 List<String>으로 변환하세요.

class Person{
    String name;
    int age;

    Person(String name, int age){
        this.name = name;
        this.age = age;
    }
}

List<Person> people = Arrays.asList(
        new Person("Alice", 30),
        new Person("Bob", 25),
        new Person("Charlie", 28)
);

// 결과 예시 [Alice, Bob, Charlie]
 List<String> peopleList = people.stream()
         .map(person -> person.name)
         .toList();
System.out.println(peopleList);
// Person 클래스의 리스트가 주어졌을 때, 나이가 28 이상인 사람만 필터링하여 새로운 리스트를 만드세요
class Person{
    String name;
    int age;

    Person(String name, int age){
        this.name = name;
        this.age = age;
    }
}

List<Person> people = Arrays.asList(
        new Person("Alice", 30),
        new Person("Bob", 25),
        new Person("Charlie", 28)
);

// 결과 예시 [Alice, Charlie]
 List<String> peopleList = people.stream()
         .filter(person -> person.age >= 28)
         .map(person -> person.name)
         .toList();
System.out.println(peopleList);
// List<String> 형태의 문자열 리스트가 주어졌을 때, 각 문자열의 길이를 계산하여 길이가 5이하인 요소만 담아서 List<String> 으로 변환하세요.

List<String> words = Arrays.asList("apple", "banana", "cherry");

// 결과 예시 [apple]
 List<String> words = Arrays.asList("apple", "banana", "cherry");

List<String> wordsResult = words.stream()
        .filter(x -> x.length() <= 5)
        .toList();
System.out.println(wordsResult);
// List<String> 형태의 문자열 리스트가 주어졌을 때, 내림차순으로 정렬하고 모든 문자열을 대문자로 변환하세요.

List<String> words = Arrays.asList("hello", "world", "java");

// 결과 예시 [WORLD, JAVA, HELLO]
List<String> words2 = Arrays.asList("hello", "world", "java");

List<String> result3 = words2.stream()
        .map(x -> x.toUpperCase())
        .sorted(Comparator.reverseOrder())
        .toList();
System.out.println(result3);
// List<String> 형태의 문자열 리스트가 주어졌을 때, 문자열의 길이가 5글자 이상인 것만 필터링하여 새로운 리스트를 만드세요.

List<String> words = Arrays.asList("apple", "banana", "cat", "dog", "elephant");

// 결과 예시 [apple, banana, elephant]
List<String> words3 = Arrays.asList("apple", "banana", "cat", "dog", "elephant");

List<String> result4 = words3.stream()
        .filter(x -> x.length() >= 5)
        .toList();

System.out.println(result4);
// List<Integer>가 주어졌을 때, 리스트에서 10보다 크고 50보다 작은 숫자만 필터링하세요.

List<Integer> numbers = Arrays.asList(5, 12, 25, 37, 48, 50, 63);

// 결과 예시 [12, 25, 37, 48]
List<Integer> numbers3 = Arrays.asList(5, 12, 25, 37, 48, 50, 63);

List<Integer> result5 = numbers3.stream()
        .filter(x -> 50 > x && x > 10)
        .toList();
System.out.println(result5);
// List<String> 형태의 문자열 리스트가 주어졌을 때, 특정 단어 (예: "apple")가 포함된 문자열만 필터링하세요.

List<String> sentences = Arrays.asList("I like apples", "Bananas are tasty", "apple pie is delicious", "I have an apple");

// 결과 예시 [I like apples, apple pie is delicious, I have an apple]
List<String> sentences2 = Arrays.asList("I like apples", "Bananas are tasty", "apple pie is delicious", "I have an apple");

List<String> result6 = sentences2.stream()
        .filter(x -> x.contains("apple"))
        .toList();
System.out.println(result6);
profile
룰루

0개의 댓글