리스트

PJPJ·2026년 2월 21일

Coding_Test

목록 보기
3/8

함수에서 리스트 호출

  1. 얕은 복사 (Slicing) - 가장 간단하고 추천하는 방법
    리스트 전체를 [:]를 이용해 자르는 방식입니다. 이렇게 하면 새로운 리스트 객체가 생성되어 전달되므로, 함수 내에서 수정해도 원본에는 영향이 없습니다.
def my_function(some_list):
    some_list[0] = 999  # 복사본을 수정하므로 원본은 안전함

original_list = [1, 2, 3]

# 함수 호출 시 [:] 를 붙여서 복사본을 전달
my_function(original_list[:]) 

print(original_list)  # 출력: [1, 2, 3] (변경되지 않음)
  1. 함수 내부에서 copy() 메서드 사용
    함수를 호출하는 쪽이 아니라, 함수를 작성하는 쪽에서 안전하게 처리하고 싶다면 함수 내부에서 .copy()를 사용합니다.
def my_function(data):
    # 함수 안에서 복사본을 만들어 사용 (new_data는 별개의 리스트)
    new_data = data.copy()
    new_data.append(4)
    return new_data

original = [1, 2, 3]
my_function(original)
print(original)  # 출력: [1, 2, 3]
  1. deepcopy() (깊은 복사) - 중첩 리스트일 때 필수
    만약 리스트 안에 또 다른 리스트가 들어있는 2차원 리스트(중첩 리스트)라면, 위의 방법들로는 부족합니다. 내부의 리스트까지 완벽하게 분리하려면 copy 모듈의 deepcopy를 써야 합니다.
python
import copy

def my_function(data):
    # 내부의 리스트까지 싹 다 새로 복사
    new_data = copy.deepcopy(data)
    new_data[0][0] = 999
    
original = [[1, 2], [3, 4]]
my_function(original)

print(original) # 출력: [[1, 2], [3, 4]] (깊은 복사 덕분에 안전)

정렬

1. sort(): 원본 자체를 수정

  • 리스트 객체에서만 사용할 수 있는 메서드입니다. 원본 리스트의 순서를 직접 바꾸기 때문에, 실행 후에는 원본 데이터가 영구적으로 변합니다.
  • 반환값이 None이므로, new_list = my_list.sort()처럼 변수에 할당하면 안 됩니다. (변수에 None이 저장됨).
  • 원본을 보존할 필요가 없고 메모리를 아끼고 싶을 때 유용합니다.
data = [3, 1, 2]
data.sort()          # 원본 data가 [1, 2, 3]으로 바뀜
print(data)          # [1, 2, 3]

2. sorted(): 새로운 정렬 리스트 생성

  • 파이썬의 모든 반복 가능한 객체(리스트, 튜플, 문자열 등)에 사용할 수 있는 함수입니다. 원본은 그대로 두고, 정렬된 새로운 리스트를 반환합니다.
  • 원본 데이터를 유지해야 할 때 사용합니다.
  • 새로운 리스트를 생성하므로 sort()보다 메모리를 더 사용합니다.
data = [3, 1, 2]
new_data = sorted(data)  # 정렬된 새 리스트 [1, 2, 3] 반환
print(data)              # 원본 유지: [3, 1, 2]
print(new_data)          # 새 리스트: [1, 2, 3]

결론적으로, 원본 리스트를 망가뜨려도 된다면 sort()를, 원본을 보존하고 싶거나 리스트 외의 자료형을 정렬해야 한다면 sorted()를 사용.

3. 내림차순 정렬 (reverse=True)

  • 기본값은 오름차순(작은 것 →\rightarrow 큰 것)입니다. reverse=True 옵션을 주면 내림차순(큰 것 →\rightarrow 작은 것)으로 정렬됩니다.
data = [1, 5, 3]

# sort() 사용 (원본 변경)
data.sort(reverse=True)  
print(data)  # [5, 3, 1]

# sorted() 사용 (새 리스트 반환)
new_data = sorted([1, 5, 3], reverse=True)
print(new_data)  # [5, 3, 1]

4. 복합 조건 (key와 reverse 함께 사용)

  • "절대값이 큰 순서대로" 정렬하는 것처럼 두 옵션을 같이 쓸 수 있습니다.
nums = [-5, 2, -10, 3]

# 절대값(abs)을 기준으로 내림차순(reverse=True) 정렬
nums.sort(key=abs, reverse=True)
print(nums)  # [-10, -5, 3, 2] (절대값이 10, 5, 3, 2 순서)

5. 특정 기준(key)을 이용한 정렬

  • 단순히 값의 크기가 아니라, 내가 원하는 기준(함수)을 적용해 정렬하고 싶을 때 key 매개변수를 사용합니다. key에는 함수를 전달해야 합니다.

  • 예제 A: 길이(len) 순으로 정렬하기

  • 문자열 리스트를 알파벳 순서가 아닌, 단어의 길이 순서대로 정렬할 때 유용합니다.

words = ['apple', 'b', 'banana']
words.sort(key=len)  
print(words)  # ['b', 'apple', 'banana'] (길이가 짧은 순)
  • 예제 B: 람다(Lambda) 함수 활용 (튜플 정렬)
  • 리스트 안에 튜플이나 딕셔너리가 있을 때, 특정 요소를 기준으로 정렬하려면 lambda 함수를 많이 사용합니다.
