f # является языком со статической типизацией - мы просто часто этого не замечаем из-за его превосходного вывода типа. Но при десериализации из файла JSON перед написанием любого кода полезно определить, имеет ли JSON фиксированную схему, и, если это так, создать или выбрать подходящую модель данных, в которую можно отобразить JSON автоматически.
В вашем случае ваш JSON выглядит следующим образом:
{
"1": [29,30,41,48,64],
"2": [29,320,441,548,11]
// Additional items omitted
}
Когда у вас есть объект root с именами переменных, значения которых всегда являются массивом целых чисел , Как объяснено в документации Newtonsoft Десериализация словаря , такой JSON объект может быть десериализован до некоторого IDictionary<string, T>
для соответствующего типа значения T
. И как объяснено в Десериализация коллекции массив JSON может быть десериализован в коллекцию соответствующего типа элемента.
В f # мы используем Map<'Key,'Value>
для представления словаря и списки для представления материализованного списка статически типизированных значений. Таким образом, ваш JSON соответствует
Map<string, int list>
Определив соответствующую модель данных, введите следующую функцию для десериализации JSON из файла:
//https://www.newtonsoft.com/json/help/html/DeserializeWithJsonSerializerFromFile.htm
let jsonFromFile<'T>(fileName : string, settings : JsonSerializerSettings) =
use streamReader = new StreamReader(fileName)
use jsonReader = new JsonTextReader(streamReader)
let serializer = JsonSerializer.CreateDefault(settings)
serializer.Deserialize<'T>(jsonReader)
Теперь вы можете десериализовать ваш JSON и отфильтруйте значения для списков, соответствующих некоторым
let fileName = "\PATH\powernum.json"
let requiredValues = [29;30;41;48;64] // Or whatever list of values you are looking for
let map = jsonFromFile<Map<string, int list>>(fileName, null)
let filteredMap =
map |> Map.toSeq
|> Seq.filter (fun (key, value) -> requiredValues = value)
|> Map.ofSeq
// Print results
filteredMap |> Map.iter (fun key value ->
printf "Key = %A has matching list of values = %A\n" key value)
, которые распечатывают
Key = "1" has matching list of values = [29; 30; 41; 48; 64]
Примечания:
Всегда будьте уверены распоряжаться одноразовыми ресурсами, такими как StreamReader
, после того, как с ними покончено. Ключевое слово use
гарантирует, что это происходит автоматически, когда ресурс выходит из области видимости.
Если вы предпочитаете искать неупорядоченный набор значений, вы можете использовать set
вместо list
:
let requiredValues = set [64;29;30;41;48] // Or whatever set of values you are looking for
let map = jsonFromFile<Map<string, Set<int>>>(fileName, null)
let filteredMap =
map |> Map.toSeq
|> Seq.filter (fun (key, value) -> requiredValues = value)
|> Map.ofSeq
Как объяснено в Ограничения равенства и сравнения в F # Дона Сайма оба list
и set
поддерживают сравнения структурного равенства, поэтому requiredValues = value
проверяет, что коллекции имеют идентичное содержимое .
Демонстрационная скрипка # 1 здесь для list
и # 2 здесь для set
.