Ruby

본 토픽은 현재 준비중입니다. 공동공부에 참여하시면 완성 되었을 때 알려드립니다.

배열, 해쉬

배열

배열이란 영어로 Array라고 한다.  배열은 연관된 데이터를 모아서 관리하기 위해서 사용하는 데이터 타입이다. 변수가 하나의 데이터를 임시로 저장하기 위한 것이라면 배열은 여러 개의 데이터를 저장하기 위한 것이라고 할 수 있다. 아래의 예제를 보자. 변수 name에는 문자 egoing이 할당되었다. 이제부터 name을 호출하면 문자 egoing을 사용할 수 있다.

name = 'egoing'
puts name

배열의 생성

그렇다면 여러 개의 데이터를 하나의 변수에 담아서 관리할 수 있는 방법은 없을까? 있다. 배열을 쓰면 된다. 변수 member에 회원정보를 담아보자. 대괄호([])는 배열을 만드는 기호다. 대괄호 안에 데이터를 콤마(,)로 구분해서 나열하면 배열이 된다.

member = ['egoing', 'k8805', 'sorialgi']

하나의 변수에 3개의 데이터를 담았다. 각각의 데이터를 원소(element)라고 부른다. 자 그럼 이 데이터를 꺼내오려면 어떻게 해야 할까? 아래의 예제를 보자.

member = ['egoing', 'k8805', 'sorialgi']
puts member[0]
puts member[1]
puts member[2]

결과는 다음과 같다.

egoing
k8805
sorialgi

즉 배열에 담겨있는 값을 가져올 때는 대괄호 안에 숫자를 넣는다. 이 숫자를 색인(index)라고 부르고 0부터 시작한다. 이 값을 이용해서 배열에 저장된 원소를 찾을 수 있다.

배열이 없다면

그렇다면 배열이 없다면 어떻게 될까? 예를 들어 맴버의 이름을 제공하는 메소드를 만들어야 한다고 해보자. 그런데 메소드는 하나의 값만을 반환(return) 할 수 있다. 아래의 예를 보자.

def get_member1
    return 'egoing'
end

puts get_member1()

def get_member2
	return 'k8805'
end

puts get_member2()

def get_member3
	return 'sorialgi'
end

puts get_member3()

하나의 메소드는 하나의 값만을 반환할 수 있기 때문에 위와 같이 각각의 회원 정보를 반환하는 메소드수를 만들었다.

이번엔 배열을 이용한 아래의 코드를 보자. 맴버를 담고 있는 배열을 반환하고 있다. 간단하지 않은가?

def get_member()
    return ['egoing', 'k8805', 'sorialgi']
end

puts get_member()

배열의 사용

배열의 진가는 반복문과 결합했을 때 나타난다. 반복문으로 배열에 담긴 정보를 하나씩 꺼내서 처리 할 수 있기 때문이다. 다음 예제를 보자.

def get_members
    return ['egoing', 'k8805', 'sorialgi']
end

members = get_members()

for index in 0 ... members.size
    puts  members[index].capitalize
end

결과는 아래와 같다.

Egoing
K8805
Sorialgi

위의 예제에서 주목해야 할 것은 반복문과 배열을 결합한 부분이다. 반복문을 이용해서 배열 members의 내용을 하나씩 꺼낸 후에 이름의 첫글자를 대문자로 변경한 후에 출력하고 있다. (알파벳의 첫글자를 대문자로 만드는 방법은 String.captalize를 참고) 정리하면, 배열이란 연관된 정보를 하나의 그룹으로 관리하기 위해서 사용한다. 그리고 그 정보를 처리 할 때는 반복문을 이용한다.

반복자 - iterator

each

앞선 반복문 수업에서 while과 for 문을 알아봤다. 하지만 ruby에서는 이런 것들보다는 반복자라는 것을 더 많이 쓴다. 다음 코드를 보자. 결과는 배열의 값을 하나씩 출력한다.

arr = [1, 2, 3, 4, 5]
arr.each { |a| puts a }

arr = [1, 2, 3, 4, 5]

arr은 1부터 5까지의 숫자가 담겨있는 배열이다.

arr.each

each는 배열에 내장되어 있는 반복자(iterator)다. 이 반복자 뒤에 따라오는 { |a| puts a } 가 배열의 원자 수 만큼 반복된다.

{ |a| puts a }는 이름이 없는 메소드를 의미한다. 또한 배열이 each라는 메소드를 지원하는 것은 배열이 enumerator를 포함(include)하기 때문인데, 이 또한 여기서 다루지 않는다. 그리고 arr.each라는 방식으로 메소드를 호출할 수 있는 이유는 객체지향 토픽에서 살펴볼 예정이다. 프로그래밍 경험이 없다면 지금은 이해가 되지 않는 것이 당연하다. 차차로 알 수 있는 내용이다.

|a|

파이프(|) 사이의 a는 인자다. 반복이 실행될 때마다 인자 a에는 배열의 값이 담겨진다. a는 인자의 이름이기 때문에 다른 이름으로 변경할 수 있다. 하지만 그 인자를 사용하는 코드의 이름도 다음과 같이 변경돼야 한다. { |b| puts b }

puts a

인자 a (|a|)의 값이 변수 a에 할당 됐기때문에 puts a는 각각의 원소를 화면에 출력한다.

위의 코드는 아래와 같이 사용할 수도 있다. do와 end가 열리는 중괄호({)와 닫히는 중괄호(})의 역할을 하고 있다.

[1, 2, 3, 4, 5].each do |a| puts "This is #{a}" end

map

