목록에 대해 연산 수행하기

완료됨

목록에 여러 개의 항목을 저장한 경우 목록의 일부 또는 전부에 대해 연산을 수행하게 됩니다. 목록 모듈에는 이렇게 하는 데 도움이 되는 여러 유용한 연산이 있습니다.

모듈 함수 나열하기

속성 외에도 목록에 대해 연산을 수행하는 여러 함수를 갖는 목록 모듈이 있습니다. 함수는 찾기, 필터링, 정렬, 수학 연산 수행하기와 같은 자주 사용되는 연산을 수행합니다.

반복

반복이란 목록의 요소를 시작부터 종료까지 하나씩 살펴보는 것을 의미합니다. 반복의 경우 특히 흥미로운 다음 두 가지 함수가 있습니다.

  • iter(): 이 함수를 사용하면 다음과 같이 목록의 각 항목에 대해 반복을 수행할 수 있습니다.

    let cards = [ 1 .. 5 ]
    List.iter(fun i -> printfn "%i" i) cards // 1 2 3 4 5
    

    iter() 함수는 함수를 받습니다. 위 코드에서는 fun 키워드를 사용하여 익명 함수를 제공합니다. 이 함수는 반복이 수행되고 있는 현재 항목을 나타내는 하나의 매개 변수를 받습니다. 위 코드를 루프를 사용하여 작성하면 아래 코드가 됩니다.

    for i in cards do printfn "%i" i
    
  • map(): 이 함수는 iter()과 비슷하나, 요소를 변환할 수 있다는 차이가 있습니다. 예를 들면 다음과 같습니다.

    type Person = { FirstName: string; LastName: string  }
    let people = [
       { FirstName="Albert"; LastName= "Einstein" }
       { FirstName="Marie"; LastName="Curie" }
    ]
    let nobelPrizeWinners = List.map (fun person -> person.FirstName + person.LastName) people 
    printfn "%A" nobelPrizeWinners // ["Albert Einstein"; "Marie Curie"]
    

    위 코드에서는 Person 개체로 구성된 목록이 문자열로 구성된 목록으로 변환되었습니다.

Assert

filter() 함수도 매개 변수로 함수를 받지만, 이 함수의 목적은 유지해야 할 요소를 정의하는 것입니다. 식이 true로 계산되면 요소가 유지됩니다. 식이 false이면 필터링된 목록에 해당 요소가 포함되지 않습니다. 아래 예에서는 값을 2로 나눌 수 있는 항목만 유지하도록 목록이 필터링됩니다.

let cards = [ 1 .. 5 ]
let filteredList = List.filter(fun i-> i % 2 = 0) cards
List.iter(fun i -> printfn "item %i" i) filteredList // item 2 item 4

이제 filteredList 목록은 i % 2 = 0을 계산했을 때 true을 반환하는 요소(2와 4)만 포함합니다.

정렬

목록의 정렬은 자주 사용되는 기능입니다. 아래에서 목록을 정렬할 때 유용하게 사용할 수 있는 세 개의 함수를 살펴보세요.

  • sort()은(는) 오름차순으로 정렬합니다. 예를 들면 다음과 같습니다.

    let list = [2; 1; 5; 3]
    let sortedList = List.sort list // 1 2 3 5 
    
  • sortBy(): 이 함수의 목표는 정렬의 기준이 되는 키를 찾는 것입니다. 사람으로 구성된 목록이 있고 각 레코드에 name 필드와 age 필드가 있다고 가정해 보겠습니다. 이때 age를 기준으로 정렬하도록 지정할 수 있습니다. 이 함수는 키를 가리키는 함수를 취합니다. 또 다른 키는 다음 예에서와같이 문자열의 길이가 될 수 있습니다.

    let fruits = ["Banana"; "Apple"; "Pineapple"]
    let sortedFruits = List.sortBy (fun (fruit : string) -> fruit.Length) fruits // Apple, Banana, Pineapple
    
  • sortWith(): 이 함수를 사용하면 비교자 함수를 제공할 수 있습니다. 처음에는 여러 항목 중에서 가장 먼저 어느 항목을 기준으로 정렬하는 것이 좋을지 알기 어려울 수 있습니다. 다음 예제 코드를 살펴보세요.

    // assume a type like so
    type MagicCreature = { Name : string; Level: int; Attack: int }
    let creatures = [
       { Name="Dragon"; Level=2; Attack=20 }
       { Name="Orc"; Level=1; Attack=5 }
       { Name="Demon"; Level=2; Attack=10 } 
    ]
    
    // comparison function, -1 = less than, 1 = larger than, 0 = equal
    let compareCreatures c1 c2 =
         if c1.Level < c2.Level then -1
         else if c1.Level > c2.Level then 1
         else if c1.Attack < c2.Attack then -1
         else if c1.Attack > c2.Attack then 1
         else 0
    
    let sorted = List.sortWith compareCreatures creatures // { Name="Orc"; Level=1; Attack=5 }, { Name="Demon"; Level=2; Attack=10 }, { Name="Dragon"; Level=2; Attack=20 }
    

    위의 비교자 함수 compareCreatures()는 먼저 Level을 기준으로 비교를 시도합니다. Level이 동일하면 다음으로 Attack을 기준으로 비교를 시도합니다. 보다 작은 경우에는 -1을, 보다 큰 경우에는 1을, 동일한 경우에는 0을 반환합니다.

