Тип Map в языке F# представляет словарь, где каждый элемент имеет ключ и связанное с ним значение.
Для определения словаря применяются квадратные скобки [], в которых располагаются элементы словаря:
let dict = Map["red", "красный"; "blue", "синий"; "green", "зеленый"]
Здесь определен словарь, который называется dict
. Чтобы указать, что создается словарь, перед квадратными скобками указывается название типа -
Map
Каждый элемент словаря определяется в виде:
ключ, значение
То есть сначала идет ключ и через запятую значение. Например, первый элемент словаря:
"red", "красный"
Здесь ключом выступает строка "red", а значением - строка "красный".
Если элементы размещаются на одной строке, то они отделяется друг от друга точкой с запятой. Если элементы размещены по отдельности на разных строках, тогда не требуется разделять их точкой с запятой:
let dict = Map[ "red", "красный" "blue", "синий" "green", "зеленый" ]
По умолчанию тип элементов словаря выводится из значений, которыми инициализируется словарь. Но также можно указать тип словаря явным образом:
let dict: Map<string, string> = Map[] // Map<тип_ключей, тип_значений>
В угловых скобках после названия типа Map указываем тип ключей и тип значений элементов. То есть в данном случае тип ключей - string
и тип значений тоже
string
.
Явное указание типа может быть полезно, когда надо создать пустой словарь, соответственно компилятор не сможет неявно вывести тип ключей и значений.
Другой пример:
let letters: Map<string, int> = Map["a", 1; "b", 2; "c", 3]
Здесь словарь letters с качестве типа ключей использует тип string
, а в качестве типа значений - int
Тип Map определяет ряд свойств:
Count: количество элементов в словаре
Keys: возвращает список ключей словаря
Values: возвращает список значений словаря
IsEmpty: возвращает true
, если в словаре нет элементов
Применение свойств:
let dict = Map["red", "красный"; "blue", "синий"; "green", "зеленый"] printfn "Count: %d" dict.Count // Count: 3 printfn "IsEmpty: %b" dict.IsEmpty // IsEmpty: false printfn "Keys: %A" dict.Keys // Keys: seq ["blue"; "green"; "red"] printfn "Values: %A" dict.Values // Values: seq ["синий"; "зеленый"; "красный"]
Для получения значения элемента из словаря применяется следующий синтаксис:
словарь[ключ]
После имени словаря в квадратных скобках указывается ключ. Например:
let dict = Map["red", "красный"; "blue", "синий"; "green", "зеленый"] printfn "red: %s" dict["red"] // red: красный
Однако этот способ имеет недостаток: если переданного ключа нет в словаре, то генерируется исключение. В этом случае можно использовать метод
TryFind. Он принимает ключ и возвращает значение по этому ключу Поскольку такого ключа может и не быть в словаре,
то возвращается в реальности не сам элемент, а его обертка в виде объекта Option
. С помощью свойства Value можно получить значение.
let dict = Map["red", "красный"; "blue", "синий"; "green", "зеленый"] let printOption option = match option with | Some value -> printfn $"{value}" | None -> printfn "Не найдено" let result1 = dict.TryFind "red" printOption result1 // красный let result2 = dict.TryFind "yellow" printOption result2 // Не найдено
В первом случае ищем в словаре значение по ключу "red", а во втором случае - по ключу "yellow". Для вывода результата определяем функцию printOption, которая получает объект Option и с помощью конструкции match сопоставляет его с двумя паттернами - Some и None. Если элемент найден, тогда объект option успешно сопоставляется с Some, а его значение помещается в переменную value:
match option with | Some value -> printfn $"{value}"
Аналогично работает функция Map.tryFind:
let dict = Map["red", "красный"; "blue", "синий"; "green", "зеленый"] let printOption option = match option with | Some value -> printfn $"{value}" | None -> printfn "Не найдено" let result1 = Map.tryFind "red" dict printOption result1 // красный let result2 = Map.tryFind "yellow" dict printOption result2 // Не найдено
Для перебора элементов словаря можно использовать цикл for..in:
let dict = Map["red", "красный"; "blue", "синий"; "green", "зеленый"] for word in dict do printfn "%s: %s" word.Key word.Value
При переборе словаря мы получаем объект, у которого с помощью свойства Key можно получить ключ, а с помощью свойства Value - значение.
Также для перебора можно использовать функцию Map.iter. Эта функция принимает два параметра. Первый параметр - функция, которая выполняется для каждого элемента словаря. Второй параметр - сам перебираемый словарь:
let dict = Map["red", "красный"; "blue", "синий"; "green", "зеленый"] Map.iter (fun key value -> printfn "Перевод слова %s: %s" key value) dict
В функцию Map.iter
передается функция, которая через два параметра получает ключ и значение каждого элемента словаря.
С помощью функции Array.filter можно отфильтровать элементы словаря в сответствии с некоторым условием. Функция возвращает новый словарь, которая содержит только те элементы, которые соответствуют этому условию.
Первый параметр функции - функция условия, а второй параметр - фильтруемый словарь
let people = [|"Tom"; "Alice"; "Sam"; "Kate"; "Bob"|] let result = Array.filter (fun (p:string) -> p.Length = 3) people printfn "%A" people // [|"Tom"; "Sam"; "Bob"|]
В данном случае получаем в новый словарь из исходного словаря все строки, длина которых равна 3 символам.
Метод ContainsKey() позволяет проверить, есть ли в словаре элемент с определенным ключом. При наличии такого элемента возвращается true
, иначе возвращается false
:
let dict = Map["red", "красный"; "blue", "синий"; "green", "зеленый"] printfn "Есть ли слово `red`: %b" (dict.ContainsKey "red") printfn "Есть ли слово `yellow`: %b" (dict.ContainsKey "yellow")
F# позволяет изменять содержимое словаря. Однако поскольку словарь - неизменяемая структура данных, то изначальный словарь остается неизменнным, вместо этого операции возвращают новую измененную копию словаря.
Метод Add() возвращает копию словаря, в которую добавляется новый элемент. Данному методу передается кортеж, первое значение в котором представляет ключ, а второе - значение:
let dict = Map["red", "красный"; "blue", "синий"; "green", "зеленый"] let newDict = dict.Add ("yellow", "желтый") printfn "%A" newDict // консольный вывод // map [("blue", "синий"); ("green", "зеленый"); ("red", "красный"); ("yellow", "желтый")]
Аналогично работает функция Map.add:
let dict = Map["red", "красный"; "blue", "синий"; "green", "зеленый"] let newDict = Map.add "yellow" "желтый" dict
Метод Remove() возвращает копию словаря, из которой удаляется элемент с определенным ключом:
let dict = Map["red", "красный"; "blue", "синий"; "green", "зеленый"] let newDict = dict.Remove "blue" printfn "%A" newDict // консольный вывод // map [("green", "зеленый"); ("red", "красный")]
Аналогично работает функция Map.remove:
let dict = Map["red", "красный"; "blue", "синий"; "green", "зеленый"] let newDict = Map.remove "blue" dict
Метод Change() возвращает копию словаря, в которой изменен элемент с определенным ключом:
let dict = Map["red", "красный"; "blue", "синий"; "green", "зеленый"] let newDict = dict.Change ("red", (fun item -> match item with | Some -> Some ("алый") | None -> None )) printfn "%A" newDict // консольный вывод // map [("blue", "синий"); ("green", "зеленый"); ("red", "алый")]
Метод Change()
получает кортеж, в котором первое значение - ключ изменяемого элемента, а второе значение - функция изменения.
Поскольку запрошенного ключа, по которому мы хотим изменить значение, может не оказаться, то в эту функцию передается объект Option. Если ключ есть в словаре, то его можно получить
через значение Some и также через Some можно установить новое значение. В данном случае меняем для ключа "red" значение на "алый"
Аналогично работает функция Map.change:
let dict = Map["red", "красный"; "blue", "синий"; "green", "зеленый"] let newDict = dict |> Map.change "red" (fun item -> match item with | Some s -> Some ("алый") | None -> None) printfn "%A" newDict // консольный вывод // map [("blue", "синий"); ("green", "зеленый"); ("red", "алый")]