次の方法で共有


リスト

F# のリストは、同じ型の順序付けされた変更できない一連の要素です。 リストに対して基本的な操作を実行するには、 List モジュールの関数を使用します。

リストの作成と初期化

次のコード行に示すように、要素をセミコロンで区切り、角かっこで囲んで明示的に一覧表示することで、リストを定義できます。

let list123 = [ 1; 2; 3 ]

要素間に改行を配置することもできます。この場合、セミコロンは省略可能です。 後者の構文では、要素の初期化式が長い場合や、各要素のコメントを含める場合に、読みやすいコードが生成される可能性があります。

let list123 = [ 1; 2; 3 ]

通常、すべてのリスト要素は同じ型である必要があります。 例外として、基本型として要素が指定されているリストには、派生型の要素を含めることができます。 したがって、 ButtonCheckBox の両方が Controlから派生するため、次の値を使用できます。

let myControlList: Control list = [ new Button(); new CheckBox() ]

次のコードに示すように、範囲演算子 (..) で区切られた整数で示される範囲を使用して、リスト要素を定義することもできます。

let list1 = [ 1..10 ]

空のリストは、その間に何も入っていない角かっこのペアによって指定されます。

// An empty list.
let listEmpty = []

シーケンス式を使用してリストを作成することもできます。 詳細については、「 シーケンス式」 を参照してください。 たとえば、次のコードは、1 から 10 までの整数の 2 乗のリストを作成します。

let listOfSquares = [ for i in 1..10 -> i * i ]

リストを操作するための演算子

:: (cons) 演算子を使用して、リストに要素をアタッチできます。 list1[2; 3; 4]場合、次のコードは[100; 2; 3; 4]としてlist2を作成します。

let list2 = 100 :: list1

次のコードのように、 @ 演算子を使用して、互換性のある型を持つリストを連結できます。 list1[2; 3; 4]され、list2[100; 2; 3; 4]場合、このコードは[2; 3; 4; 100; 2; 3; 4]としてlist3を作成します。

let list3 = list1 @ list2

リストに対して操作を実行するための関数は、 List モジュールで使用できます。

F# のリストは不変であるため、変更操作では既存のリストを変更する代わりに新しいリストが生成されます。

F# のリストは、単一のリンクリストとして実装されます。つまり、リストの先頭にのみアクセスする操作は O(1)、要素アクセスは O(n) です。

プロパティ

リストの種類では、次のプロパティがサポートされています。

プロパティ タイプ 説明
Head 'T 最初の要素。
'T list 適切な型の空のリストを返す静的プロパティ。
IsEmpty bool true リストに要素がない場合は 。
アイテム '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関数は、2 つのリストを受け取る再帰関数です。 最初のリストには、倍数が削除される数値が含まれ、2 番目のリストは番号を削除するリストです。 次の例のコードでは、この再帰関数を使用して、リストからすべての非素数を削除し、素数のリストを結果として残しています。

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]

モジュール関数

List モジュールには、リストの要素にアクセスする関数が用意されています。 ヘッド要素は、最も高速で簡単にアクセスできます。 プロパティ Head またはモジュール関数 List.head を使用します。 Tail プロパティまたは List.tail 関数を使用して、リストの末尾にアクセスできます。 インデックスで要素を検索するには、 List.nth 関数を使用します。 List.nth はリストを走査します。 したがって、O(n) です。 コードで List.nth を頻繁に使用する場合は、リストではなく配列を使用することを検討してください。 配列内の要素アクセスは O(1) です。

リストに対するブール演算

List.isEmpty 関数は、リストに要素があるかどうかを判断します。

List.exists 関数は、リストの要素にブール型テストを適用し、いずれかの要素がテストを満たす場合はtrueを返します。 List.exists2 は似ていますが、2 つのリスト内の要素の連続するペアで動作します。

次のコードは、 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 は、2 つのリスト内の対応する位置にあるすべての要素が、要素の各ペアを含むブール式を満たすかどうかを判断します。

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.sortList.sortBy、および List.sortWith 関数の並べ替えリスト。 並べ替え関数は、これら 3 つの関数のうちどれを使用するかを決定します。 List.sort では、既定のジェネリック比較が使用されます。 ジェネリック比較では、ジェネリック比較関数に基づくグローバル演算子を使用して値を比較します。 単純な数値型、タプル、レコード、判別共用体、リスト、配列、 System.IComparableを実装する任意の型など、さまざまな要素型で効率的に動作します。 System.IComparableを実装する型の場合、ジェネリック比較ではSystem.IComparable.CompareTo()関数が使用されます。 ジェネリック比較は文字列でも機能しますが、カルチャに依存しない並べ替え順序を使用します。 ジェネリック比較は、関数型など、サポートされていない型では使用しないでください。 また、既定のジェネリック比較のパフォーマンスは、小規模な構造化型に最適です。比較して頻繁に並べ替える必要がある大規模な構造化型の場合は、 System.IComparable を実装し、 System.IComparable.CompareTo() メソッドの効率的な実装を提供することを検討してください。

