파이썬 교육 챕터 25 리스트 조작하기

리스트(List) 조작하기: 데이터를 자유자재로 추가, 삭제, 수정

1. 서론: 살아있는 데이터 컬렉션, 리스트의 유연성

이전 챕터에서 우리는 파이썬 리스트의 기본적인 개념과 생성 방법, 그리고 인덱싱을 통해 리스트의 요소에 접근하는 방법을 배웠습니다. 리스트의 가장 큰 특징 중 하나는 ‘변경 가능(Mutable)’하다는 점입니다. 이는 리스트가 한 번 생성된 후에도 그 안에 담긴 데이터를 자유롭게 추가하고, 삭제하며, 수정할 수 있다는 의미입니다. 이러한 유연성 덕분에 리스트는 프로그램 실행 중에 동적으로 변화하는 데이터를 관리하는 데 매우 강력한 도구가 됩니다. 예를 들어, 쇼핑 카트에 상품을 추가하거나(추가), 품절된 상품을 제거하거나(삭제), 상품의 수량을 변경하는(수정) 등의 작업은 모두 리스트 조작을 통해 이루어집니다. 이 챕터에서는 파이썬 리스트의 요소를 추가, 삭제, 수정하는 다양한 메서드와 기법에 대해 깊이 있게 알아보겠습니다. 리스트 조작 기술을 마스터하는 것은 여러분의 파이썬 프로그래밍 능력을 한 단계 더 발전시키고, 실제 데이터를 효율적으로 관리할 수 있는 실질적인 역량을 길러줄 것입니다.

2. 리스트에 요소 추가하기

리스트에 새로운 요소를 추가하는 방법은 여러 가지가 있습니다.

2.1. append(): 리스트의 끝에 요소 추가

append() 메서드는 리스트의 가장 마지막에 새로운 요소를 추가합니다.

fruits = ["apple", "banana"]
print(f"원본 리스트: {fruits}") # 출력: 원본 리스트: ['apple', 'banana']

fruits.append("cherry")
print(f"append 후: {fruits}") # 출력: append 후: ['apple', 'banana', 'cherry']

fruits.append("date")
print(f"append 후: {fruits}") # 출력: append 후: ['apple', 'banana', 'cherry', 'date']

2.2. insert(): 특정 위치에 요소 삽입

insert(index, element) 메서드는 리스트의 특정 index 위치에 element를 삽입합니다. 기존 요소들은 뒤로 밀려납니다.

fruits = ["apple", "banana", "cherry"]
print(f"원본 리스트: {fruits}") # 출력: 원본 리스트: ['apple', 'banana', 'cherry']

fruits.insert(1, "grape") # 인덱스 1 위치에 'grape' 삽입
print(f"insert 후: {fruits}") # 출력: insert 후: ['apple', 'grape', 'banana', 'cherry']

fruits.insert(0, "kiwi") # 맨 앞에 삽입
print(f"insert 후: {fruits}") # 출력: insert 후: ['kiwi', 'apple', 'grape', 'banana', 'cherry']

fruits.insert(len(fruits), "mango") # 맨 뒤에 삽입 (append와 동일한 효과)
print(f"insert 후: {fruits}") # 출력: insert 후: ['kiwi', 'apple', 'grape', 'banana', 'cherry', 'mango']

2.3. extend(): 다른 리스트(또는 반복 가능한 객체)의 요소들을 추가

extend() 메서드는 다른 리스트나 튜플 등 반복 가능한 객체의 모든 요소들을 현재 리스트의 끝에 추가합니다.

list1 = [1, 2, 3]
list2 = [4, 5]
print(f"원본 list1: {list1}") # 출력: 원본 list1: [1, 2, 3]

list1.extend(list2)
print(f"extend 후: {list1}") # 출력: extend 후: [1, 2, 3, 4, 5]

list1.extend(("a", "b")) # 튜플 추가
print(f"extend 후: {list1}") # 출력: extend 후: [1, 2, 3, 4, 5, 'a', 'b']

# + 연산자를 이용한 리스트 연결도 가능합니다. (새로운 리스트 생성)
list_a = [1, 2]
list_b = [3, 4]
list_c = list_a + list_b
print(f"+ 연산자 사용: {list_c}") # 출력: + 연산자 사용: [1, 2, 3, 4]

3. 리스트에서 요소 삭제하기

리스트에서 요소를 삭제하는 방법도 다양합니다.

3.1. remove(): 특정 값의 요소 삭제

