리스트 연산

토파즈의 리스트와 컬렉션 연산을 마스터하세요. 배열, 맵, 셋 등 모든 컬렉션 타입의 고급 조작법을 배워보세요.

토파즈는 강력한 리스트 및 컬렉션 연산을 제공하여 데이터 구조를 효율적으로 다룰 수 있습니다. 모든 연산은 불변성과 함수형 프로그래밍을 지원합니다. 📊

📋 배열 (Array) 연산

배열 생성 및 초기화

// 다양한 배열 생성 방법
let 빈배열: Array<int> = []
let 숫자배열 = [1, 2, 3, 4, 5]
let 문자배열 = ["사과", "바나나", "체리"]

// 반복으로 배열 생성
let 반복배열 = Array.fill(10, 0)              // [0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
let 범위배열 = Array.range(1, 6)              // [1, 2, 3, 4, 5]
let 생성배열 = Array.generate(5, i => i * 2)  // [0, 2, 4, 6, 8]

// 타입 추론과 제네릭
let 혼합배열: Array<any> = [1, "hello", true]
let 제네릭배열: Array<T> = Array.new()

print("숫자 배열: {숫자배열}")
print("범위 배열: {범위배열}")
print("생성 배열: {생성배열}")

배열 변환 연산

let 원본배열 = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]

// map - 각 요소 변환
let 제곱배열 = 원본배열.map(x => x * x)
let 문자열배열 = 원본배열.map(x => "숫자: {x}")
let 객체배열 = 원본배열.map(x => { 값: x, 제곱: x * x })

// flatMap - 평면화와 매핑 결합
let 중첩배열 = [[1, 2], [3, 4], [5, 6]]
let 평면화 = 중첩배열.flatMap(arr => arr)     // [1, 2, 3, 4, 5, 6]

// 조건부 매핑
let 조건부변환 = 원본배열.map(x => {
    if x % 2 == 0 {
        return x * 2
    } else {
        return x
    }
})

print("제곱 배열: {제곱배열}")
print("평면화: {평면화}")
print("조건부 변환: {조건부변환}")

배열 필터링 연산

let 테스트배열 = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15]

// 기본 필터링
let 짝수필터 = 테스트배열.filter(x => x % 2 == 0)     // [2, 4, 6, 8, 10, 12, 14]
let 큰수필터 = 테스트배열.filter(x => x > 10)         // [11, 12, 13, 14, 15]

// 복합 조건 필터링
let 복합필터 = 테스트배열.filter(x => x % 2 == 0 && x > 5)  // [6, 8, 10, 12, 14]

// 인덱스 기반 필터링
let 인덱스필터 = 테스트배열.filterWithIndex((값, 인덱스) => 인덱스 % 3 == 0)

// 타입 필터링
let 혼합데이터: Array<any> = [1, "hello", 3.14, true, "world", 42]
let 숫자만 = 혼합데이터.filter(x => match x {
    case _: int => true
    case _: float => true
    case _ => false
})     // [1, 3.14, 42]
let 문자열만 = 혼합데이터.filter(x => match x {
    case _: string => true
    case _ => false
})   // ["hello", "world"]

print("짝수 필터: {짝수필터}")
print("복합 필터: {복합필터}")
print("숫자만: {숫자만}")

배열 누적 연산

let 숫자들 = [1, 2, 3, 4, 5]

// reduce - 기본 누적
let 합계 = 숫자들.reduce((누적, 현재) => 누적 + 현재, 0)        // 15
let 곱셈 = 숫자들.reduce((누적, 현재) => 누적 * 현재, 1)        // 120
let 최대값 = 숫자들.reduce((누적, 현재) => Math.max(누적, 현재), 숫자들[0])

// reduceRight - 오른쪽부터 누적
let 오른쪽누적 = 숫자들.reduceRight((누적, 현재) => 누적 + 현재, 0)

// scan - 중간 결과 포함
let 누적합배열 = 숫자들.scan((누적, 현재) => 누적 + 현재, 0)     // [0, 1, 3, 6, 10, 15]

