F#의 목록은 동일한 형식의 순서가 지정되고 변경할 수 없는 요소 시리즈입니다. 목록에 대한 기본 작업을 수행하려면 목록 모듈의 함수를 사용합니다.
목록 만들기 및 초기화
다음 코드 줄과 같이 세미콜론으로 구분되고 대괄호로 묶인 요소를 명시적으로 나열하여 목록을 정의할 수 있습니다.
let list123 = [ 1; 2; 3 ]
요소 사이에 줄 바꿈을 배치할 수도 있습니다. 이 경우 세미콜론은 선택 사항입니다. 후자의 구문은 요소 초기화 식이 더 길거나 각 요소에 대한 주석을 포함하려는 경우 더 읽기 쉬운 코드가 될 수 있습니다.
let list123 = [ 1; 2; 3 ]
일반적으로 모든 목록 요소는 동일한 형식이어야 합니다. 예외는 요소가 기본 형식으로 지정된 목록에 파생 형식인 요소가 있을 수 있다는 것입니다. 따라서 둘 다 Button 에서 CheckBox 파생 Control되므로 다음이 허용됩니다.
let myControlList: Control list = [ new Button(); new CheckBox() ]
다음 코드와 같이 범위 연산자()..로 구분된 정수로 표시된 범위를 사용하여 목록 요소를 정의할 수도 있습니다.
let list1 = [ 1..10 ]
빈 목록은 대괄호 쌍으로 지정되며 그 사이에 아무 것도 없습니다.
// An empty list.
let listEmpty = []
시퀀스 식을 사용하여 목록을 만들 수도 있습니다. 자세한 내용은 시퀀스 식을 참조하세요. 예를 들어 다음 코드는 1에서 10까지 정수의 제곱 목록을 만듭니다.
let listOfSquares = [ for i in 1..10 -> i * i ]
목록 작업을 위한 연산자
(cons) 연산자를 사용하여 :: 목록에 요소를 연결할 수 있습니다. 이 경우 list1 다음 코드는 다음과 같이 [100; 2; 3; 4]만듭니다list2.[2; 3; 4]
let list2 = 100 :: list1
다음 코드와 같이 연산자를 사용하여 호환되는 형식이 @ 있는 목록을 연결할 수 있습니다. 있는 [2; 3; 4] 경우 이 코드는 [100; 2; 3; 4].로 [2; 3; 4; 100; 2; 3; 4]만듭니다list3.list1list2
let list3 = list1 @ list2
목록에 대한 작업을 수행하기 위한 함수는 목록 모듈에서 사용할 수 있습니다.
F#의 목록은 변경할 수 없으므로 수정 작업은 기존 목록을 수정하는 대신 새 목록을 생성합니다.
F#의 목록은 Singly 연결된 목록으로 구현됩니다. 즉, 목록의 헤드에만 액세스하는 작업은 O(1)이고 요소 액세스는 O(n)입니다.
속성
목록 형식은 다음 속성을 지원합니다.
| 재산 | 유형 | 설명 |
|---|---|---|
| 머리 | 'T |
첫 번째 요소입니다. |
| 비어 있음 | 'T list |
적절한 형식의 빈 목록을 반환하는 정적 속성입니다. |
| IsEmpty | bool |
|
| 항목 | 'T |
지정된 인덱스(0부터)의 요소입니다. |
| 길이 | int |
요소 수입니다. |
| Tail | 'T list |
첫 번째 요소가 없는 목록입니다. |
다음은 이러한 속성을 사용하는 몇 가지 예입니다.
let list1 = [ 1; 2; 3 ]
// Properties
printfn "list1.IsEmpty is %b" (list1.IsEmpty)
printfn "list1.Length is %d" (list1.Length)
printfn "list1.Head is %d" (list1.Head)
printfn "list1.Tail.Head is %d" (list1.Tail.Head)
printfn "list1.Tail.Tail.Head is %d" (list1.Tail.Tail.Head)
printfn "list1.Item(1) is %d" (list1.Item(1))
목록 사용
목록을 사용하여 프로그래밍하면 적은 양의 코드로 복잡한 작업을 수행할 수 있습니다. 이 섹션에서는 기능 프로그래밍에 중요한 목록에 대한 일반적인 작업을 설명합니다.
목록을 사용하여 재귀
목록은 재귀 프로그래밍 기술에 고유하게 적합합니다. 목록의 모든 요소에서 수행해야 하는 작업을 고려합니다. 목록의 머리에서 작업한 다음 첫 번째 요소 없이 원래 목록으로 구성된 더 작은 목록인 목록의 꼬리를 다시 다음 재귀 수준으로 다시 전달하여 이 작업을 재귀적으로 수행할 수 있습니다.
이러한 재귀 함수를 작성하려면 패턴 일치에서 cons 연산자(::)를 사용하여 목록의 헤드를 꼬리에서 분리할 수 있습니다.
다음 코드 예제에서는 패턴 일치를 사용하여 목록에서 작업을 수행하는 재귀 함수를 구현하는 방법을 보여 줍니다.
let rec sum list =
match list with
| head :: tail -> head + sum tail
| [] -> 0
이전 코드는 작은 목록에 적합하지만 더 큰 목록의 경우 스택을 오버플로할 수 있습니다. 다음 코드는 재귀 함수를 사용하기 위한 표준 기술인 누적기 인수를 사용하여 이 코드를 개선합니다. 누적기 인수를 사용하면 함수 비상 재귀가 수행되어 스택 공간이 절약됩니다.
let sum list =
let rec loop list acc =
match list with
| head :: tail -> loop tail (acc + head)
| [] -> acc
loop list 0
이 함수 RemoveAllMultiples 는 두 개의 목록을 사용하는 재귀 함수입니다. 첫 번째 목록에는 배수가 제거되는 숫자가 포함되고, 두 번째 목록은 숫자를 제거할 목록입니다. 다음 예제의 코드는 이 재귀 함수를 사용하여 목록에서 소수가 아닌 모든 숫자를 제거하고 결과적으로 소수 목록을 남깁니다.
let IsPrimeMultipleTest n x = x = n || x % n <> 0
let rec RemoveAllMultiples listn listx =
match listn with
| head :: tail -> RemoveAllMultiples tail (List.filter (IsPrimeMultipleTest head) listx)
| [] -> listx
let GetPrimesUpTo n =
let max = int (sqrt (float n))
RemoveAllMultiples [ 2..max ] [ 1..n ]
printfn "Primes Up To %d:\n %A" 100 (GetPrimesUpTo 100)
출력은 다음과 같습니다.
Primes Up To 100:
[2; 3; 5; 7; 11; 13; 17; 19; 23; 29; 31; 37; 41; 43; 47; 53; 59; 61; 67; 71; 73; 79; 83; 89; 97]
모듈 함수
목록 모듈은 목록의 요소에 액세스하는 함수를 제공합니다. 헤드 요소는 가장 빠르고 쉽게 액세스할 수 있습니다.
Head 또는 모듈 함수 List.head 속성을 사용합니다.
Tail 속성 또는 List.tail 함수를 사용하여 목록의 꼬리에 액세스할 수 있습니다. 인덱스별로 요소를 찾으려면 List.nth 함수를 사용합니다.
List.nth 는 목록을 트래버스합니다. 따라서 O(n)입니다. 코드에서 자주 사용하는 List.nth 경우 목록 대신 배열을 사용하는 것이 좋습니다. 배열의 요소 액세스는 O(1)입니다.
목록의 부울 작업
List.isEmpty 함수는 목록에 요소가 있는지 여부를 결정합니다.
List.exists 함수는 부울 테스트를 목록의 요소에 적용하고 테스트에 맞는 요소가 있으면 반환 true 합니다.
List.exists2 는 비슷하지만 두 목록의 연속 요소 쌍에서 작동합니다.
다음 코드는 .의 List.exists사용을 보여 줍니다.
// Use List.exists to determine whether there is an element of a list satisfies a given Boolean expression.
// containsNumber returns true if any of the elements of the supplied list match
// the supplied number.
let containsNumber number list = List.exists (fun elem -> elem = number) list
let list0to3 = [0 .. 3]
printfn "For list %A, contains zero is %b" list0to3 (containsNumber 0 list0to3)
출력은 다음과 같습니다.
For list [0; 1; 2; 3], contains zero is true
다음 예에서는 List.exists2의 사용법을 보여줍니다.
// Use List.exists2 to compare elements in two lists.
// isEqualElement returns true if any elements at the same position in two supplied
// lists match.
let isEqualElement list1 list2 = List.exists2 (fun elem1 elem2 -> elem1 = elem2) list1 list2
let list1to5 = [ 1 .. 5 ]
let list5to1 = [ 5 .. -1 .. 1 ]
if (isEqualElement list1to5 list5to1) then
printfn "Lists %A and %A have at least one equal element at the same position." list1to5 list5to1
else
printfn "Lists %A and %A do not have an equal element at the same position." list1to5 list5to1
출력은 다음과 같습니다.
Lists [1; 2; 3; 4; 5] and [5; 4; 3; 2; 1] have at least one equal element at the same position.
목록의 모든 요소가 조건을 충족하는지 테스트하려는 경우 List.forall 을 사용할 수 있습니다.
let isAllZeroes list = List.forall (fun elem -> elem = 0.0) list
printfn "%b" (isAllZeroes [0.0; 0.0])
printfn "%b" (isAllZeroes [0.0; 1.0])
출력은 다음과 같습니다.
true
false
마찬가지로 List.forall2 는 두 목록의 해당 위치에 있는 모든 요소가 각 요소 쌍을 포함하는 부울 식을 충족하는지 여부를 결정합니다.
let listEqual list1 list2 = List.forall2 (fun elem1 elem2 -> elem1 = elem2) list1 list2
printfn "%b" (listEqual [0; 1; 2] [0; 1; 2])
printfn "%b" (listEqual [0; 0; 0] [0; 1; 0])
출력은 다음과 같습니다.
true
false
목록의 정렬 작업
List.sort, List.sortBy 및 List.sortWith 함수는 목록을 정렬합니다. 정렬 함수는 이러한 세 함수 중 사용할 함수를 결정합니다.
List.sort 는 기본 제네릭 비교를 사용합니다. 제네릭 비교에서는 제네릭 비교 함수를 기반으로 하는 전역 연산자를 사용하여 값을 비교합니다. 단순 숫자 형식, 튜플, 레코드, 구분된 공용 구조체, 목록, 배열 및 구현하는 모든 형식과 같은 다양한 요소 형식에서 효율적으로 작동합니다 System.IComparable. 구현 System.IComparable하는 형식의 경우 제네릭 비교는 함수를 System.IComparable.CompareTo() 사용합니다. 제네릭 비교는 문자열에서도 작동하지만 문화권 독립적 정렬 순서를 사용합니다. 제네릭 비교는 함수 형식과 같이 지원되지 않는 형식에 사용하면 안 됩니다. 또한 기본 제네릭 비교의 성능은 작은 구조화된 형식에 가장 적합합니다. 자주 비교하고 정렬해야 하는 더 큰 구조화된 형식의 경우 메서드의 System.IComparable.CompareTo() 효율적인 구현을 System.IComparable 구현하고 제공하는 것이 좋습니다.
List.sortBy 는 정렬 기준으로 사용되는 값을 반환하는 List.sortWith 함수를 사용하고 비교 함수를 인수로 사용합니다. 이러한 후자의 두 함수는 비교를 지원하지 않는 형식을 사용하거나 문화권 인식 문자열의 경우처럼 비교에 더 복잡한 비교 의미 체계가 필요한 경우에 유용합니다.
다음 예에서는 List.sort의 사용법을 보여줍니다.
let sortedList1 = List.sort [1; 4; 8; -2; 5]
printfn "%A" sortedList1
출력은 다음과 같습니다.
[-2; 1; 4; 5; 8]
다음 예에서는 List.sortBy의 사용법을 보여줍니다.
let sortedList2 = List.sortBy (fun elem -> abs elem) [1; 4; 8; -2; 5]
printfn "%A" sortedList2
출력은 다음과 같습니다.
[1; -2; 4; 5; 8]
다음 예제에서는 .의 List.sortWith사용을 보여 줍니다. 이 예제에서는 사용자 지정 비교 함수 compareWidgets 를 사용하여 먼저 사용자 지정 형식의 한 필드를 비교한 다음 첫 번째 필드의 값이 같을 때 다른 필드를 비교합니다.
type Widget = { ID: int; Rev: int }
let compareWidgets widget1 widget2 =
if widget1.ID < widget2.ID then -1 else
if widget1.ID > widget2.ID then 1 else
if widget1.Rev < widget2.Rev then -1 else
if widget1.Rev > widget2.Rev then 1 else
0
let listToCompare = [
{ ID = 92; Rev = 1 }
{ ID = 110; Rev = 1 }
{ ID = 100; Rev = 5 }
{ ID = 100; Rev = 2 }
{ ID = 92; Rev = 1 }
]
let sortedWidgetList = List.sortWith compareWidgets listToCompare
printfn "%A" sortedWidgetList
출력은 다음과 같습니다.
[{ID = 92;
Rev = 1;}; {ID = 92;
Rev = 1;}; {ID = 100;
Rev = 2;}; {ID = 100;
Rev = 5;}; {ID = 110;
Rev = 1;}]
목록에서 작업 검색
목록에는 다양한 검색 작업이 지원됩니다. 가장 간단한 List.find를 사용하면 지정된 조건과 일치하는 첫 번째 요소를 찾을 수 있습니다.
다음 코드 예제에서는 목록에서 5로 나눌 수 있는 첫 번째 숫자를 찾는 방법을 List.find 보여 줍니다.
let isDivisibleBy number elem = elem % number = 0
let result = List.find (isDivisibleBy 5) [ 1 .. 100 ]
printfn "%d " result
결과는 5입니다.
요소를 먼저 변환해야 하는 경우 List.pick을 호출합니다. List.pick은 옵션을 반환하는 함수를 사용하고 첫 번째 옵션 값을 찾습니다 Some(x). 요소를 List.pick 반환하는 대신 결과를 x반환합니다. 일치하는 요소를 찾을 수 List.pick 없으면 throw합니다 System.Collections.Generic.KeyNotFoundException. 다음 코드에서는 .List.pick
let valuesList = [ ("a", 1); ("b", 2); ("c", 3) ]
let resultPick = List.pick (fun elem ->
match elem with
| (value, 2) -> Some value
| _ -> None) valuesList
printfn "%A" resultPick
출력은 다음과 같습니다.
"b"
다른 검색 작업 그룹인 List.tryFind 및 관련 함수는 옵션 값을 반환합니다. 이 함수는 List.tryFind 이러한 요소가 있는 경우 조건을 충족하는 목록의 첫 번째 요소를 반환하지만 그렇지 않은 경우 옵션 값을 None 반환합니다. 변형 List.tryFindIndex 는 요소 자체가 아닌 요소의 인덱스를 반환합니다. 이러한 함수는 다음 코드에 설명되어 있습니다.
let list1d = [1; 3; 7; 9; 11; 13; 15; 19; 22; 29; 36]
let isEven x = x % 2 = 0
match List.tryFind isEven list1d with
| Some value -> printfn "The first even value is %d." value
| None -> printfn "There is no even value in the list."
match List.tryFindIndex isEven list1d with
| Some value -> printfn "The first even value is at position %d." value
| None -> printfn "There is no even value in the list."
출력은 다음과 같습니다.
The first even value is 22.
The first even value is at position 8.
목록의 산술 연산
합계 및 평균과 같은 일반적인 산술 연산은 목록 모듈에 기본 제공됩니다.
List.sum을 사용하려면 list 요소 형식이 연산자를 + 지원하고 값이 0이어야 합니다. 모든 기본 제공 산술 유형은 이러한 조건을 충족합니다.
List.average를 사용하려면 요소 형식이 정수 계열 형식을 제외하지만 부동 소수점 형식을 허용하는 나머지 없이 나누기를 지원해야 합니다.
List.sumBy 및 List.averageBy 함수는 함수를 매개 변수로 사용하며, 이 함수의 결과는 합계 또는 평균 값을 계산하는 데 사용됩니다.
다음 코드는 , List.sumBy및 List.average.의 List.sum사용을 보여 줍니다.
// Compute the sum of the first 10 integers by using List.sum.
let sum1 = List.sum [1 .. 10]
// Compute the sum of the squares of the elements of a list by using List.sumBy.
let sum2 = List.sumBy (fun elem -> elem*elem) [1 .. 10]
// Compute the average of the elements of a list by using List.average.
let avg1 = List.average [0.0; 1.0; 1.0; 2.0]
printfn "%f" avg1
1.000000가 출력됩니다.
다음 코드에서는 .List.averageBy
let avg2 = List.averageBy (fun elem -> float elem) [1 .. 10]
printfn "%f" avg2
5.5가 출력됩니다.
목록 및 튜플
튜플이 포함된 목록은 zip 및 압축 풀기 함수로 조작할 수 있습니다. 이러한 함수는 두 개의 단일 값 목록을 하나의 튜플 목록으로 결합하거나 하나의 튜플 목록을 단일 값의 두 목록으로 구분합니다. 가장 간단한 List.zip 함수는 두 개의 단일 요소 목록을 사용하고 단일 튜플 쌍 목록을 생성합니다. 또 다른 버전인 List.zip3은 단일 요소의 세 목록을 사용하고 세 개의 요소가 있는 단일 튜플 목록을 생성합니다. 다음 코드 예제에서는 .의 List.zip사용을 보여 줍니다.
let list1 = [ 1; 2; 3 ]
let list2 = [ -1; -2; -3 ]
let listZip = List.zip list1 list2
printfn "%A" listZip
출력은 다음과 같습니다.
[(1, -1); (2, -2); (3; -3)]
다음 코드 예제에서는 .의 List.zip3사용을 보여 줍니다.
let list3 = [ 0; 0; 0]
let listZip3 = List.zip3 list1 list2 list3
printfn "%A" listZip3
출력은 다음과 같습니다.
[(1, -1, 0); (2, -2, 0); (3, -3, 0)]
해당 unzip 버전인 List.unzip 및 List.unzip3은 튜플 목록을 가져와서 튜플에서 목록을 반환합니다. 여기서 첫 번째 목록에는 각 튜플의 첫 번째 요소가 모두 포함되고 두 번째 목록에는 각 튜플의 두 번째 요소가 포함됩니다.
다음 코드 예제에서는 List.unzip의 사용을 보여 줍니다.
let lists = List.unzip [(1,2); (3,4)]
printfn "%A" lists
printfn "%A %A" (fst lists) (snd lists)
출력은 다음과 같습니다.
([1; 3], [2; 4])
[1; 3] [2; 4]
다음 코드 예제에서는 List.unzip3의 사용을 보여 줍니다.
let listsUnzip3 = List.unzip3 [(1,2,3); (4,5,6)]
printfn "%A" listsUnzip3
출력은 다음과 같습니다.
([1; 4], [2; 5], [3; 6])
목록 요소에서 작업
F#은 목록 요소에 대한 다양한 작업을 지원합니다. 가장 간단한 것은 목록의 모든 요소에서 함수를 호출할 수 있는 List.iter입니다. 변형에는 각 요소의 인덱스가 각 요소에 대해 호출되는 함수에 인수로 전달된다는 점을 제외하고 List.iteri라는 두 목록의 요소에 대해 작업을 수행할 수 있는 List.iter2List.iter와 기능 List.iter2List.iteri의 조합인 List.iteri2가 포함됩니다. 다음 코드 예제에서는 이러한 함수를 보여 줍니다.
let list1 = [1; 2; 3]
let list2 = [4; 5; 6]
List.iter (fun x -> printfn "List.iter: element is %d" x) list1
List.iteri(fun i x -> printfn "List.iteri: element %d is %d" i x) list1
List.iter2 (fun x y -> printfn "List.iter2: elements are %d %d" x y) list1 list2
List.iteri2 (fun i x y ->
printfn "List.iteri2: element %d of list1 is %d element %d of list2 is %d"
i x i y)
list1 list2
출력은 다음과 같습니다.
List.iter: element is 1
List.iter: element is 2
List.iter: element is 3
List.iteri: element 0 is 1
List.iteri: element 1 is 2
List.iteri: element 2 is 3
List.iter2: elements are 1 4
List.iter2: elements are 2 5
List.iter2: elements are 3 6
List.iteri2: element 0 of list1 is 1; element 0 of list2 is 4
List.iteri2: element 1 of list1 is 2; element 1 of list2 is 5
List.iteri2: element 2 of list1 is 3; element 2 of list2 is 6
목록 요소를 변환하는 또 다른 자주 사용되는 함수는 목록의 각 요소에 함수를 적용하고 모든 결과를 새 목록에 넣을 수 있는 List.map입니다.
List.map2 및 List.map3 은 여러 목록을 사용하는 변형입니다. 또한 요소 외에도 함수를 각 요소의 인덱스로 전달해야 하는 경우 List.mapi 및 List.mapi2를 사용할 수 있습니다. 둘 사이의 List.mapi2List.mapi 유일한 차이점은 두 개의 목록에서 작동한다는 List.mapi2 것입니다. 다음 예제에서는 List.map을 보여 줍니다.
let list1 = [1; 2; 3]
let newList = List.map (fun x -> x + 1) list1
printfn "%A" newList
출력은 다음과 같습니다.
[2; 3; 4]
다음 예제에서는 List.map2의 사용을 보여 줍니다.
let list1 = [1; 2; 3]
let list2 = [4; 5; 6]
let sumList = List.map2 (fun x y -> x + y) list1 list2
printfn "%A" sumList
출력은 다음과 같습니다.
[5; 7; 9]
다음 예제에서는 List.map3의 사용을 보여 줍니다.
let newList2 = List.map3 (fun x y z -> x + y + z) list1 list2 [2; 3; 4]
printfn "%A" newList2
출력은 다음과 같습니다.
[7; 10; 13]
다음 예제에서는 List.mapi의 사용을 보여 줍니다.
let newListAddIndex = List.mapi (fun i x -> x + i) list1
printfn "%A" newListAddIndex
출력은 다음과 같습니다.
[1; 3; 5]
다음 예제에서는 List.mapi2의 사용을 보여 줍니다.
let listAddTimesIndex = List.mapi2 (fun i x y -> (x + y) * i) list1 list2
printfn "%A" listAddTimesIndex
출력은 다음과 같습니다.
[0; 7; 18]
List.collect 는 각 요소가 목록을 생성하고 이러한 모든 목록이 최종 목록에 연결된다는 점을 제외하면 비슷합니다 List.map. 다음 코드에서 목록의 각 요소는 세 개의 숫자를 생성합니다. 이러한 항목은 모두 하나의 목록으로 수집됩니다.
let collectList = List.collect (fun x -> [for i in 1..3 -> x * i]) list1
printfn "%A" collectList
출력은 다음과 같습니다.
[1; 2; 3; 2; 4; 6; 3; 6; 9]
또한 부울 조건을 사용하고 지정된 조건을 충족하는 요소로만 구성된 새 목록을 생성하는 List.filter를 사용할 수도 있습니다.
let evenOnlyList = List.filter (fun x -> x % 2 = 0) [1; 2; 3; 4; 5; 6]
결과 목록은 .입니다 [2; 4; 6].
맵과 필터의 조합인 List.choose 을 사용하면 요소를 동시에 변환하고 선택할 수 있습니다.
List.choose 는 목록의 각 요소에 옵션을 반환하는 함수를 적용하고, 함수가 옵션 값을 Some반환할 때 요소에 대한 결과의 새 목록을 반환합니다.
다음 코드에서는 단어 목록에서 대문자로 된 단어를 선택하는 방법을 List.choose 보여 줍니다.
let listWords = [ "and"; "Rome"; "Bob"; "apple"; "zebra" ]
let isCapitalized (string1:string) = System.Char.IsUpper string1[0]
let results = List.choose (fun elem ->
match elem with
| elem when isCapitalized elem -> Some(elem + "'s")
| _ -> None) listWords
printfn "%A" results
출력은 다음과 같습니다.
["Rome's"; "Bob's"]
여러 목록에서 작업
목록을 함께 조인할 수 있습니다. 두 목록을 하나로 조인하려면 List.append를 사용합니다. 두 개 이상의 목록을 조인하려면 List.concat을 사용합니다.
let list1to10 = List.append [1; 2; 3] [4; 5; 6; 7; 8; 9; 10]
let listResult = List.concat [ [1; 2; 3]; [4; 5; 6]; [7; 8; 9] ]
List.iter (fun elem -> printf "%d " elem) list1to10
printfn ""
List.iter (fun elem -> printf "%d " elem) listResult
접기 및 검사 작업
일부 목록 작업에는 모든 목록 요소 간의 상호 종속성이 포함됩니다. 접기 및 스캔 작업은 각 요소에 대해 함수를 호출하는 것과 비슷하 List.iterList.map 지만 이러한 작업은 계산을 통해 정보를 전달하는 누적기 라는 추가 매개 변수를 제공합니다.
목록에서 계산을 수행하는 데 사용합니다 List.fold .
다음 코드 예제에서는 List.fold 를 사용하여 다양한 작업을 수행하는 방법을 보여 줍니다.
목록이 트래버스됩니다. 누적기는 acc 계산이 진행됨에 따라 전달되는 값입니다. 첫 번째 인수는 accumulator 및 list 요소를 사용하고 해당 목록 요소에 대한 계산의 중간 결과를 반환합니다. 두 번째 인수는 누적기의 초기 값입니다.
let sumList list = List.fold (fun acc elem -> acc + elem) 0 list
printfn "Sum of the elements of list %A is %d." [ 1 .. 3 ] (sumList [ 1 .. 3 ])
// The following example computes the average of a list.
let averageList list = (List.fold (fun acc elem -> acc + float elem) 0.0 list / float list.Length)
// The following example computes the standard deviation of a list.
// The standard deviation is computed by taking the square root of the
// sum of the variances, which are the differences between each value
// and the average.
let stdDevList list =
let avg = averageList list
sqrt (List.fold (fun acc elem -> acc + (float elem - avg) ** 2.0 ) 0.0 list / float list.Length)
let testList listTest =
printfn "List %A average: %f stddev: %f" listTest (averageList listTest) (stdDevList listTest)
testList [1; 1; 1]
testList [1; 2; 1]
testList [1; 2; 3]
// List.fold is the same as to List.iter when the accumulator is not used.
let printList list = List.fold (fun acc elem -> printfn "%A" elem) () list
printList [0.0; 1.0; 2.5; 5.1 ]
// The following example uses List.fold to reverse a list.
// The accumulator starts out as the empty list, and the function uses the cons operator
// to add each successive element to the head of the accumulator list, resulting in a
// reversed form of the list.
let reverseList list = List.fold (fun acc elem -> elem::acc) [] list
printfn "%A" (reverseList [1 .. 10])
함수 이름에 숫자가 있는 이러한 함수의 버전은 둘 이상의 목록에서 작동합니다. 예를 들어 List.fold2 는 두 목록에 대해 계산을 수행합니다.
다음 예에서는 List.fold2의 사용법을 보여줍니다.
// Use List.fold2 to perform computations over two lists (of equal size) at the same time.
// Example: Sum the greater element at each list position.
let sumGreatest list1 list2 = List.fold2 (fun acc elem1 elem2 ->
acc + max elem1 elem2) 0 list1 list2
let sum = sumGreatest [1; 2; 3] [3; 2; 1]
printfn "The sum of the greater of each pair of elements in the two lists is %d." sum
List.fold및 List.scan은 추가 매개 변수의 최종 값을 반환하지만 List.scan 추가 매개 변수의 중간 값 목록(최종 값과 함께)을 반환한다는 List.fold 점에서 다릅니다.
이러한 각 함수에는 목록이 트래버스되는 순서와 인수 순서가 다른 역방향 변형(예: List.foldBack)이 포함됩니다.
List.fold
List.foldBack 또한 길이가 같은 두 목록을 사용하는 List.fold2 및 List.foldBack2 변형도 있습니다. 각 요소에서 실행되는 함수는 두 목록의 해당 요소를 사용하여 일부 작업을 수행할 수 있습니다. 다음 예제와 같이 두 목록의 요소 형식은 다를 수 있습니다. 한 목록에는 은행 계좌의 거래 금액이 포함되고 다른 목록에는 입금 또는 인출과 같은 거래 유형이 포함됩니다.
// Discriminated union type that encodes the transaction type.
type Transaction =
| Deposit
| Withdrawal
let transactionTypes = [Deposit; Deposit; Withdrawal]
let transactionAmounts = [100.00; 1000.00; 95.00 ]
let initialBalance = 200.00
// Use fold2 to perform a calculation on the list to update the account balance.
let endingBalance = List.fold2 (fun acc elem1 elem2 ->
match elem1 with
| Deposit -> acc + elem2
| Withdrawal -> acc - elem2)
initialBalance
transactionTypes
transactionAmounts
printfn "%f" endingBalance
합계 List.fold 와 List.foldBack 같은 계산의 경우 결과가 순회 순서에 따라 달라지지 않으므로 동일한 효과를 갖습니다. 다음 예제 List.foldBack 에서는 목록에 요소를 추가하는 데 사용됩니다.
let sumListBack list = List.foldBack (fun elem acc -> acc + elem) list 0
printfn "%d" (sumListBack [1; 2; 3])
// For a calculation in which the order of traversal is important, fold and foldBack have different
// results. For example, replacing fold with foldBack in the listReverse function
// produces a function that copies the list, rather than reversing it.
let copyList list = List.foldBack (fun elem acc -> elem::acc) list []
printfn "%A" (copyList [1 .. 10])
다음 예제는 은행 계좌 예제로 돌아갑니다. 이번에는 새 트랜잭션 유형이 추가됩니다. 이자 계산입니다. 이제 종료 잔액은 트랜잭션 순서에 따라 달라집니다.
type Transaction2 =
| Deposit
| Withdrawal
| Interest
let transactionTypes2 = [Deposit; Deposit; Withdrawal; Interest]
let transactionAmounts2 = [100.00; 1000.00; 95.00; 0.05 / 12.0 ]
let initialBalance2 = 200.00
// Because fold2 processes the lists by starting at the head element,
// the interest is calculated last, on the balance of 1205.00.
let endingBalance2 = List.fold2 (fun acc elem1 elem2 ->
match elem1 with
| Deposit -> acc + elem2
| Withdrawal -> acc - elem2
| Interest -> acc * (1.0 + elem2))
initialBalance2
transactionTypes2
transactionAmounts2
printfn "%f" endingBalance2
// Because foldBack2 processes the lists by starting at end of the list,
// the interest is calculated first, on the balance of only 200.00.
let endingBalance3 = List.foldBack2 (fun elem1 elem2 acc ->
match elem1 with
| Deposit -> acc + elem2
| Withdrawal -> acc - elem2
| Interest -> acc * (1.0 + elem2))
transactionTypes2
transactionAmounts2
initialBalance2
printfn "%f" endingBalance3
List.reduce 함수는 별개의 누적기를 List.reduce 전달하는 대신 요소 형식의 두 인수를 사용하는 함수를 사용하고 이러한 인수 중 하나가 누적기 역할을 하므로 계산의 중간 결과를 저장한다는 점을 제외하면 다소 유사 List.foldList.scan합니다.
List.reduce 는 처음 두 목록 요소에서 작업한 다음 다음 요소와 함께 작업의 결과를 사용합니다. 자체 형식이 있는 별도의 누적기는 없으므로 누적기 및 요소 형식 List.reduce 의 List.fold 형식이 같은 경우에만 대신 사용할 수 있습니다. 다음 코드는 .의 List.reduce사용을 보여 줍니다.
List.reduce 는 제공된 목록에 요소가 없는 경우 예외를 throw합니다.
다음 코드에서 람다 식에 대한 첫 번째 호출에는 인수 2와 4가 지정되고 6이 반환되고 다음 호출에는 인수 6과 10이 주어지므로 결과는 16입니다.
let sumAList list =
try
List.reduce (fun acc elem -> acc + elem) list
with
| :? System.ArgumentException as exc -> 0
let resultSum = sumAList [2; 4; 10]
printfn "%d " resultSum
목록과 다른 컬렉션 형식 간 변환
이 모듈은 List 시퀀스와 배열을 변환하는 함수를 제공합니다. 시퀀스로 또는 시퀀스에서 변환하려면 List.toSeq 또는 List.ofSeq를 사용합니다. 배열로 또는 배열에서 변환하려면 List.toArray 또는 List.ofArray를 사용합니다.
추가 작업
목록에 대한 추가 작업에 대한 자세한 내용은 라이브러리 참조 항목 목록 모듈을 참조하세요.
참고하십시오
.NET