remove(value) 메서드는 리스트에서 value와 일치하는 첫 번째 요소를 삭제합니다. 만약 해당 값이 리스트에 없으면 ValueError가 발생합니다.

fruits = ["apple", "banana", "cherry", "banana"]
print(f"원본 리스트: {fruits}") # 출력: 원본 리스트: ['apple', 'banana', 'cherry', 'banana']

fruits.remove("banana") # 첫 번째 'banana' 삭제
print(f"remove 후: {fruits}") # 출력: remove 후: ['apple', 'cherry', 'banana']

# fruits.remove("grape") # ValueError: list.remove(x): x not in list

3.2. pop(): 특정 인덱스의 요소 삭제 및 반환

pop(index) 메서드는 리스트의 특정 index 위치에 있는 요소를 삭제하고, 그 요소를 반환합니다. 인덱스를 지정하지 않으면 리스트의 마지막 요소를 삭제하고 반환합니다.

fruits = ["apple", "banana", "cherry"]
print(f"원본 리스트: {fruits}") # 출력: 원본 리스트: ['apple', 'banana', 'cherry']

removed_fruit = fruits.pop(1) # 인덱스 1의 요소 삭제 및 반환
print(f"pop 후: {fruits}, 삭제된 요소: {removed_fruit}")
# 출력: pop 후: ['apple', 'cherry'], 삭제된 요소: banana

last_fruit = fruits.pop() # 마지막 요소 삭제 및 반환
print(f"pop 후: {fruits}, 삭제된 요소: {last_fruit}")
# 출력: pop 후: ['apple'], 삭제된 요소: cherry

# 빈 리스트에서 pop() 호출 시 IndexError 발생
# empty_list = []
# empty_list.pop() # IndexError: pop from empty list

3.3. del 키워드: 특정 인덱스 또는 슬라이스 삭제

del 키워드는 리스트의 특정 인덱스에 있는 요소를 삭제하거나, 슬라이싱을 사용하여 여러 요소를 한 번에 삭제할 수 있습니다.

my_list = [10, 20, 30, 40, 50]
print(f"원본 리스트: {my_list}") # 출력: 원본 리스트: [10, 20, 30, 40, 50]

del my_list[1] # 인덱스 1의 요소 (20) 삭제
print(f"del 후: {my_list}") # 출력: del 후: [10, 30, 40, 50]

del my_list[1:3] # 인덱스 1부터 2까지 (30, 40) 삭제
print(f"del 슬라이싱 후: {my_list}") # 출력: del 슬라이싱 후: [10, 50]

# 리스트 전체 삭제
# del my_list[:] # 리스트의 모든 요소 삭제 (리스트는 남아있음)
# del my_list # 리스트 변수 자체를 삭제

3.4. clear(): 리스트의 모든 요소 삭제

clear() 메서드는 리스트의 모든 요소를 삭제하여 빈 리스트로 만듭니다. 리스트 객체 자체는 남아있습니다.

my_list = [1, 2, 3, 4, 5]
print(f"원본 리스트: {my_list}") # 출력: 원본 리스트: [1, 2, 3, 4, 5]

my_list.clear()
print(f"clear 후: {my_list}") # 출력: clear 후: []

4. 리스트 요소 수정하기

리스트는 변경 가능한 자료형이므로, 인덱스를 사용하여 특정 요소의 값을 직접 수정할 수 있습니다.

4.1. 인덱스를 이용한 단일 요소 수정

fruits = ["apple", "banana", "cherry"]
print(f"원본 리스트: {fruits}") # 출력: 원본 리스트: ['apple', 'banana', 'cherry']

fruits[1] = "grape" # 인덱스 1의 요소를 'grape'로 변경
print(f"수정 후: {fruits}") # 출력: 수정 후: ['apple', 'grape', 'cherry']

4.2. 슬라이싱을 이용한 여러 요소 수정/교체

슬라이싱을 사용하여 리스트의 특정 범위에 있는 여러 요소를 한 번에 수정하거나 다른 요소들로 교체할 수 있습니다.

numbers = [10, 20, 30, 40, 50]
print(f"원본 리스트: {numbers}") # 출력: 원본 리스트: [10, 20, 30, 40, 50]

numbers[1:3] = [25, 35] # 인덱스 1부터 2까지의 요소를 [25, 35]로 교체
print(f"슬라이싱 수정 후: {numbers}") # 출력: 슬라이싱 수정 후: [10, 25, 35, 40, 50]