each는 반복작업이 목적이다. map은 each와 비슷하지만 배열의 내용을 바꾸는 것이 목적이다. 다음 예를 보자.

fruit = ['apple', 'orange', 'grape']
fruit = fruit.map { |e| e + ' is delicious' }
puts fruit

결과는 아래와 같다.

apple is delicious
orange is delicious
grape is delicious

배열 제어

배열은 복수의 데이터를 효율적으로 관리, 전달하기 위한 목적으로 고안된 데이터 타입이다. 따라서 데이터의 추가/수정/삭제와 같은 일을 편리하게 할 수 있도록 돕는 다양한 기능을 가지고 있다. 몇가지 중요한 기능들만 살펴보자.

배열의 생성

위에서 대괄호를 이용해서 배열을 생성하는 법을 알아봤다. 아래 방법은 new 메소드를 이용한 방법이다.

아래 예제와 같은 문법적인 설명은 객체지향 수업에서 다루게 될 것이다.

arr = Array.new()

다음은 배열을 똑같은 글자로 채우는 방법이다. 아래와 같은 방법으로 coding everybody라는 값이 채워진 10개짜리 원소를 가진 배열을 만들었다.

arr = Array.new(10, 'coding everybody')

다음은 1부터 10까지의 숫자로 채워진 배열을 만드는 코드다.

arr = Array(1..10)

배열의 크기

아래와 같은 방법을 배열의 크기를 알아낼 수 있다

arr = [1, 2, 3, 4, 5]
puts arr.length
puts arr.size

배열의 조작

추가

다음은 배열의 끝에 원소를 추가하는 방법이다. 배열 arr는 a, b, c, d, e이 됐다. 배열에 값을 추가하는 것을 푸쉬라고 한다.

arr = ['a', 'b', 'c', 'd', 'e']
arr << 'f'
puts arr

아래는 위와 같은 의미다.

arr = ['a', 'b', 'c', 'd', 'e']
arr.push('f')
puts arr

다음은 배열의 시작점에 원소를 추가하는 방법이다. 배열 arr은 z, a, b, c, d, e가 됐다.

arr = ['a', 'b', 'c', 'd', 'e']
arr.unshift('z')
puts arr

제거

다음은 배열 시작점에 있는 원소 두개를 배열 arr에서 제거한다. 결과는 c, d, e다.

arr = ['a', 'b', 'c', 'd', 'e']
arr.shift(2)
puts arr

다음은 배열 끝점의 원소 두개를 배열 arr에서 제거한다. 결과는 a, b, c다.

arr = ['a', 'b', 'c', 'd', 'e']
arr.pop(2)
puts arr

정렬

정렬을 하고 싶다면 아래와 같이 한다. 결과는 a, b, c, d, e 다.

li = ['c', 'e', 'a', 'b', 'd']
li.sort!
puts li

역순으로 정렬하고 싶다면 아래와 같이 한다. 결과는 e, d, c, b, a 다.

li = ['c', 'e', 'a', 'b', 'd']
li.sort! { |x, y| y <=> x }
puts li

hash(연관배열)

지금까지 살펴본 배열은 원소에 대한 식별자(인덱스)로 숫자를 사용했다. 데이터가 추가되면 배열 전체에서 중복되지 않는 인덱스가 자동으로 만들어져서 그 데이터에 대한 식별자가 된다. 만약 인덱스로 문자를 사용하고 싶다면 해쉬(hash)를 사용해야 한다. 다른 언어에서는 연관배열(associative array) 또는 사전(dictionary)라고 한다.

해쉬 생성

다음은 해쉬를 만드는 법이다.

grades = { 'egoing' => 10, 'k8805' => 6 , 'sorialgi' => 80}

위의 예제에서 egoing은 key가 되고, 10은 value가 된다. 아래는 해쉬를 만드는 다른 방법이다.

grades = Hash.new
grades['egoing'] = 10
grades['k8805'] = 6
grades['sorialgi'] = 80

다음은 특정한 key의 값을 가져오는 법이다. 결과는 80이다.

grades = { 'egoing' => 10, 'k8805' => 6 , 'sorialgi' => 80}
puts grades['sorialgi']

다음은 해쉬의 데이터를 기준으로 반복작업을 하는 방법이다. 반복자(iterator) each를 사용하고 있다.

grades = { 'egoing' => 10, 'k8805' => 6 , 'sorialgi' => 80}
grades.each{ |k,v| puts "Key : #{k} \t Value : #{v}" }

결과는 아래와 같다.

Key : egoing    Value : 10
Key : k8805     Value : 6
Key : sorialgi  Value : 80

해쉬의 반복자는 인자로 두개의 값을 받는다. |k, v|에는 각각의 key와 value값이 담기도록 약속되어 있다. puts 안에 \t 기호는 문자 탭(tab)을 의미한다. 일정한 간격으로 문자를 정렬하기 위해서 사용했다.

해쉬와 배열

해쉬는 인덱스가 있는 데이터를 그룹핑하기에 좋은 데이터 타입이다. 만약 색인이 중복된다면 같은 색인을 가지고 있는 이전 데이터는 새로운 데이터로 덮어쓰기 될 것이다. 따라서 해쉬에서 색인은 유일무일하게 value를 식별하는 식별자여야 한다. 식별자가 있는 데이터는 해쉬를 사용하는 것이 더 빠르고, 편리하다. 반대로 식별자가 없는 데이터는 배열을 사용한다.

참고

댓글

댓글 본문
버전 관리
egoing@gmail.com
현재 버전
선택 버전
graphittie 자세히 보기