# (이름, 점수) 튜플 리스트
scores = [('철수', 50), ('영희', 80), ('민수', 30)]

# 점수(x[1])를 기준으로 오름차순 정렬
sorted_scores = sorted(scores, key=lambda x: x[1])
print(sorted_scores)  # [('민수', 30), ('철수', 50), ('영희', 80)]

5-1. 기본: 특정 요소 기준 정렬

  • 리스트 안의 원소가 튜플이나 리스트일 때, 특정 위치의 값을 기준으로 정렬합니다.
data = [("A", 30), ("B", 10), ("C", 20)]

# 1번 인덱스(숫자)를 기준으로 정렬
data.sort(key=lambda x: x[1])  
# 결과: [('B', 10), ('C', 20), ('A', 30)]

5-2. 값 변형 정렬 (길이, 절대값 등)

  • 원소의 값을 그대로 쓰지 않고, 변형된 값을 기준으로 삼습니다.

    	길이순: len(x)
    
    	절대값: abs(x)
    
    	나머지: x % n
words = ["apple", "b", "car"]

# 길이(len) 순서대로 정렬
words.sort(key=lambda x: len(x))
# 결과: ['b', 'car', 'apple']

5-3. 다중 조건 정렬 (튜플 반환) ⭐

  • 가장 강력한 기능입니다. (1순위, 2순위, 3순위) 형태의 튜플을 반환하면 순서대로 우선순위를 가집니다.
# (이름, 점수)
students = [("A", 50), ("B", 80), ("C", 50)]

# 1순위: 점수, 2순위: 이름
students.sort(key=lambda x: (x[1], x[0]))
# 결과: [('A', 50), ('C', 50), ('B', 80)] ('A'와 'C'는 점수가 같아 이름순 정렬됨)

5-4. 오름차순/내림차순 혼합 (- 부호 활용)

  • 여러 기준이 있을 때 하나는 오름차순, 하나는 내림차순으로 하고 싶다면 숫자에 마이너스(-)를 붙여 반대로 정렬합니다.

  • 문자열에는 마이너스를 붙일 수 없으므로 주의하세요.

# (이름, 점수)
students = [("A", 50), ("B", 80), ("C", 50)]

# 점수는 내림차순(높은 순), 이름은 오름차순(가나다 순)
# -x[1]: 점수에 -를 붙이면 큰 수가 작아지므로 내림차순 효과가 남
students.sort(key=lambda x: (-x[1], x[0]))
# 결과: [('B', 80), ('A', 50), ('C', 50)]

5-5. 딕셔너리 리스트 정렬

  • JSON 데이터를 다룰 때 필수적인 패턴입니다. 딕셔너리의 특정 key 값을 기준으로 정렬합니다.
users = [
    {"name": "철수", "age": 20},
    {"name": "영희", "age": 15},
    {"name": "민수", "age": 20}
]

# 나이(age) 순으로 정렬
users.sort(key=lambda x: x["age"])

5-6. 조건부 정렬 (Boolean 활용)

  • 특정 조건을 만족하는 것만 앞으로(또는 뒤로) 보내고 싶을 때 사용합니다. False는 0, True는 1로 취급됩니다.
nums = [1, 2, 3, 4, 5]

# 짝수를 먼저 오게 하고 싶을 때 (나머지가 0인 것이 앞)
# x % 2 결과: 짝수(0), 홀수(1) -> 0이 1보다 작으므로 짝수가 먼저 옴
nums.sort(key=lambda x: x % 2)
# 결과: [2, 4, 1, 3, 5]

a 리스트가 끝날 때까지 b 리스트를 무한 반복해서 비교

방법 1: itertools.cycle과 zip 사용

cycle(b)는 b 리스트를 무한히 반복하는 반복자(iterator)를 만듭니다. 이걸 zip으로 a와 묶으면, a의 길이에 맞춰서 b가 자동으로 반복되다가 a가 끝나면 멈춥니다. speedy-hand.tistory

from itertools import cycle

a = [1, 2, 3, 4, 5]
b = [1, 2, 3]

# b를 무한 반복시키고(cycle), a의 길이만큼만 짝지음(zip)
count = 0
for val_a, val_b in zip(a, cycle(b)):
    if val_a == val_b:
        count += 1

print(count)  # 3

방법 2: 나머지 연산(%) 사용 (라이브러리 없이)

인덱스를 사용하여 직접 구현할 수도 있습니다. b의 인덱스를 i % len(b)로 계산하면 b의 길이를 넘어가도 다시 0부터 시작하게 됩니다. hcr3066.tistory

a = [1, 2, 3, 4, 5]
b = [1, 2, 3]

count = 0
for i in range(len(a)):
    # a[i]와 b[i % len(b)]를 비교
    if a[i] == b[i % len(b)]:
        count += 1

print(count)  # 3

Tip

  • box[-4:] == [1,2,3,1] 리스트끼리 바로 비교 가능
  • del box[-4:] 리스트 삭제

0개의 댓글