List.sortBy は、並べ替え条件として使用される値を返す関数を受け取り、 List.sortWith は比較関数を引数として受け取ります。 後者の 2 つの関数は、比較をサポートしない型を使用する場合や、カルチャに対応した文字列の場合と同様に、比較にさらに複雑な比較セマンティクスが必要な場合に便利です。

次の例では、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 を使用すると、特定の条件に一致する最初の要素を見つけることができます。

次のコード例は、 List.find を使用して、リスト内で 5 で割り切れる最初の数値を検索する方法を示しています。

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.pickSystem.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 モジュールに組み込まれています。 List.sum を操作するには、list 要素の型が + 演算子をサポートし、値が 0 である必要があります。 すべての組み込み算術型は、これらの条件を満たしている。 List.average を使用するには、要素型で剰余のない除算をサポートする必要があります。これは整数型を除外しますが、浮動小数点型を使用できます。 List.sumBy 関数と List.averageBy 関数はパラメーターとして関数を受け取り、この関数の結果を使用して合計または平均の値を計算します。

次のコードは、 List.sumList.sumBy、および List.averageの使用方法を示しています。

// 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 関数と解凍関数で操作できます。 これらの関数は、単一値の 2 つのリストをタプルの 1 つのリストに結合するか、タプルの 1 つのリストを 1 つの値の 2 つのリストに分割します。 最も単純な List.zip 関数は、単一の要素の 2 つのリストを受け取り、タプル ペアの 1 つのリストを生成します。 別のバージョン の List.zip3 は、3 つの要素のリストを受け取り、3 つの要素を持つタプルの 1 つのリストを生成します。 次のコード例は、 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)]

対応する解凍バージョン の List.unzipList.unzip3 は、タプルのリストを取得し、タプル内のリストを返します。最初のリストには各タプルの最初の要素がすべて含まれており、2 番目のリストには各タプルの 2 番目の要素が含まれます。

次のコード例は、 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.iter2 が含まれます。 List.iteri という 2 つのリストの要素に対して操作を実行できます。これは、各要素のインデックスが各要素に対して呼び出される関数に引数として渡される点を除き、 List.iter に似ています。 List.iteri2 は、 List.iter2List.iteriの機能の組み合わせです。 次のコード例は、これらの関数を示しています。

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

リスト要素を変換するもう 1 つの頻繁に使用される関数は List.map です。これにより、リストの各要素に関数を適用し、すべての結果を新しいリストに配置できます。 List.map2List.map3 は、複数のリストを取得するバリエーションです。 また、 List.mapiList.mapi2 を使用することもできます。要素に加えて、各要素のインデックスを渡す必要がある場合は、この関数を使用します。 List.mapi2List.mapiの唯一の違いは、List.mapi2が 2 つのリストで動作する点です。 次の例は 、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.collectList.mapに似ていますが、各要素によってリストが生成され、これらすべてのリストが最終的なリストに連結される点が異なります。 次のコードでは、リストの各要素が 3 つの数値を生成します。 これらはすべて 1 つのリストに収集されます。

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"]

複数のリストでの操作

リストは一緒に結合できます。 2 つのリストを 1 つに結合するには、 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 は、計算が進むにつれて渡される値です。 最初の引数はアキュムレータとリスト要素を受け取り、そのリスト要素の計算の中間結果を返します。 2 番目の引数はアキュムレータの初期値です。

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 は 2 つのリストに対して計算を実行します。

次の例では、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.foldが余分なパラメーターの最終的な値を返す点で異なりますが、List.scanは、追加のパラメーターの中間値の一覧と共に (最終値と共に) 返します。

これらの各関数には、リストが走査される順序と引数の順序が異なる逆のバリエーション ( List.foldBack など) が含まれています。 また、 List.foldList.foldBack には、同じ長さの 2 つのリストを受け取るバリエーション List.fold2List.foldBack2 があります。 各要素で実行される関数は、両方のリストの対応する要素を使用して何らかのアクションを実行できます。 次の例のように、2 つのリストの要素の種類は異なる場合があります。一方のリストには銀行口座の取引金額が含まれ、もう一方のリストには取引の種類 (入金または出金) が含まれています。

// 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.foldList.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.foldList.scanに似ていますが、別のアキュムレータを渡す代わりに、List.reduceは 1 つではなく要素型の 2 つの引数を受け取る関数を受け取り、それらの引数の 1 つがアキュムレータとして機能し、計算の中間結果を格納することを意味します。 List.reduce 最初の 2 つのリスト要素で操作を開始し、次の要素と共に操作の結果を使用します。 独自の型を持つ独立したアキュムレータがないため、アキュムレータと要素型が同じ型である場合にのみ、List.foldの代わりにList.reduceを使用できます。 次のコードは、 List.reduceの使用方法を示しています。 List.reduce 指定されたリストに要素がない場合、例外がスローされます。

次のコードでは、ラムダ式の最初の呼び出しには引数 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 を使用します。

その他の操作

リストに対する追加操作の詳細については、ライブラリー・リファレンス・トピック 「リスト・モジュール」を参照してください。

こちらも参照ください