// 복잡한 누적 연산
let 통계 = 숫자들.reduce((누적, 현재) => {
    return {
        합계: 누적.합계 + 현재,
        개수: 누적.개수 + 1,
        최대값: Math.max(누적.최대값, 현재),
        최소값: Math.min(누적.최소값, 현재)
    }
}, { 합계: 0, 개수: 0, 최대값: -Infinity, 최소값: Infinity })

print("합계: {합계}")
print("누적합 배열: {누적합배열}")
print("통계: {통계}")

🔍 배열 검색 및 정렬

검색 연산

let 데이터배열 = [10, 25, 8, 15, 32, 7, 18, 42, 3, 29]

// 기본 검색
let 찾기 = 데이터배열.find(x => x > 20)              // Some(25)
let 인덱스찾기 = 데이터배열.findIndex(x => x > 20)    // Some(1)
let 마지막찾기 = 데이터배열.findLast(x => x > 20)     // Some(42)

// 다중 검색
let 모든큰수 = 데이터배열.filter(x => x > 20)         // [25, 32, 42, 29]
let 첫번째3개 = 데이터배열.take(3)                    // [10, 25, 8]
let 마지막3개 = 데이터배열.takeLast(3)               // [42, 3, 29]

// 조건부 검색
let 조건검색 = 데이터배열.takeWhile(x => x != 32)     // [10, 25, 8, 15]
let 조건건너뛰기 = 데이터배열.skipWhile(x => x < 20)  // [25, 8, 15, 32, 7, 18, 42, 3, 29]

// 이진 검색 (정렬된 배열에서)
let 정렬된배열 = [1, 3, 5, 7, 9, 11, 13, 15]
let 이진검색결과 = 정렬된배열.binarySearch(9)          // Some(4)

print("찾기 결과: {찾기}")
print("모든 큰수: {모든큰수}")
print("조건 검색: {조건검색}")

정렬 연산

let 무작위배열 = [64, 34, 25, 12, 22, 11, 90, 5]

// 기본 정렬
let 오름차순 = 무작위배열.sort()                      // [5, 11, 12, 22, 25, 34, 64, 90]
let 내림차순 = 무작위배열.sortDescending()            // [90, 64, 34, 25, 22, 12, 11, 5]

// 커스텀 정렬
let 사용자정렬 = 무작위배열.sortBy((a, b) => {
    if a % 2 == 0 && b % 2 != 0 { return -1 }    // 짝수를 앞으로
    if a % 2 != 0 && b % 2 == 0 { return 1 }     // 홀수를 뒤로
    return a - b                                   // 같은 타입은 오름차순
})

// 객체 배열 정렬
let 사용자들 = [
    { 이름: "김철수", 나이: 25, 점수: 85 },
    { 이름: "이영희", 나이: 30, 점수: 92 },
    { 이름: "박민수", 나이: 20, 점수: 78 }
]

let 나이순정렬 = 사용자들.sortBy(user => user.나이)
let 점수순정렬 = 사용자들.sortByDescending(user => user.점수)
let 다중정렬 = 사용자들.sortBy([
    user => user.점수,      // 1차: 점수 오름차순
    user => -user.나이      // 2차: 나이 내림차순
])

print("사용자 정렬: {사용자정렬}")
print("나이순 정렬: {나이순정렬}")
print("점수순 정렬: {점수순정렬}")

📊 집합 연산 (Set)

Set 생성 및 기본 연산

// Set 생성
let 빈집합: Set<int> = Set.new()
let 숫자집합 = Set.from([1, 2, 3, 4, 5])
let 중복제거집합 = Set.from([1, 1, 2, 2, 3, 3])    // {1, 2, 3}

// 기본 집합 연산
let mut 가변집합 = Set.from([1, 2, 3])
가변집합.add(4)                                      // {1, 2, 3, 4}
가변집합.remove(2)                                   // {1, 3, 4}

let 포함확인 = 가변집합.contains(3)                  // true
let 크기 = 가변집합.size()                          // 3

