오늘은 배열의 메서드 중 블록 전달을 통해 원하는 반복 작업을 처리하거나 배열에서 원하는 요소를 검색하는 메서드를 알아보려고 한다.
처음 살펴 볼 each 메서드는 블록을 받아 반복 작업을 처리할 수 있게 해주는 가장 기본적인 메서드라 할 수 있다.
사용법은 매우 간단하다. 아래 그림을 보면 블록 안에서 각각의 요소 문자열을 대문자로 변환하여 화면에 출력하고 있다.
당연히 원래 배열에는 변함이 없다.
블록 안에서 배열의 요소와 함께 해당 요소의 인덱스를 가지고 작업을 해야 한다면 아래 첫 번째 코드처럼 따로 변수를 만들어 사용할 필요 없이 each_with_index 메서드를 사용하면 된다.
블록 파라미터를 두 개 선언해 주면 첫 번째 변수에는 요소 값을 두 번째 변수에는 해당 요소의 인덱스를 넘겨 준다.
inspect 메서드는 해당 객체의 클래스를 확인하기 쉬운 형태의 문자열로 표현해 반환하는 메서드로서 p 메서드로 객체를 출력할 때 내부적으로 inspect 메서드의 반환 값을 출력한다.
아래 그림을 보면 숫자 1과 문자열 "1" 을 puts 메서드를 사용해서 출력하면 둘 다 1 로 나와 어떤 클래스인지 알 수가 없다. 그러나 p 메서드로 호출하면 구분이 된다.
배열도 p 로 출력하면 배열의 리터럴 표기법 형태로 출력해 주기 때문에 해당 객체가 '배열'임을 쉽게 알 수 있다.
puts 메서드로 배열을 출력하면 배열의 요소 각각을 출력하는 걸 볼 수 있는데 2차원 배열의 경우에도 마찬가지로 가장 안쪽의 요소들을 하나씩 출력하고 있다.
그래서 puts 메서드는 보통 사용자에게 값을 표시해 줄 때 사용하고 p 메서드는 개발자가 값을 확인해야 할 때 주로 사용한다.
이제부터는 조금씩 더 재미있는 기능들을 살펴볼 차례이다.
먼저 배열이 제공하는 검색 기능을 알아보자. 배열의 요소 중 원하는 값을 찾을 때는 find 나 select 메서드를 사용하면 되는데 find 메서드는 해당하는 요소가 여러 개 있을 때 첫 번째 요소를 반환하고 select 메서드는 해당하는 요소 전체를 배열에 담아 반환한다.
그리고 reject 메서드는 select 메서드와 반대로 필요 없는 값을 제외한 나머지를 배열로 받고 싶을 때 사용한다.
아래 그림을 보자. 1부터 10까지의 정수가 담긴 배열에서 find 메서드로 짝수를 찾게 되면 첫 번째 짝수인 2 가 반환되고 select 메서드로 짝수를 찾게되면 1부터 10까지의 모든 짝수 2,4,6,8,10 을 배열에 담아 반환한다.
그리고 reject 메서드로도 홀수를 걸러내면 짝수만 담긴 배열을 받을 수 있다.
특정 범위 내의 정수 배열을 만들기 위해 Range 객체의 to_a 메서드를 사용하였는데 ("a".."e").to_a 로 ["a", "b", "c", "d", "e"] 알파벳 문자 배열도 쉽게 만들 수 있다. 한 번 테스트해 보기 바란다.
select 메서드와 reject 메서드는 모두 원래의 배열은 변경시키지 않고 원하는 요소들만 새 배열에 담아 돌려주는데 만약 원래의 배열 자체를 변경하여 원하는 요소만 남도록 하려면 어떻게 해야 할까?
그때는 동일한 이름의 메서드 끝에 '!' 가 붙은 select! 메서드와 reject! 메서드를 사용하면 된다. 루비에서는 보통 호출 대상 객체 자체를 변경시키는 등 주의가 필요한 메서드에 대해 끝에 '!' 을 붙여 이름을 짓는다.
아래 그림을 보면 select! 메서드와 reject! 메서드를 호출한 후에 원래의 배열이 변경된 것을 볼 수 있다.
이번엔 조건에 맞는 요소 자체가 아니라 해당 요소의 인덱스를 찾는 방법을 살펴보자.
index 메서드는 조건에 맞는 첫 번째 요소의 인덱스를 반환하고 rindex 메서드는 반대로 조건에 맞는 가장 마지막 요소의 인덱스를 반환한다.
rindex 에서 'r' 은 'reverse' 를 뜻하고 그래서 배열의 오른쪽에서 왼쪽으로 찾는다.
아래 그림을 보면 메서드 호출 시 인수를 주면 인수와 요소의 값을 비교하여 해당하는 요소의 인덱스를 반환하고 블록을 주면 블록의 실행 결괏값이 참인 요소의 인덱스를 반환한다.
만약 조건에 맞는 모든 요소의 인덱스를 찾으려면 어떻게 해야 할까? 단순하게 생각하면 배열의 요소가 아니라 인덱스로 반복문을 실행하여 조건에 맞는 인덱스를 별도의 배열에 저장하면 될 것 같다.
먼저 이 아이디어 그대로 작성해 보자.
원하는 대로 1부터 10까지의 정수에서 짝수인 요소의 인덱스만 잘 가져와 보여준다. 그런데 배열에는 이미 각각의 인덱스로 원하는 처리를 할 수 있는 메서드가 존재한다.
each_index 라는 메서드인데 each_with_index 와 헛갈리지 않길 바란다. each_index 는 배열의 인덱스를 하나씩 블록 파라미터에 전달하면서 블록을 실행시켜 준다.
그래서 each_index 를 사용하여 위의 코드를 다시 아래처럼 수정할 수 있다.
그런데 배열의 each_index 메서드를 블록 없이 호출하게 되면 Enumerator 객체를 반환하는데 Enumerator 객체는 배열과 마찬가지로 select 메서드를 사용할 수 있다.
이것은 Enumerator 클래스가 Array 클래스와 마찬가지로 Enumerable 모듈을 인클루드하고 있기 때문인데 이와 관련해서는 별도의 주제로 글을 쓸까 한다.
each_index 메서드를 통해 받은 Enumerator 객체는 배열의 요소가 아닌 인덱스에 대해 반복 처리를 할 수 있도록 해주기 때문에 아래 그림처럼 메서드 체이닝 형식으로 select 메서드를 바로 호출하면 간결한 코드로 조건에 맞는 모든 요소의 인덱스를 찾을 수 있다.
마지막으로 include? 메서드는 배열에서 인수와 같은 값을 갖는 요소가 존재하는지 알려준다.
이번 글에서는 배열에서 기본적인 반복 처리 작업과 검색을 위한 다양한 메서드에 대해 알아보았다.
다음 글에서는 배열에서 조금 특수한 목적을 위해 반복 처리를 해야할 때 사용할 수 있는 몇 가지 유용한 메서드를 알아보겠다.
See you again~~