我如何在F#中制作一个for循环来扫描JSON。
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了我如何在F#中制作一个for循环来扫描JSON。相关的知识,希望对你有一定的参考价值。
使用F#我试图扫描一个JSON文件,并将其数组与一个(随机生成的)数字数组进行比较。json的格式是:
{"1":[#,#,#,#,#],"2":[#,#,#,#,#],...}
等121个条目。 我目前正在尝试使用Json.NET。 我的问题是
我如何用Json.NET导入一个本地文件?
我如何设置对json key进行简单的调用,返回适合在for循环中运行的数组值?
这是我的代码,我已经做到了这一点。
open System
open System.IO
open Newtonsoft.Json
(*open FSharp.Data
type Provider = JsonProvider<"powernum.json">
let numbers = Provider.Load("powernum.json")
//numbers.``1`` gets me the array but can't scan through all the IDs with an iterating for loop
(*
if numbers.``3`` = [|29;30;41;48;64|] then
printfn "True"
else printfn "False"
*)
(*numbers.JsonValue.Item "1"
let test (a: int) = string a
let testPile =
for i = 1 to 10 do
let goNum = numbers.JsonValue.Item (test i)
Console.Write goNum
Console.WriteLine ""
testPile // This works but is not usable for data comparison with an F# Array
*)
*)
let r = new StreamReader("\PATH\powernum.json")
let (json: string) = r.ReadToEnd();
let conv = JsonConvert.DeserializeObject<> (json)
Console.WriteLine("{0}",conv)//where I'm stuck with Json.NET
[<EntryPoint>]
let main argv =
let rnd = Random()
let numberGen = Set.empty.Add(rnd.Next(1,69)).Add(rnd.Next(1,69)).Add(rnd.Next(1,69)).Add(rnd.Next(1,69)).Add(rnd.Next(1,69)) |>Set.toArray |>Array.sort
Console.ReadKey() |> ignore
0// return an integer exit code
Jsontocsharp.com无效。
我试过使用F# Data,但根据我的发现,不可能做一个迭代循环,因为我必须把 "key "用重音封装的数字拉起来,像这样把它读成一个int。numbers.``1``
.它不接受变量。在仍然使用F# Data的情况下,尝试了另一种方法,但它只能作为一个字符串工作,当我试图转换它时,它会出错。
为了比较,这是我在python中原型的版本。
import random
import json
with open('/PATH/powernum.json') as pnumbers:
data = json.load(pnumbers)
#makes an array with the range of numbers
Valid_numbers =[]
for x in range(69):
Valid_numbers.append(x+1)
generated = []
def pulledNumber():
generated[:]=[]
#adds numbers to the array from 0-4
while len(generated) !=5:
#takes a random number from the range of numbers
generate_number = random.choice(Valid_numbers)
#check if the two arrays have the same values
if generate_number not in generated:
#add to the array if values don't match
generated.append(generate_number)
generated.sort()
return generated
pulledNumber()
for x, y in data.items():
if generated not in y:
print("Id: %s passed" % x)
else:
print("Id: %s failed" % x)
pulledNumber()
break
print (pulledNumber())
f#是一种静态类型的语言--由于它出色的类型推断,我们只是经常没有注意到。 但是当从JSON文件中反序列化时,在编写任何代码之前,确定JSON是否有固定的模式是很有用的,如果有的话,创建或选择一个合适的数据模型,JSON可以自动映射到这个模型。
在你的案例中,你的JSON看起来是这样的。
{
"1": [29,30,41,48,64],
"2": [29,320,441,548,11]
// Additional items omitted
}
当你在这里有一个根对象 与变量属性名 其值总是一个整数组。 正如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
.
以上是关于我如何在F#中制作一个for循环来扫描JSON。的主要内容,如果未能解决你的问题,请参考以下文章
如何在 Python 中没有任何循环(例如:for、while 等)递归 JSON 文件