// 집합 변환
let 배열로변환 = 가변집합.toArray()                 // [1, 3, 4]
let 리스트로변환 = 가변집합.toList()                // List(1, 3, 4)

print("숫자 집합: {숫자집합}")
print("가변 집합: {가변집합}")

Set 집합 연산

let 집합A = Set.from([1, 2, 3, 4, 5])
let 집합B = Set.from([4, 5, 6, 7, 8])
let 집합C = Set.from([1, 3, 5, 7, 9])

// 합집합 (Union)
let 합집합 = 집합A.union(집합B)                     // {1, 2, 3, 4, 5, 6, 7, 8}

// 교집합 (Intersection)
let 교집합 = 집합A.intersection(집합B)              // {4, 5}

// 차집합 (Difference)
let 차집합 = 집합A.difference(집합B)                // {1, 2, 3}

// 대칭차집합 (Symmetric Difference)
let 대칭차집합 = 집합A.symmetricDifference(집합B)   // {1, 2, 3, 6, 7, 8}

// 부분집합 확인
let 부분집합확인 = Set.from([1, 2]).isSubsetOf(집합A)    // true
let 상위집합확인 = 집합A.isSupersetOf(Set.from([1, 2]))  // true

// 교집합 존재 확인
let 교집합있음 = 집합A.intersects(집합B)            // true

print("합집합: {합집합}")
print("교집합: {교집합}")
print("차집합: {차집합}")
print("대칭차집합: {대칭차집합}")

🗺️ 맵 연산 (Map)

Map 생성 및 기본 연산

// Map 생성
let 빈맵: Map<string, int> = Map.new()
let 점수맵 = Map.from([
    ["김철수", 85],
    ["이영희", 92],
    ["박민수", 78]
])

// 기본 맵 연산
let mut 가변맵 = Map.new()
가변맵.set("사과", 1000)
가변맵.set("바나나", 1500)
가변맵.set("오렌지", 2000)

let 값가져오기 = 가변맵.get("사과")                 // Some(1000)
let 키존재확인 = 가변맵.has("바나나")              // true
let 크기확인 = 가변맵.size()                       // 3

// 기본값과 함께 가져오기
let 기본값 = 가변맵.getOrDefault("포도", 0)         // 0

// 맵 순회
가변맵.forEach((값, 키) => {
    print("{키}: {값}원")
})

print("점수 맵: {점수맵}")
print("가변 맵: {가변맵}")

Map 변환 및 필터링

let 상품맵 = Map.from([
    ["노트북", 1500000],
    ["마우스", 50000],
    ["키보드", 120000],
    ["모니터", 300000],
    ["스피커", 80000]
])

// 맵 변환
let 할인가격 = 상품맵.map((가격, 상품) => 가격 * 0.9)
let 상품설명 = 상품맵.map((가격, 상품) => "{상품}: {가격}원")

// 맵 필터링
let 고가상품 = 상품맵.filter((가격, 상품) => 가격 > 100000)
let 특정상품 = 상품맵.filterKeys(상품 => 상품.contains("북"))

// 키와 값 추출
let 모든키 = 상품맵.keys()                        // ["노트북", "마우스", ...]
let 모든값 = 상품맵.values()                      // [1500000, 50000, ...]
let 엔트리들 = 상품맵.entries()                   // [["노트북", 1500000], ...]

// 맵 합치기
let 추가상품 = Map.from([["태블릿", 800000], ["충전기", 30000]])
let 합친맵 = 상품맵.merge(추가상품)

print("할인 가격: {할인가격}")
print("고가 상품: {고가상품}")
print("모든 키: {모든키}")

📝 리스트 (List) 고급 연산

함수형 리스트 연산

let 숫자리스트 = List.from([1, 2, 3, 4, 5, 6, 7, 8, 9, 10])

// 체이닝 연산
let 복합연산결과 = 숫자리스트
    .filter(x => x % 2 == 0)        // 짝수만
    .map(x => x * x)                // 제곱
    .take(3)                        // 처음 3개
    .sum()                          // 합계

