itertools.groupby는 입력 전체에서 같은 키를 한데 모으지 않습니다. 현재 입력 순서에서 키가 연속해 같은 구간마다 그룹을 하나 만들기 때문에 A, B, A는 A 그룹 두 개와 B 그룹 하나로 나뉩니다.

같은 키의 모든 항목을 한 그룹에서 보고 싶다면 그 항목들이 연속하도록 입력을 준비해야 합니다. 떨어져 있다면 같은 key 함수로 정렬하는 방법을 쓸 수 있습니다. 이 동작은 SQL의 GROUP BY와 다릅니다.

groupby는 같은 키가 이어지는 구간을 묶습니다

함수 이름을 보고 groupby가 입력 어디에 있든 같은 값을 전부 모을 것이라고 예상하기 쉽습니다. Python 3.12의 itertools.groupby는 그런 전체 집계를 하지 않습니다. 입력을 앞에서부터 읽다가 key 함수의 결과가 달라지면 현재 그룹을 끝내고 새 그룹을 시작합니다. 따라서 같은 키가 나중에 다시 나타나도 그때는 별도 그룹입니다. 문서에서는 이 동작을 연속한 키의 그룹으로 정의하며, 일반적으로 같은 key 함수 기준으로 데이터를 미리 정렬해야 한다고 설명합니다.

A, B, A에는 세 개의 연속 구간이 있습니다

아래 기록에서 첫 번째 값은 부서 코드이고 두 번째 값은 작업 이름이라고 하겠습니다. key 함수는 부서 코드만 봅니다. A로 시작한 첫 그룹에는 A-1이 들어갑니다. 그다음 B를 만나면 그룹이 바뀌고, 마지막에 A가 다시 나와도 앞의 A 그룹으로 돌아가지 않습니다. 입력의 실행 흐름대로 경계를 그으면 세 그룹이 만들어집니다.

Python 3.12에서 key 값이 연속한 구간별로 출력하는 창작 예제입니다.
from itertools import groupby

rows = [("A", "A-1"), ("B", "B-1"), ("A", "A-2")]
groups = [(key, [name for _, name in group])
          for key, group in groupby(rows, key=lambda row: row[0])]
print(groups)
입력 순서에서 키가 바뀌는 지점마다 그룹을 나눕니다
입력 위치키처리그룹 경계
1AA-1을 저장첫 번째 A 그룹 시작
2B새 그룹 시작A 그룹 종료
3A다시 새 그룹 시작B 그룹 종료, 두 번째 A 그룹

이 예제의 결과는 [("A", ["A-1"]), ("B", ["B-1"]), ("A", ["A-2"])]입니다. 키 종류는 두 가지지만 그룹은 세 개입니다. 그룹의 수를 키의 고유 개수와 같다고 생각하면 틀립니다. 첫 번째 A와 세 번째 행의 A 사이에 B가 있기 때문입니다. groupby는 키를 기억해 과거 그룹에 합치지 않고, 현재 이웃한 값이 같은지를 기준으로 이어 갑니다.

같은 키가 연속한지 확인하고 필요하면 정렬합니다

같은 부서의 기록을 한 그룹으로 처리하려는 목적이라면 groupby에 넘기는 key 함수와 같은 기준으로 sorted를 먼저 적용할 수 있습니다. 예를 들어 부서 코드를 기준으로 정렬하면 A 기록 두 줄이 붙고, 이어서 B가 나옵니다. 그때 groupby는 A 한 그룹과 B 한 그룹을 만듭니다. sorted는 새 목록을 반환하므로 원래 기록 순서를 보존해야 한다면 원본과 정렬 결과의 용도를 구분하세요. 대소문자 정규화나 여러 필드 키를 쓴다면 정렬과 그룹화에 동일한 key 함수를 전달해야 합니다.

그룹화 전에 동일한 key 기준으로 정렬합니다.
import itertools

rows = [("A", "A-1"), ("B", "B-1"), ("A", "A-2")]
ordered = sorted(rows, key=lambda row: row[0])
all_by_department = [(key, [name for _, name in group])
                     for key, group in itertools.groupby(ordered, key=lambda row: row[0])]
print(all_by_department)
  1. 무엇을 같은 것으로 볼지 key 함수를 정합니다.
  2. 같은 키의 항목이 입력에서 연속하는지 살펴봅니다.
  3. 같은 키가 떨어져 있다면 결과에서 별도 그룹으로 나뉨을 예상합니다.
  4. 같은 키를 한데 모을 목적이고 아직 떨어져 있다면 동일한 key 함수로 정렬할 수 있습니다.
  5. 각 그룹 iterator는 필요한 시점에 소비하거나 목록으로 저장합니다.

같은 키가 이미 연속한 B, B, A, A는 오름차순 정렬을 새로 하지 않아도 B와 A가 각각 한 그룹입니다. 정렬 함수 호출 자체가 필수 조건은 아닙니다. 입력 순서에 따라 연속 구간을 찾는 것이 목표라면 원래 순서를 유지하고 groupby 결과를 세면 됩니다. 예를 들어 이벤트 로그에서 상태가 바뀌는 구간을 찾을 때는 A-B-A를 세 구간으로 보는 편이 목적에 맞을 수 있습니다. 반면 부서별 합계를 구하려고 한다면 A가 떨어져 있어도 한 묶음으로 처리하려는지부터 정해야 합니다. 문제의 요구가 ‘연속 구간’인지 ‘같은 키 전체 집계’인지 구별하세요.

SQL GROUP BY와 같은 전역 집계로 읽지 않습니다

흔한 실수는 SQL의 GROUP BY처럼 입력 행의 위치와 상관없이 같은 키를 하나로 모은다고 생각하는 것입니다. Python 공식 itertools 라이브러리 문서는 키가 바뀔 때 새 그룹을 만들며 SQL의 GROUP BY와 다르다고 설명합니다. 반대로 미리 정렬하지 않은 데이터를 무조건 정렬하면 원래 시간순이나 우선순위순이 사라질 수 있습니다. 먼저 질문이 요구하는 결과를 확인한 뒤 순서를 유지할지, 키별 집계를 위해 순서를 재배치할지 선택해야 합니다. 그룹에서 실제 합계나 건수를 만들려면 각 그룹을 소비하며 그 값을 직접 계산해야 합니다. groupby가 합계까지 자동으로 계산해 주지는 않습니다.

정답을 가리고 확인해 보세요

이 글을 위해 만든 학습 예시이며 공식 기출문제나 판매 카드의 인용이 아닙니다.

키가 A, B, A, A인 입력을 같은 key 함수로 groupby하면 그룹의 키 순서는 무엇인가요? 전체 A를 한 그룹으로 모으려면 입력에서 무엇을 만족해야 하며 어떤 준비 방법을 쓸 수 있나요?

정답과 해설 확인그룹 키는 A, B, A입니다. A 전체가 연속해야 합니다. 이 입력은 A가 떨어져 있으므로 같은 key 함수로 정렬하는 방법을 쓸 수 있습니다.

groupby는 키가 달라지는 지점에서 새 구간을 만듭니다. 마지막 두 A는 연속하지만 첫 A와 B 사이가 끊어졌으므로 A 그룹 두 개가 생깁니다.