배열과 훑개에 대해 알아봅시다.
Todo : 존댓말로 바꾸기!
내가 넣고 싶은만큼 단어를 입력하고(한 줄에 한 단어씩, 빈 줄에 엔터를 치면 끝나는 걸로), 그 단어들을 알파벳 순서로 되돌려주는 프로그램을 짜보자. 오케바리?
자... 그러니까 처음으로.. 일단 우리는... 음... 뭘하냐면.. 어.. 음....
근데, 우리 이거 못 만들 것 같다. 몇 개인지 알 수 없는 단어들을 저장하는 방법을 먼저 알아야 하고, 그것들을 관리하는 방법도 알아야 단어들이 서로 섞여 버리지 않게 할 수 있다. 단어들을 뭔가 목록(list) 같은 것 속에 넣어 두어야 된다. 배열(array)이 필요하다.
배열은 컴퓨터 속에 있는 목록이다. 목록의 모든 슬롯(저장공간)은 변수처럼 작동한다. 특정 슬롯이 어떤 객체를 가르키고 있는지 알 수 있고, 그 저장공간이 다른 객체를 가리킬 수도 있다. 몇몇 배열들을 살펴보자.
(역자주: 가리키다. 지시하다. 등의 표현이 개념적으로는 맞겠지만 확실히 이해하기는 힘든 것 같아요. )
[]
[5]
['Hello', 'Goodbye']
flavor = 'vanilla' # This is not an array, of course... #이건 당연히 배열이 아니다. [89.9, flavor, [true, false]] # ...but this is. # 그런데 이건 배열이 맞다.
처음에는 빈 배열이 있다. 다음으로 숫자 하나를 가지고 있는 배열이 있고, 문자열 두 개를 가진 배열이 나온다. 다음으로 간단한 변수 할당(assignment)이 있고, 세 개의 객체를 가지고 있는 배열이 있는데, 이 세 개 중 마지막 객체는 [true, false]라는 배열이다. 변수들은 객체가 아니라는 점을 명심하자. 때문에 마지막 배열은 실수, 문자열, 그리고 배열을 가르키고 있다. 변수 flavor에 다른 값이 할당되어 있어도 배열은 변하지 않는다.
배열 속의 특정 객체를 찾아내기 위해서 모든 슬롯(저장공간)은 고유의 지정번호(index number)를 가지고 있다. 프로그래머들 (그리고 우연히도 수학자들 역시) 숫자를 0부터 세기 때문에, 첫번째 슬롯(저장공간)은 슬롯 0번 이다. 이렇게해서 배열 속에 있는 객체를 찾을 수 있게 된다.
names = ['Ada', 'Belle', 'Chris']
# 예제에 사용한 이름을 바꿀까?
puts names
puts names[0]
puts names[1]
puts names[2]
puts names[3] # This is out of range. # 범위를 벗어났음.
#실행결과
Ada
Belle
Chris
Ada
Belle
Chris
nil
그러니까, puts names는 names 배열 속에 있는 각각의 이름들을 출력해주는 것을 알 수 있다. 다음으로, puts names[0]는 names 배열의 "첫번째" 이름을, puts names[1]은 "두번째" 이름을 출력한다. 확실히 조금 헷갈린다. 하지만 계속 사용하다보면 익숙해 진다. 숫자를 셀 때 0부터 시작한다고 생각해야 하고, '첫번째', '두번째' 같은 단어는 그만 쓰는 것이 좋다. 5번 음식이 나오는 서양식 코스요리를 먹는다면, 첫번째 코스에 대해 말하지 말고 코스 0에 대해 말해보자(그리고 머리속에서는 course[0]를 떠올리자). 손가락이 5개 있다면 각각은 손가락 0, 1, 2, 3, 4 이다.
(역자주: 저글링 부분 이하 번역 생략. 웃으며 읽으라고 쓴 내용인데 한국어로 번역하려니까 괜히 골아픈 내용이 되는 듯.. ㅡ.ㅡ;;)
마지막으로, 어떤 일이 벌어질지 보기 위해서 puts names[3]를 쳐봤다. 에러가 날 것이라고 생각했나? 가끔 어떤 질문을 던졌을 때, 그 질문이 말이 안될 때가 있다(적어도 컴퓨터에게는). 이럴 때 에러가 난다. 하지만 가끔은 질문에 대한 답이 없음(무, nothting)일 수 있다. 3번 슬롯에는 무엇이 들어있나? 없음 (무, nothing)이다. names[3]는 뭘까? nil 이다. nil은 ruby 언어로 '없음'이라고 말하는 말하는 방법이다. nil은 기본적으로 "아무런 객체가 없다"를 뜻하는 특별한 객체이다.
이 우스꽝스런 슬롯 지정번호 때문에 골치아프다고 두려워할 필요 없다. 많은 경우 다양한 배열 메서드를 통해 이런 골치아픈 상태를 피할 수 있다. 예를 들어 each 같은 메서드를 사용할 수 있다.
Each 메서드는 어떤 일을 해줄까요?
each 메서드는 배열이 가르키는 객체(배열 속에 있는 객체) 각각에 우리가 원하는 것을 할 수 있게 해준다. 아래 있는 언어들에 각각에 대해 뭔가 좋은 말을 해주고 싶다면, 이렇게 하면 된다.
languages = ['English', 'German', 'Ruby'] languages.each do |lang| puts 'I love ' + lang + '!' puts 'Don\'t you?' end puts 'And let\'s hear it for C++!' puts '...' #실행결과 I love English! Don't you? I love German! Don't you? I love Ruby! Don't you? And let's hear it for C++! ...
무슨 일이 벌어졌는지 봤남? 지정번호(number)를 쓰지 않고 배열 속에 있는 모든 객체들을 가져다 썼다. 이건 분명히 멋진거다. 위의 프로그램을 한국어로 번역하자면, 대략 이렇게 읽을 수 있다.
아마 여러분은 속으로 이렇게 생각하고 있을 지도 몰라요, "전에 배운 순환문이랑 비슷한 것 같은데?" 네, 순환문과 비슷합니다! 한가지 중요한 차이점이 있다면, 이 each라는 메서드는 메서드라는 거죠. while과 end, do, if, else등등 파랗게 표시된 단어들은 메서드가 아닙니다. 이들은 루비의 근본적인 부분을 이루는 것들이죠. 마치 = 나 괄호처럼ㄹ요. 영어에서 구두점 처럼요.
하지만 each는 아닙니다. each는 배열 메서드예요. each같은 메서드처럼 loops'처럼 행동하는' 메서드를 보통 iterators라고 부릅니다.
iterator에 대해서 살펴볼 점은요, iterators뒤에는 항상 do와 end가 온다는 거예요. while과 if 안에는 do가 없었죠. iterator를 쓸 때에만 do를 씁니다.
작고 귀여운 iterator를 또 하나 살펴 보지요. 이 iterator는 배열 메서드가 아니에요. 정수 메서드입니다.
3.times do puts 'Hip-Hip-Hooray!' end #실행결과 Hip-Hip-Hooray! Hip-Hip-Hooray! Hip-Hip-Hooray!
다른 배열 메서드도 살펴볼까요?
So we've learned each, but there are many other array methods... almost as many as there are string methods! In fact, some of them (like length, reverse, +, and *) work just like they do for strings, except that they operate on the slots of the array rather than the letters of the string. Others, like last and join, are specific to arrays. Still others, like push and pop, actually change the array. And just as with the string methods, you don't have to remember all of these, as long as you can remember where to find out about them (right here).
자, 이제 몇 가지 배열에 대해서 배워봤습니다. (앞 내용 확인하기), 하지만 다른 종류의 배열 메서드도 많이 있습니다. 문자열 관련 메서드 만큼이나 많죠. 사실 배열 관련 매서드 중에 몇 가지는, 이를 테면 length라든가, reverse, +, * 라든가 하는 메서드는 배열의 slot이 아니라, 문자열에 대해서 작업할 때에는 문자열 관련 메서드와 비슷하게 작동합니다. (내용을 제대로 이해한건지 모르겟음 ㅜㅜ) last라든지 join 등의 다른 메서드는 배열에 특이하게 있는 메서드라고 할 수 있고요. 그리고 push나 pop 등의 메서드는 실제로 배열을 바꿉니다. 그리고 문자열 메서드의 경우와 마찬가지로, 이 메서드를 모두 기억할 필요는 없습니다. 다만 어디에서 이런 메서드에 대해서 찾아볼 수 있는지만 알면 되요. 바로 여깁니다. (링크 넣기)
First, let's look at to_s and join. join works much like to_s does, except that it adds a string in between the array's objects. Let's take a look:
자, 그럼 우선은 to_s메서드와 join 메서드를 같이 살펴 보죠. join 메서드는 to_s 메서드와 비슷하게 작동합니다. 다만 join 메서드가 배열의 objects 사이에다가 문자열을 삽입할 때에는 to_s와는 다르게 작동하죠. 다음 예를 볼까요 :
foods = ['artichoke', 'brioche', 'caramel'] puts foods puts puts foods.to_s puts puts foods.join(', ') puts puts foods.join(' :) ') + ' 8)' 200.times do puts [] end #실행결과 artichoke brioche caramel artichokebriochecaramel artichoke, brioche, caramel artichoke :) brioche :) caramel 8)
여기서 보듯이 puts가 객체를 다루는 방식은 배열을 다루는 방식과 다릅니다. 배열에 있는 객체의 각각에 대해서 그냥 puts을 호출시키죠. 그래서 비어있는 배열을 가지고 200번 puts를 호출하더라도 아무런 것도 안 보이게 되는 겁니다. 배열이 아무것도 가리키지 않기 때문이죠. 그러니 puts를 호출하더라도 보여줄 게 없죠. (아무것도 안 하는 작업을 200번 하더라도, 아무것도 안 한다는 점에는 변함이 없죠.) 다른 배열을 포함하고 있는 배열을 가지고 puts를 호출해 봅시다. 예상했던 결과가 나오나요?
아참, 화면에 빈 줄을 넣고 싶을 때는 빈 문자열을 가지고 puts를 호출했는데, 알아보셨나요? 이 역시 같은 역할을 합니다.
자, 이제는 push, pop, last 메서드를 살펴 봅시다. push와 pop 메서드는 서로 반대된다고 할 수 있어요. 마치 +와 -가 그렇듯이요. push는 배열의 끝에다가 객체를 하나 집어넣어주고요, pop은 배열에서 제일 마지막에 있는 객체를 지워줍니다. 그리고 그 마지막 객체가 뭐였는지 알려주죠. last는 pop과 비슷하긴 한데요, 배열의 끝에 무슨 객체가 알려준다는 점에서 pop과 비슷하고요, 다른 점은 배열에서 객체를 지우지 않는다는 겁니다. 즉 push와 pop은 실제로 배열안에 있는 것을 바꾸는 반면에 last는 배열을 바꾸지 않죠:
favorites = [] favorites.push 'raindrops on roses' favorites.push 'whiskey on kittens' puts favorites[0] puts favorites.last puts favorites.length puts favorites.pop puts favorites puts favorites.length #실행결과 raindrops on roses whiskey on kittens 2 whiskey on kittens raindrops on roses 1
프로그램 만들어보기
7장의 처음부분에서 얘기나누었던 프로그램을 작성해 보세요.
힌트를 드린다면, 배열 관련된 메서드 중에는 sort라는 메서드가 있답니다. 아주 편리하죠. sort를 사용하면 배열을 정렬할 수가 있답니다. sort를 사용해서 프로그램을 만들어보세요!
앞에서 만든 프로그램을 만드는데 sort 메서드를 사용하지 말고 만들어 보세요
프로그래밍을 한다는 것은 문제를 해결한다는 것과 비슷하답니다. 그러니 해볼 수 있는 것은 다 시도해 보세요!
목차를 보여주는 프로그램을 작성하세요. (메서드에 대한 장부터 시작하세요.)
프로그램의 시작 부분에는 목차에 들어가는 내용을 포함하는 배열을 작성하세요. 예를 들면 챕터의 이름, 페이지 등등이 들어가야겠죠? 그다음 배열에 들어있는 정보를 예쁜 목차 포맷으로 화면에 보여주세요.
7장을 마무리하며
자, 이제까지 아주 다양한 메서드에 대해 살펴 보았습니다. 이제는 직접 메서드를 만들어볼까요?