Programming/Python

[코딩도장-파이썬] 슬라이스(Slice)

Supreme_YS 2020. 11. 11. 21:31

*shell 환경이 아닌 스크립트(script) 환경에서 작업했기 때문에 print로 출력. shell 환경이라면 print 생략 가능


._시퀀스 자료형은 슬라이스라는 기능을 자주 사용한다. 끝 인덱스는 가져오려는 범위에 포함되지 않기 때문에 끝 인덱스는 실제로 가져오려는 인덱스보다 1을 더 크게 지정해야 한다. 예를 들어 요소가 10개 들어있는 리스트를 처음부터 끝까지 가져오려면 [0:9]가 아닌 [0:10]이라야 한다(끝 인덱스는 범위를 벗어난 인덱스를 지정할 수 있다).

 

형태 : 시퀀스객체[시작인덱스:끝인덱스]

 

예.

a = [0, 10, 20, 30, 40, 50, 60, 70, 80, 90]
print(a[0:4]) # 인덱스 0부터 3까지 잘라서 새 리스트를 만듦

결과값 : [0, 10, 20, 30]

 

슬라이스 출처.코딩도장

._음수 슬라이스 

인덱스에서 -1은 뒤에서 첫 번째 요소를 뜻한다. 끝 인덱스는 가져오려는 인덱스보다 1을 더 크게 지정한다고 했으므로 실제로는 뒤에서 두 번째(인덱스 -2) 요소인 80까지만 가져온다(음수는 숫자가 작을 수록 큰 수. 그래서 -1은 -2보다 1이 더 크다.

 

예. print(a[4:-1])

결과값 : [40, 50, 60, 70, 80]

음수 슬라이스 출처. 코딩도장

._인덱스 증가폭 사용하기

슬라이스는 인덱스의 증가폭을 지정하여 범위 내에서 인덱스를 건너뛰며 요소를 가져올 수 있다. 아래는 인덱스를 3씩 증가시키면서 요소를 가져온다. 여기서 주의할 점은 인덱스의 증가폭이지 요소의 값 증가폭이 아니다.

 

형태 : 시퀀스객체[시작인덱스:끝인덱스:인덱스증가폭]

예. print(a[2:8:3]) # 인덱스 2부터 3씩 증가시키면서 인덱스 7까지 가져옴

결과값 : [20, 50]

예. print(a[2:9:3]) # 인덱스 2부터 3씩 증가시키면서 인덱스 8까지 가져옴

결과값 : [20, 50, 80]

슬라이스 증가폭 설정 출처. 코딩도장

._인덱스 생략하기

인덱스를 생략하는 방법은 시퀀스 객체의 길이를 몰라도 되기 때문에 자주 쓰이는 방식. 주로 시퀀스 객체의 마지막 일부분만 출력할 때 사용한다. 그리고 a[7:]과 같이 끝 인덱스를 생략하면 시작 인덱스(인덱스 7)부터 마지막 요소까지 가져온다.

 

예. print(a[:7]) # 리스트 처음부터 인덱스 6까지 가져옴

결과값 : [0, 10, 20, 30, 40, 50, 60]

예. print(a[7:]) # 인덱스 7부터 마지막 요소까지 가져옴

결과값 : [70, 80, 90]

인덱스 생략하기 출처. 코딩도장

._리스트 전체 가져오기, 시작 인덱스와 끝 인덱스를 둘다 생략하면 리스트 전체를 가져온다.

형태 : 리스트객체[:]

예. print(a[:])

결과값 : [0, 10, 20, 30, 40, 50, 60, 70, 80, 90]

생략을 통한 리스트 전체 값 호출 출처.코딩도장

._인덱스를 생략하면서 증가폭 사용하기

리스트 a에서 a[:7:2]와 같이 시작 인덱스를 생략하면서 인덱스 증가폭을 2로 지정하면 리스트의 처음부터 인덱스를 2씩 증가시키면서 끝 인덱스 - 1(인덱스 6)까지 요소를 가져온다.

예. print(a[:7:2]) # 리스트의 처음부터 인덱스를 2씩 증가시키면서 인덱스 6까지 가져옴

결과값 : [0, 20, 40, 60] 

예. print(a[7::2] # 인덱스 7부터 2씩 증가시키면서 리스트의 마지막 요소까지 가져옴

결과값 : [70, 90]

예. print(a[::2]) # 리스트 전체에서 인덱스 0부터 2씩 증가시키면서 요소를 가져옴

결과값 : [0, 20, 40, 60, 80]

._마찬가지로 a[::]이런식으로 다 생략하면 리스트 전체 값을 가져온다.

인덱스 생략 증가폭 사용 출처. 코딩도장

 

._인덱스 증가폭을 음수로 한다면 요소를 뒤에서부터 가져올 수 있다. 

 

예. print(a[5:1:-1]) #리스트 a에서 인덱스 5부터 2까지 1씩 감소시키면서 요소를 가져옴

결과값 : [50, 40, 30, 20]

 

주의할 점은 인덱스가 감소하므로 끝 인덱스보다 시작 인덱스를 더 크게 지정해야 한다는 점. 즉, a[5:1:-1]과 같이 시작 인덱스부터 끝 인덱스까지 감소하도록 지정. 그리고 끝 인덱스는 가져오려는 범위에 포함되지 않는다.

특히, 다음과 같이 시작 인덱스와 끝 인덱스를 생략하면서 인덱스 증가폭을 -1로 지정하면 리스트 전체에서 인덱스를 1씩 감소시키면서 요소를 가져오므로 리스트를 반대로 뒤집는다.

 

예. print(a[::-1])

결과값 : [90, 80, 70, 60, 50, 40, 30, 20, 10, 0]

 


._len 함수를 이용한 전체 리스트 가져오기
예.

print(a[0:len(a)])
print(a[:len(a)])

결과값 : [0, 10, 20, 30, 40, 50, 60, 70, 80, 90] 

len을 이용한 전체 리스트 호출 출처. 코딩도장

._tuple, range, 문자열에 슬라이스 사용하기

파이썬에서는 튜플, range, 문자열도 시퀀스 자료형이므로 리스트와 같은 방식으로 슬라이스를 사용할 수 있다.

예. b = (0, 10, 20, 30, 40, 50, 60, 70, 80, 90)
print(b[4:7]) #인덱스 4부터 6까지 요소 3개를 가져옴
print(b[4:]) #인덱스 4부터 마지막 요소까지 가져옴
print(b[:7:2] #튜플의 처음부터 인덱스를 2씩 증가시키면서 6까지 가져옴

 

결과값 :

(40, 50, 60)
(40, 50, 60, 70, 80, 90)
(0, 20, 40, 60)

튜플 인덱스 출처. 코딩도장

._range는 연속된 숫자를 생성한다. 따라서 range에 슬라이스를 사용하면 지정된 범위의 숫자를 생성하는 range 객체를 새로 만든다. 

예. r = range(10)
range(0, 10)
print(r[4:7])     # 인덱스 4부터 6까지 숫자 3개를 생성하는 range 객체를 만듦
range(4, 7)
print(r[4:])      # 인덱스 4부터 9까지 숫자 6개를 생성하는 range 객체를 만듦
range(4, 10)
print(r[:7:2])    # 인덱스 0부터 2씩 증가시키면서 인덱스 6까지 숫자 4개를 생성하는 range 객체를 만듦
range(0, 7, 2)

 

만일 위처럼 코딩을 하면 출력될 때는 생성 범위가 출력이 된다. 따라서 위처럼 잘라낸 range객체들을 리스트로 만들려면 list에 넣어줘야 한다.

예.

print(list(range(0, 10)))
print(list(r[4:7])) 
print(list(range(4, 7)))
print(list(r[4:]))     
print(list(range(4, 10)))
print(list(r[:7:2]))    
print(list(range(0, 7, 2)))

range 인덱스 슬라이스 출처. 코딩도장

._문자열은 특히 문자 하나가 요소이므로 문자 단위로 잘라서 새 문자열을 만든다.

예.

hello = 'Hello, world!'
print(hello[2:9])    # 인덱스 2부터 인덱스 8까지 잘라서 문자열을 만듦
print(hello[2:])     # 인덱스 2부터 마지막 요소까지 잘라서 문자열을 만듦
print(hello[:9:2])   # 문자열의 처음부터 인덱스를 2씩 증가시키면서 인덱스 8까지 잘라서 문자열을 만듦

 

결과값.

llo, wo
llo, world!
Hlo o

문자열 슬라이싱 출처.코딩도장

._slice 객체 사용하기

슬라이스객체 = slice(끝인덱스)

슬라이스객체 = slice(시작인덱스, 끝인덱스)

슬라이스객체 = slice(시작인덱스, 끝인덱스, 인덱스증가폭)

시퀀스객체[슬라이스객체]

시퀀스객체.__getitem__(슬라이스객체)

예.

range(10)[slice(4, 7, 2)]                  --> range(4, 7, 2) 출력
range(10).__getitem__(slice(4, 7, 2))  --> range(4, 7, 2) 출력

 

#slice 객체를 하나만 만든 뒤 여러 시퀀스에 적용하기
s = slice(4, 7) # 인덱스 4부터 6까지 자르는 slice 객체 생성
print(a[s])
r = range(10)
print(list(r[s])) #r은 위에서 range로 정의했기 때문에 list에 삽입을 해줘야 범위 출력이 아닌 값이 출력

 

결과값.

[40, 50, 60]
[4, 5, 6]
o, 

 

._slice 요소 할당

예. a = [0, 10, 20, 30, 40, 50, 60, 70, 80, 90]
a[2:5] = ['a','b','c'] #인덱스 2부터 4까지 값 할당
print(a)

결과값 : [0, 10, 'a', 'b', 'c', 50, 60, 70, 80, 90]

이렇게 하면 인덱스 2부터 4까지 문자 'a', 'b', 'c'가 들어간다. 특히 이렇게 범위를 지정해서 요소를 할당했을 경우에는 원래 있던 리스트가 변경되며 새 리스트는 생성되지 않는다.

slice assignment 출처. 코딩도장

위처럼 요소 갯수를 정확히 맞췄지만 사실 갯수를 맞추지 않아도 된다. 알아서 할당되기 때문이다. 할당할 요소 갯수가 적으면 그만큼 리스트의 요소 개수도 줄어든다. 반면 할당할 요소 개수가 많으면 그만큼 리스트의 요소 개수도 늘어난다. 

예. a = [0, 10, 20, 30, 40, 50, 60, 70, 80, 90]  

a[2:5] = ['a']    # 인덱스 2부터 4까지에 값 1개를 할당하여 요소의 개수가 줄어듦
print(a)

결과값 : [0, 10, 'a', 50, 60, 70, 80, 90]

 

a = [0, 10, 20, 30, 40, 50, 60, 70, 80, 90]
a[2:5] = ['a', 'b', 'c', 'd', 'e'] #인덱스 2부터 4까지 값 5개를 할당하여 요소 개수가 늘어남
print(a)

 

slice assignment2 갯수가 적을때와 많을 때 출처. 코딩도장

._인덱스 증가폭을 이용한 슬라이스 단, 인덱스 증가폭을 지정했을 때는 슬라이스 범위의 요소 개수와 할당할 요소 개수가 정확히 일치해야 한다. 또한, 튜플, range, 문자열은 슬라이스 범위를 지정하더라도 요소를 할당할 수 없다. (읽기 전용이니깐 >_<)

예. a = [0, 10, 20, 30, 40, 50, 60, 70, 80, 90]
a[2:8:2] = ['a', 'b', 'c']    # 인덱스 2부터 2씩 증가시키면서 인덱스 7까지 값 할당
print(a)

결과값 : [0, 10, 'a', 30, 'b', 50, 'c', 70, 80, 90]

증가폭 인덱스를 이용한 슬라이싱 및 할당 출처. 코딩도장

._del을 이용한 슬라이스 삭제

예. a = [0, 10, 20, 30, 40, 50, 60, 70, 80, 90]
del a[2:5]    # 인덱스 2부터 4까지 요소를 삭제
print(a)

결과값 : [0, 10, 50, 60, 70, 80, 90]

슬라이스 삭제 출처. 코딩도장

._증가폭을 활용한 슬라이스 삭제 물론 튜플, range, 문자열은 del로 슬라이스를 삭제할 수 없다. (읽기 전용 ^_^)
예. a = [0, 10, 20, 30, 40, 50, 60, 70, 80, 90]
del a[2:8:2]    # 인덱스 2부터 2씩 증가시키면서 인덱스 6까지 삭제
print(a)

결과값 : [0, 10, 30, 50, 70, 80, 90]

증가폭을 이용한 슬라이스 삭제 출처. 코딩도장

무엇보다 시퀀스 자료형의 인덱스가 0부터 시작한다는 점이 가장 중요하다.