| 일 | 월 | 화 | 수 | 목 | 금 | 토 |
|---|---|---|---|---|---|---|
| 1 | 2 | 3 | 4 | 5 | ||
| 6 | 7 | 8 | 9 | 10 | 11 | 12 |
| 13 | 14 | 15 | 16 | 17 | 18 | 19 |
| 20 | 21 | 22 | 23 | 24 | 25 | 26 |
| 27 | 28 | 29 | 30 |
- junit5
- HashMap
- input
- 자바문법
- 스프링부트
- 단위테스트
- Eclipse
- 문자열
- list
- IntelliJ
- Array
- 배열
- java테스트
- 인텔리제이
- junit
- 자바스크립트
- 정규식
- vscode
- CSS
- 테스트자동화
- Java
- 자바
- Visual Studio Code
- string
- javascript
- js
- ArrayList
- math
- html
- SpringBoot
- Today
- Total
어제 오늘 내일
[Python] "리스트 안의 리스트?" 2차원 리스트 중복 제거 본문
1차원 리스트의 중복을 제거할 때는 마법의 주머니 set()을 쓰면 아주 쉽게 해결되었습니다.
하지만 실무에서 엑셀 데이터나 표 형태의 데이터를 다루다 보면 리스트 안에 또 리스트가 들어있는 '2차원 리스트'를 만나게 됩니다.
여기에 평소 하던 대로 set()을 씌우면 파이썬은 TypeError: unhashable type: 'list'라는 무시무시한 에러를 뿜어냅니다. 오늘은 이 에러가 왜 발생하는지 알아보고, 2차원 리스트의 중복을 3가지 방법으로 완벽하게 날려버리는 비법을 전수해 드립니다.
1. 왜 그냥 set()을 쓰면 에러가 날까요?
파이썬의 집합(set)이나 딕셔너리의 이름표(Key)에는 아주 엄격한 규칙이 하나 있습니다. 바로 "내용물이 중간에 바뀔 위험이 있는 데이터(Mutable)는 절대 들어올 수 없다"는 것입니다.
우리가 아는 리스트([])는 .append()로 값을 추가하거나 수정할 수 있는 자유로운 영혼입니다. 반면, 이전에 배웠던 튜플(())은 한 번 만들어지면 절대 수정할 수 없는 자물쇠 채운 상자(Immutable)죠.
파이썬은 내용물이 변할 수 있는 리스트를 집합에 넣는 것을 불안해해서 거부합니다. 따라서 해결책은 아주 간단합니다. 잠깐 자물쇠(튜플)를 채워서 중복을 제거하고, 다시 리스트로 풀어주면 됩니다.
2. 방법 1: 튜플(Tuple)로 변신시켜서 중복 날리기 (순서 무시)
가장 기본적이고 파이썬다운 방법입니다. 지난 시간에 배운 '리스트 컴프리헨션'을 활용하면 코드가 아주 깔끔해집니다.
📌 예제 코드: set과 tuple의 콜라보
# 이름, 나이, 부서가 담긴 2차원 리스트 (홍길동 데이터가 중복됨)
data = [
["홍길동", 30, "영업팀"],
["김철수", 25, "개발팀"],
["홍길동", 30, "영업팀"], # 완벽히 똑같은 중복 데이터!
["이영희", 28, "디자인팀"]
]
# 1. 안쪽 리스트들을 모두 튜플()로 바꾼 뒤, set()에 넣어 중복을 날립니다.
# (이때 데이터의 원래 순서는 뒤죽박죽 섞이게 됩니다.)
unique_tuples = set(tuple(row) for row in data)
# 2. 튜플로 묶여있던 데이터를 다시 리스트[]로 풀어줍니다.
clean_data = [list(row) for row in unique_tuples]
print(clean_data)
# 출력 예시 (순서는 다를 수 있음):
# [['이영희', 28, '디자인팀'], ['홍길동', 30, '영업팀'], ['김철수', 25, '개발팀']]
3. 방법 2: 원래 순서까지 완벽하게 지키기 (dict.fromkeys)
크롤링을 했거나 시간순으로 쌓인 데이터라서 "처음 들어온 순서를 무조건 유지"해야 한다면, 1차원 리스트 때 썼던 딕셔너리 꼼수를 똑같이 적용하면 됩니다.
📌 예제 코드: 순서 유지하며 중복 제거하기
data = [
["홍길동", 30, "영업팀"],
["김철수", 25, "개발팀"],
["홍길동", 30, "영업팀"], # 중복
["이영희", 28, "디자인팀"]
]
# 1. 안쪽 리스트를 튜플로 바꿔서 딕셔너리의 Key로 만듭니다. (중복 제거 + 순서 기억)
dict_data = dict.fromkeys(tuple(row) for row in data)
# 2. 딕셔너리의 Key들만 쏙쏙 뽑아서 다시 리스트로 감싸줍니다.
ordered_clean_data = [list(key) for key in dict_data]
print("순서 유지 결과:")
for row in ordered_clean_data:
print(row)
실행 결과:
순서 유지 결과:
['홍길동', 30, '영업팀']
['김철수', 25, '개발팀']
['이영희', 28, '디자인팀']
홍길동이 맨 처음에 등장했던 그 순서 그대로 예쁘게 살아남았습니다!
4. 방법 3: 보너스 트랙! 판다스(Pandas)로 1초 컷
만약 여러분이 엑셀처럼 방대한 데이터를 다루고 있고 이미 pandas 패키지를 알고 계신다면, 저렇게 복잡하게 튜플로 변환할 필요가 전혀 없습니다. 판다스는 2차원 리스트(표 형태)를 다루는 끝판왕이기 때문입니다.
📌 예제 코드: 판다스의 drop_duplicates()
import pandas as pd
data = [
["홍길동", 30, "영업팀"],
["김철수", 25, "개발팀"],
["홍길동", 30, "영업팀"],
["이영희", 28, "디자인팀"]
]
# 1. 2차원 리스트를 판다스 데이터프레임으로 만듭니다.
df = pd.DataFrame(data)
# 2. 중복을 날리고(.drop_duplicates()), 다시 리스트로 되돌립니다(.values.tolist())
pandas_clean_data = df.drop_duplicates().values.tolist()
print(pandas_clean_data)
# 출력: [['홍길동', 30, '영업팀'], ['김철수', 25, '개발팀'], ['이영희', 28, '디자인팀']]
단 한 줄(df.drop_duplicates().values.tolist())로 순서까지 갓벽하게 유지하면서 중복을 없앴습니다. 실무에서 데이터 분석가들이 가장 사랑하는 방식입니다.
📝 마치며
핵심 요약입니다.
2차원 리스트는 그냥 set()에 넣으면 에러가 납니다! 따라서 안쪽 데이터들을 자물쇠 채운 튜플(tuple)로 변환하는 과정을 거쳐야 합니다.
- 순서 상관없을 때:
[list(x) for x in set(tuple(x) for x in data)] - 순서 지켜야 할 때:
[list(x) for x in dict.fromkeys(tuple(x) for x in data)] - 판다스를 쓸 줄 안다면:
pd.DataFrame(data).drop_duplicates().values.tolist()
이제 아무리 복잡하게 얽힌 다차원 리스트를 만나도 가뿐하게 중복을 날려버리실 수 있습니다.
'IT > Python' 카테고리의 다른 글
| [Python 실전 팁] "누가 겹치고 누가 빠졌지?" 파이썬 리스트 교집합, 차집합 비교하기 (1) | 2026.05.14 |
|---|---|
| [Python] "중복 데이터, 대체 어디 숨어있어?" 파이썬 리스트 중복 인덱스(위치) 찾기 완벽 가이드 (0) | 2026.05.12 |
| [Python] "원하는 데이터만 쏙쏙!" 파이썬 정규표현식(Regex) 기초 완벽 가이드 (0) | 2026.04.17 |
| [Python 기초] "중복 제거와 정렬을 단 한 줄로!" 파이썬 리스트 완벽 정리 비법 (1) | 2026.04.16 |
| [Python 기초] "똑같은 데이터 다 나와!" 파이썬 리스트 중복 제거 완벽 가이드 (순서 유지 vs 순서 무시) (0) | 2026.04.16 |