Ruby의 select 메서드를 사용하면 객체 배열을 손쉽게 필터링할 수 있습니다.
예를 들어 숫자 리스트에서 짝수만 골라내야 한다면 select가 딱 맞는 도구입니다.
select 없이 작성하면 다음과 같습니다:
even_numbers = []
[1,2,3,4,5,6].each do |n|
if n.even?
even_numbers << n
end
end
even_numbers
이렇게 간단한 작업에 코드가 꽤 길어지죠?
지금부터 select를 제대로 활용하는 방법을 알아보겠습니다.
Select 메서드 기본 예제
select를 사용하려면 블록이 필요합니다.
블록 안에는 true 또는 false로 평가되는 값을 반환해야 하며, select는 그 결과를 기준으로 배열 요소를 걸러냅니다.
Ruby의 불리언(Boolean) 값에 대해 더 알고 싶다면 관련 문서를 참고하세요.
예제:
[1,2,3,4,5,6].select { |n| n.even? }
앞서 소개한 첫 번째 예제와 동일한 결과를 훨씬 적은 코드로 얻을 수 있습니다.
심지어 코드를 더 줄일 수도 있습니다.
이렇게요:
[1,2,3,4,5,6].select(&:even?)
이런 축약형(& 기호)은 배열의 모든 요소에 단일 메서드를 바로 호출할 때만 사용할 수 있다는 점에 유의하세요.
참고로 select는 해시(Hash)에도 사용할 수 있습니다.
예제:
stock = {
apples: 10,
oranges: 5,
bananas: 1
}
stock.select { |k, v| v > 1 }
# {:apples=>10, :oranges=>5}
여기서 k는 키(key)를, v는 값(value)을 나타냅니다.
즉, "재고가 1개보다 많은 과일을 모두 찾아줘"라고 요청하는 것과 같습니다.
다른 메서드와 조합하기
select는 다른 Enumerable 메서드와 조합해 사용할 수 있습니다.
가장 대표적인 것이 with_index입니다.
예제:
fruits = %w(apple orange banana)
fruits.select.with_index { |word, idx| idx.even? }
# ["apple", "banana"]
이렇게 하면 객체 자체가 아니라 인덱스를 기준으로 요소를 필터링할 수 있습니다.
원본 배열 직접 수정하기
배열에 select를 사용하면 항상 새로운 배열이 생성됩니다.
반면 원본 배열 자체를 변경하고 싶다면 select! 메서드를 사용하면 됩니다.
사용 방법:
fruits = %w(apple orange banana)
fruits.select! { |fruit| fruit.start_with? "a" }
# ["apple"]
느낌표(!)로 끝나는 메서드(예: select!)는 새 객체를 반환하는 대신 원본 객체를 변경합니다. 다만 이 규칙은 언어 차원에서 강제되는 것이 아니라 개발자들 사이의 암묵적인 관례일 뿐이라는 점을 기억하세요.
find vs select
select는 목록을 필터링해서 결과를 담은 배열을 얻고 싶을 때 매우 유용합니다.
그런데 객체 하나만 찾고 싶다면 어떻게 할까요?
이럴 때는 find 메서드를 사용하면 됩니다.
예제:
letters = %w(a aa aaa aaaa)
letters.find { |l| l.size == 3 }
# "aaa"
letters.find { |l| l.size == 10 }
# nil
find는 조건에 일치하는 첫 번째 요소를 반환하고, 찾지 못하면 nil을 돌려줍니다.
find_all 메서드 이해하기
find_all 메서드가 무엇인지, 그리고 find 및 select와 어떤 관계인지 궁금하다면...
정답은 아주 간단합니다!
find_all메서드는select의 별칭(alias)입니다.find메서드는 여러 객체가 아닌 특정 하나의 객체를 찾을 때 사용합니다.
또한 Ruby 2.6부터는 select의 또 다른 별칭으로 filter가 추가되었습니다.
filter
select의 반대는 무엇일까?
원하는 요소를 선택하는 대신, 불필요한 요소를 제거하는 접근 방식도 있습니다.
select로도 충분히 가능합니다:
[1,2,3,4,5,6].select { |n| n != 4 }
하지만 의도를 더 명확하게 드러내는 메서드가 바로 reject입니다.
예제:
[1,2,3,4,5,6].reject { |n| n == 4 }
성능 면에서나 기술적으로 이점이 있는 것은 아니지만, 코드의 가독성과 의도 전달력이 훨씬 좋아집니다.
Rails의 select 메서드 주의사항
Rails 모델을 다루다 보면 거기서도 select를 사용할 수 있다는 것을 알게 되는데, 혼동하지 않도록 주의해야 합니다.
꼭 알아두어야 할 점은...
이 select 메서드는 지금까지 설명한 것과 전혀 다릅니다!
예제:
Fruit.select(:id, :name, :color)
ActiveRecord 모델에 select를 사용하면 데이터베이스에서 특정 컬럼만 조회하겠다는 의미가 됩니다.
이는 주로 성능 최적화를 위해 사용되는 것으로 알려져 있습니다.
마지막으로 한 가지 덧붙이자면:
Rails 앱 안에서 일반 배열을 다루고 있다면, 이 글 전체에서 설명한 그 select 메서드를 사용하는 것입니다.
마무리
지금까지 배열, 범위(range), 해시처럼 객체 컬렉션을 다룰 때 가장 유용한 Ruby 메서드 중 하나인 select에 대해 살펴봤습니다.

이제 여러분 차례입니다. 에디터를 열고 직접 활용해 보세요!
읽어주셔서 감사합니다!