수행할 수 있는 또 다른 방법은 특정 요소를 찾는 것입니다. 이렇게 하려면 다음 함수 중 하나를 사용할 수 있습니다.

  • find(): 이 함수는 특정 조건과 일치하는 첫 번째 요소를 찾습니다. find()를 사용하려면 해당 항목을 어떻게 찾을지 표현하는 함수(조건자)를 제공해야 합니다. 예를 들면 다음과 같습니다.

    let list = [1; 2; 3; 4]
    let found = List.find( fun x -> x % 2 = 0) list // 2 - Only the first element that matches the condition is returned.
    
  • tryFind(). 이 함수는 값을 찾는 방법과 살펴볼 목록을 알려 주는 함수(조건자)를 받습니다. 하나의 옵션을 반환합니다. 사용 방법은 다음과 같습니다.

    let findValue aValue aList =
         let found = aList |> List.tryFind(fun item -> item = aValue)
    
         match found with
         | Some value -> printfn "%i" value
         | None -> printfn "Not found"
    
    findValue 1 list // 1
    findValue 5 list // Not found
    

    위 코드에서는 목록을 비교하는 데 사용할 값을 제공합니다. 찾은 경우 Some을 반환합니다. 찾지 못한 경우 None을 반환합니다.

  • tryFindIndex(). 이 함수는 tryFind()와 마찬가지로 옵션을 반환하며, 부울로 계산되는 함수(조건자)를 받습니다. 아래와 같이 사용할 수 있습니다.

    let found = List.tryFindIndex(fun x -> x = 4) list
    match found with
       | Some index -> printfn "%i" index
       | None -> printfn "Not found"
    

산술 연산

목록에 대해 수학 연산을 수행하는 것이 유용할 수 있습니다. 아래에서 목록 API의 여러 함수 중에서 가장 유용한 세 개의 함수를 살펴보세요.

  • sum(): 이 함수는 각 항목에 대해 반복을 수행하여 목록에 있는 모든 값의 합계를 구합니다. 사용 방법은 다음과 같습니다.

    let sum = List.sum [1 .. 5] // sum = 15 
    
  • sumBy(): 이 함수의 목적은 값을 합산하는 방법을 알려 주는 것입니다. 이렇게 하는 한 가지 방법은 다음 예에서와같이 어느 필드를 합산할지 가리키는 것입니다.

    type OrderItem = { Name: string; Cost:int }
    
    let orderItems = [
           { Name="XBox"; Cost=500 }
           { Name="Book"; Cost=10 }
           { Name="Movie ticket"; Cost=7 }
         ]
    
    let sum = List.sumBy(fun item -> item.Cost) orderItems
    printfn "%i" sum // 517
    

    위 코드에서는 Cost 필드가 지정되었고, 이 필드에 있는 각 항목이 합계로 합산됩니다.

  • average(): 이 함수는 숫자로 이루어진 목록에 대해 연산을 수행한다는 점에서 sum()과 비슷하지만, 두 가지 차이점이 있습니다.

    • 데이터가 정수가 아닌 부동 소수점 숫자여야 합니다.
    • 합계가 아닌 평균을 계산합니다.

    예를 들면 다음과 같습니다.

    let numbers = [ 1.0; 2.5; 3.0 ]
    let avg = List.average numbers
    printfn "%f" avg // 2.166667
    
  • averageBy(): averageBy()sumBy()처럼 원하는 값이 지정된 함수를 받습니다. 예를 들면 다음과 같습니다.

    type WeatherMeasurement = { Date: string; Temperature: float }
    let measurements = [
        { Date="07/20/2021"; Temperature=21.3 }
        { Date="07/21/2021"; Temperature=23.2 }
        { Date="07/22/2021"; Temperature=20.7 }
    ]
    
    let avgBy = List.averageBy(fun m -> m.Temperature) measurements
    printfn "%f" avgBy // 21.733333