어제 오늘 내일

[Python] "중복 데이터, 대체 어디 숨어있어?" 파이썬 리스트 중복 인덱스(위치) 찾기 완벽 가이드 본문

IT/Python

[Python] "중복 데이터, 대체 어디 숨어있어?" 파이썬 리스트 중복 인덱스(위치) 찾기 완벽 가이드

hi.anna 2026. 5. 12. 22:55

파이썬 리스트에서 특정 데이터의 위치를 찾을 때, 초보자분들이 가장 많이 하는 실수가 바로 .index() 함수를 사용하는 것입니다.

my_list.index("사과")를 쓰면 위치를 알려주긴 하지만, 치명적인 단점이 있습니다. 바로 "가장 먼저 발견된 '사과'의 위치 딱 하나만 알려주고 검색을 멈춰버린다"는 것입니다.

뒤에 숨어있는 두 번째, 세 번째 '사과'의 위치까지 싹 다 찾아내려면 어떻게 해야 할까요? 상황에 맞는 2가지 확실한 해결책을 소개합니다.


1. 특정 타겟 데이터의 모든 위치 찾기 ( 활용)

"이 리스트에서 '사과'가 도대체 몇 번, 몇 번 방에 들어있어?"
이렇게 내가 찾고 싶은 특정 타겟이 정해져 있을 때 가장 직관적이고 '파이썬스러운' 방법입니다.

이전에 반복문 단원에서 배웠던 enumerate() (인덱스 번호와 데이터를 같이 뽑아주는 마법의 함수)와 리스트 컴프리헨션을 결합합니다.

📌 예제 코드: 특정 값의 모든 인덱스 찾기

fruits = ["사과", "바나나", "사과", "포도", "사과", "귤"]
target = "사과"

# 1. 일반 for문으로 찾기 (이해하기 쉬운 버전)
target_indices = []
for i, fruit in enumerate(fruits):
    if fruit == target:
        target_indices.append(i)

print(f"일반 for문 결과 - '{target}'의 위치: {target_indices}")


# 2. 리스트 컴프리헨션으로 찾기 (실무용 한 줄 컷!)
# "fruits에서 인덱스(i)와 과일(x)을 꺼내는데, 과일이 '사과'일 때만 그 인덱스(i)를 리스트에 담아라!"
target_indices_short = [i for i, x in enumerate(fruits) if x == target]

print(f"한 줄 컷 결과 - '{target}'의 위치: {target_indices_short}")
# 출력: [0, 2, 4] (사과는 0번, 2번, 4번 방에 있습니다!)

이 한 줄짜리 코드는 실무에서 특정 조건에 맞는 데이터의 위치를 뽑아낼 때 숨 쉬듯이 사용됩니다.


2. 리스트 전체 데이터의 중복 위치 그룹화하기 (딕셔너리 활용)

이번엔 상황이 다릅니다. "사과만 찾는 게 아니라, 이 리스트에 있는 모든 데이터가 각각 몇 번 방에 있는지 싹 다 정리해 줘!" 라는 요구사항이 들어왔습니다.
이때는 데이터의 이름을 이름표(Key)로, 위치(Index)들을 바구니(Value 리스트)에 담아주는 딕셔너리(Dictionary)를 활용하는 것이 정석입니다.

📌 예제 코드: 모든 데이터의 인덱스 맵(Map) 만들기

# 출석체크 명단 (중복 발생)
attendance = ["철수", "영희", "민수", "철수", "지훈", "영희", "철수"]

# 데이터를 정리할 빈 딕셔너리를 만듭니다.
index_map = {}

for i, name in enumerate(attendance):
    # 만약 딕셔너리에 처음 등장하는 이름이라면, 빈 리스트를 먼저 만들어줍니다.
    if name not in index_map:
        index_map[name] = []

    # 해당 이름표(Key)의 리스트(Value)에 현재 인덱스(i)를 추가합니다.
    index_map[name].append(i)

print("▼ 전체 데이터 인덱스 정리 결과 ▼")
for name, indices in index_map.items():
    print(f"{name}: {indices}")

실행 결과:

▼ 전체 데이터 인덱스 정리 결과 ▼
철수: [0, 3, 6]
영희: [1, 5]
민수: [2]
지훈: [4]

어떤가요? 철수가 0, 3, 6번째 줄에 있고, 민수는 2번째 줄에 딱 한 번 있다는 것이 완벽하게 정리되었습니다!


3. 심화: 중복이 발생한(2번 이상 등장한) 데이터만 뽑아내기

위에서 만든 index_map 딕셔너리를 조금만 응용하면, "1번만 나온 정상 데이터는 빼고, 2번 이상 중복해서 나온 문제의 데이터들만 인덱스를 보여줘!"라는 것도 아주 쉽게 구현할 수 있습니다.

📌 예제 코드: 중복된 항목만 필터링하기

# (위의 index_map 딕셔너리가 만들어져 있다고 가정합니다)

print("▼ 중복 발생 데이터 및 위치 ▼")

# 딕셔너리에서 이름과 위치리스트를 하나씩 꺼내봅니다.
for name, indices in index_map.items():
    # 리스트의 길이(len)가 1보다 크다 = 2번 이상 등장했다 = 중복이다!
    if len(indices) > 1:
        print(f"경고! '{name}' 데이터가 다음 위치에서 중복 발견됨: {indices}")

실행 결과:

▼ 중복 발생 데이터 및 위치 ▼
경고! '철수' 데이터가 다음 위치에서 중복 발견됨: [0, 3, 6]
경고! '영희' 데이터가 다음 위치에서 중복 발견됨: [1, 5]

💡 보너스: 로 코드 더 줄이기

2번 예제에서 "딕셔너리에 Key가 없으면 빈 리스트를 만든다(if name not in index_map:)"는 코드를 적었죠?
파이썬의 내장 모듈인 collections.defaultdict를 쓰면 이 귀찮은 확인 과정을 파이썬이 알아서 대신해 줍니다. (실무 고수들이 정말 좋아하는 모듈입니다.)

from collections import defaultdict

attendance = ["철수", "영희", "민수", "철수"]

# "Key가 없으면 알아서 빈 리스트(list)를 기본값으로 세팅해 주는 딕셔너리를 만들게!"
index_map = defaultdict(list)

for i, name in enumerate(attendance):
    # Key가 있는지 없는지 검사할 필요 없이, 무지성으로 append만 하면 됩니다!
    index_map[name].append(i)

print(dict(index_map))
# 출력: {'철수': [0, 3], '영희': [1], '민수': [2]}

📝 마치며

핵심만 다시 정리해 볼까요?

  1. .index()의 배신: 가장 먼저 찾은 위치 1개만 반환하므로 중복 찾기에는 쓸 수 없다.
  2. 특정 값 1개만 찾을 때: [i for i, x in enumerate(리스트) if x == 타겟] (원샷원킬 리스트 컴프리헨션)
  3. 전체 데이터의 위치를 정리할 때: 딕셔너리(또는 defaultdict)에 이름: [인덱스들] 형태로 모아준다.

이 방법들을 숙지하고 계시면, 수만 줄짜리 엑셀이나 CSV 파일을 파이썬으로 불러왔을 때 불량(중복) 데이터가 몇 번째 줄에 숨어있는지 1초 만에 색출해 내실 수 있습니다!
 

반응형
Comments