// 분할 연산
let (짝수들, 홀수들) = 숫자리스트.partition(x => x % 2 == 0)
let 그룹별나눔 = 숫자리스트.groupBy(x => x % 3)    // 나머지별 그룹화

// 윈도우 연산 (슬라이딩 윈도우)
let 윈도우3 = 숫자리스트.windowed(3)              // [[1,2,3], [2,3,4], [3,4,5], ...]
let 청크2 = 숫자리스트.chunked(2)                 // [[1,2], [3,4], [5,6], [7,8], [9,10]]

// zip 연산
let 문자리스트 = List.from(["a", "b", "c", "d", "e"])
let 압축결과 = 숫자리스트.zip(문자리스트)          // [(1,"a"), (2,"b"), (3,"c"), (4,"d"), (5,"e")]

print("복합 연산 결과: {복합연산결과}")
print("짝수들: {짝수들}, 홀수들: {홀수들}")
print("윈도우 3: {윈도우3}")
print("압축 결과: {압축결과}")

리스트 집계 연산

let 점수리스트 = List.from([85, 92, 78, 96, 84, 88, 79, 91])

// 기본 집계
let 총합 = 점수리스트.sum()                       // 693
let 평균 = 점수리스트.average()                   // 86.625
let 최대값 = 점수리스트.max()                     // Some(96)
let 최소값 = 점수리스트.min()                     // Some(78)
let 개수 = 점수리스트.count()                     // 8

// 조건부 집계
let 높은점수개수 = 점수리스트.count(x => x >= 90)  // 3
let 높은점수합계 = 점수리스트.sumBy(x => if x >= 90 { x } else { 0 })

// 통계 계산
let 분산 = 점수리스트.variance()
let 표준편차 = 점수리스트.standardDeviation()
let 중앙값 = 점수리스트.median()

// 사용자 정의 집계
let 사용자집계 = 점수리스트.aggregate(
    초기값: { 합계: 0, 개수: 0, 최고: 0 },
    함수: (누적, 현재) => {
        return {
            합계: 누적.합계 + 현재,
            개수: 누적.개수 + 1,
            최고: Math.max(누적.최고, 현재)
        }
    }
)

print("평균: {평균}")
print("표준편차: {표준편차}")
print("사용자 집계: {사용자집계}")

🔄 컬렉션 변환 연산

컬렉션 간 변환

// 배열 ↔ 리스트 ↔ 셋 변환
let 원본배열 = [1, 2, 2, 3, 3, 4, 5]
let 리스트변환 = List.from(원본배열)
let 셋변환 = Set.from(원본배열)              // 중복 제거됨
let 다시배열 = 셋변환.toArray()

// 맵으로 변환
let 키값쌍 = [["a", 1], ["b", 2], ["c", 3]]
let 맵변환 = Map.from(키값쌍)

// 그룹화 변환
let 학생점수 = [
    { 이름: "김철수", 과목: "수학", 점수: 85 },
    { 이름: "김철수", 과목: "영어", 점수: 90 },
    { 이름: "이영희", 과목: "수학", 점수: 95 },
    { 이름: "이영희", 과목: "영어", 점수: 88 }
]

let 학생별그룹 = 학생점수.groupBy(x => x.이름)
let 과목별그룹 = 학생점수.groupBy(x => x.과목)

// 맵으로 인덱싱
let 이름인덱스 = 학생점수.associateBy(x => x.이름)
let 키값매핑 = 학생점수.associate(x => [x.이름, x.점수])

print("셋 변환: {셋변환}")
print("학생별 그룹: {학생별그룹}")
print("이름 인덱스: {이름인덱스}")

⚡ 성능 최적화 연산

지연 평가 (Lazy Evaluation)

// 지연 평가 시퀀스
let 큰배열 = Array.range(1, 1000000)

// 즉시 평가 (메모리 사용량 높음)
let 즉시결과 = 큰배열
    .filter(x => x % 2 == 0)
    .map(x => x * x)
    .take(10)