numbers[1:4] = ["a", "b", "c", "d"] # 교체되는 요소의 개수가 달라도 됩니다.
print(f"슬라이싱 교체 후: {numbers}") # 출력: 슬라이싱 교체 후: [10, 'a', 'b', 'c', 'd', 50]

numbers[1:3] = [] # 슬라이싱을 이용한 요소 삭제
print(f"슬라이싱 삭제 후: {numbers}") # 출력: 슬라이싱 삭제 후: [10, 'c', 'd', 50]

5. 리스트 정렬 및 뒤집기

5.1. sort(): 리스트 자체를 정렬

sort() 메서드는 리스트의 요소들을 제자리에서(in-place) 정렬합니다. 원본 리스트가 변경됩니다.

numbers = [3, 1, 4, 1, 5, 9, 2, 6]
numbers.sort() # 오름차순 정렬 (기본값)
print(f"sort() 후 (오름차순): {numbers}") # 출력: sort() 후 (오름차순): [1, 1, 2, 3, 4, 5, 6, 9]

numbers.sort(reverse=True) # 내림차순 정렬
print(f"sort() 후 (내림차순): {numbers}") # 출력: sort() 후 (내림차순): [9, 6, 5, 4, 3, 2, 1, 1]

words = ["banana", "apple", "cherry"]
words.sort()
print(f"sort() 후 (문자열): {words}") # 출력: sort() 후 (문자열): ['apple', 'banana', 'cherry']

5.2. sorted(): 정렬된 새로운 리스트 반환

sorted() 함수는 원본 리스트를 변경하지 않고, 정렬된 새로운 리스트를 반환합니다.

original_numbers = [3, 1, 4, 1, 5, 9, 2, 6]
sorted_numbers = sorted(original_numbers) # 오름차순 정렬
print(f"원본 리스트: {original_numbers}") # 출력: 원본 리스트: [3, 1, 4, 1, 5, 9, 2, 6]
print(f"sorted() 후: {sorted_numbers}") # 출력: sorted() 후: [1, 1, 2, 3, 4, 5, 6, 9]

reversed_sorted_numbers = sorted(original_numbers, reverse=True) # 내림차순 정렬
print(f"sorted() 내림차순 후: {reversed_sorted_numbers}") # 출력: sorted() 내림차순 후: [9, 6, 5, 4, 3, 2, 1, 1]

5.3. reverse(): 리스트의 순서를 뒤집기

reverse() 메서드는 리스트의 요소 순서를 제자리에서(in-place) 뒤집습니다. 정렬하는 것이 아니라 단순히 순서를 역순으로 바꿉니다.

my_list = [1, 2, 3, 4, 5]
my_list.reverse()
print(f"reverse() 후: {my_list}") # 출력: reverse() 후: [5, 4, 3, 2, 1]

6. 결론: 동적인 데이터 관리를 위한 리스트 조작

이 챕터를 통해 여러분은 파이썬 리스트의 요소를 추가, 삭제, 수정하는 다양한 메서드와 기법에 대해 깊이 있게 학습했습니다. append(), insert(), extend()를 이용한 요소 추가, remove(), pop(), del, clear()를 이용한 요소 삭제, 그리고 인덱싱과 슬라이싱을 이용한 요소 수정까지, 리스트를 자유자재로 다루는 방법을 익혔습니다. 또한, sort(), sorted(), reverse()를 통해 리스트를 정렬하거나 순서를 뒤집는 방법도 살펴보았습니다.

리스트는 파이썬에서 가장 강력하고 유연하게 사용되는 자료 구조이며, 이들을 조작하는 능력은 동적으로 변화하는 데이터를 효율적으로 관리하는 데 필수적입니다. 사용자로부터 데이터를 입력받아 리스트에 추가하거나, 특정 조건을 만족하는 데이터를 리스트에서 제거하거나, 기존 데이터를 업데이트하는 등 실제 프로그래밍에서 리스트 조작은 빈번하게 사용됩니다.

이제 여러분은 파이썬의 핵심 자료 구조인 리스트를 생성하고, 요소에 접근하며, 자유자재로 조작할 수 있는 능력을 갖추게 되었습니다. 다음 챕터에서는 리스트의 특정 부분을 잘라내어 새로운 리스트를 만드는 ‘리스트 슬라이싱’과 ‘인덱싱’에 대해 더 깊이 있게 탐구할 것입니다. 오늘 배운 리스트 조작 메서드들을 활용하여 다양한 데이터를 직접 추가, 삭제, 수정해 보면서, 여러분의 파이썬 실력을 더욱 단단하게 다지세요!

파이썬 교육 챕터 25 리스트 조작하기