// 지연 평가 (메모리 효율적)
let 지연시퀀스 = 큰배열
    .asSequence()
    .filter(x => x % 2 == 0)
    .map(x => x * x)
    .take(10)
    .toList()

// 무한 시퀀스
let 피보나치시퀀스 = Sequence.generate(
    초기값: [0, 1],
    생성함수: ([a, b]) => [b, a + b]
).map(([a, b]) => a)

let 피보나치처음10개 = 피보나치시퀀스.take(10).toList()

print("지연 시퀀스 결과: {지연시퀀스}")
print("피보나치 처음 10개: {피보나치처음10개}")

병렬 처리

// 병렬 처리 가능한 큰 데이터
let 대용량데이터 = Array.range(1, 100000)

// 순차 처리
let 순차결과 = 대용량데이터
    .filter(x => isPrime(x))
    .sum()

// 병렬 처리
let 병렬결과 = 대용량데이터
    .parallel()
    .filter(x => isPrime(x))
    .sum()

// 소수 판별 함수
function isPrime(n: int) -> bool {
    if n < 2 { return false }
    for i in 2..Math.sqrt(n) {
        if n % i == 0 { return false }
    }
    return true
}

// 병렬 맵-리듀스
let 병렬맵리듀스 = 대용량데이터
    .parallel()
    .map(x => x * x)
    .reduce((a, b) => a + b, 0)

print("병렬 결과: {병렬결과}")

🛠️ 사용자 정의 컬렉션

커스텀 컬렉션 구현

// 스택 구현
struct Stack<T> {
    items: Array<T>
}

impl<T> Stack<T> {
    function new() -> Stack<T> {
        return Stack { items: [] }
    }
    
    function push(item: T) {
        self.items.push(item)
    }
    
    function pop() -> Option<T> {
        return self.items.pop()
    }
    
    function peek() -> Option<T> {
        return self.items.last()
    }
    
    function isEmpty() -> bool {
        return self.items.isEmpty()
    }
    
    function size() -> int {
        return self.items.length()
    }
    
    // Iterator 구현
    function iterator() -> Iterator<T> {
        return self.items.reverse().iterator()
    }
}

// 사용 예제
let mut 스택 = Stack.new()
스택.push(1)
스택.push(2)
스택.push(3)

let 최상위 = 스택.peek()                      // Some(3)
let 팝결과 = 스택.pop()                       // Some(3)

for 항목 in 스택 {
    print("스택 항목: {항목}")
}

print("최상위: {최상위}")
print("팝 결과: {팝결과}")

특화된 컬렉션 연산

// 우선순위 큐
let 우선순위큐 = PriorityQueue.new((a, b) => a - b)  // 최소힙
우선순위큐.enqueue(5)
우선순위큐.enqueue(2)
우선순위큐.enqueue(8)
우선순위큐.enqueue(1)

while !우선순위큐.isEmpty() {
    let 최소값 = 우선순위큐.dequeue()
    print("우선순위: {최소값}")                // 1, 2, 5, 8 순서
}

// 트리맵 (정렬된 맵)
let 트리맵 = TreeMap.new()
트리맵.put("c", 3)
트리맵.put("a", 1)
트리맵.put("b", 2)

// 정렬된 순서로 출력
for (키, 값) in 트리맵 {
    print("{키}: {값}")                      // a:1, b:2, c:3 순서
}

// 멀티맵 (하나의 키에 여러 값)
let 멀티맵 = MultiMap.new()
멀티맵.put("과일", "사과")
멀티맵.put("과일", "바나나")
멀티맵.put("채소", "당근")

let 과일들 = 멀티맵.get("과일")               // ["사과", "바나나"]

print("과일들: {과일들}")

토파즈의 리스트 연산은 데이터 처리를 효율적이고 표현력 있게 만들어줍니다. 불변성과 함수형 프로그래밍을 활용하여 안전하고 읽기 쉬운 코드를 작성하세요! 🎯