如何在 F# 中创建一个遍历 JSON 的 for 循环
How do I make a for loop that scans through JSON in F#
我正在尝试使用 F# 扫描 JSON 文件并将其数组与单个(随机生成的)数字数组进行比较。 json 的格式为:
{"1":[#,#,#,#,#],"2":[#,#,#,#,#],...}
等 121 个条目。我目前正在尝试 Json.NET。我的问题是:
如何使用 Json.NET 导入本地文件?
我将如何着手对 json 键进行简单调用,return 它是适合 运行 的数组值,通过 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 文档 Deserialize a Dictionary, such a JSON object can be deserialized to some IDictionary<string, T>
for appropriate value type T
. And as explained in Deserialize a Collection 中所述,JSON 数组可以反序列化为适当项目类型的集合。
在 f# 中,我们使用 Map<'Key,'Value>
to represent a dictionary, and lists 来表示静态类型值的物化列表。因此,您的 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]
备注:
始终确保处理 disposable resources such as StreamReader
after you are done with them. The 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
正如 Don Syme 在 Equality and Comparison Constraints in F# 中所解释的,list
和 set
都支持结构相等比较,这这就是为什么 requiredValues = value
检查集合是否具有相同的 contents.
我正在尝试使用 F# 扫描 JSON 文件并将其数组与单个(随机生成的)数字数组进行比较。 json 的格式为:
{"1":[#,#,#,#,#],"2":[#,#,#,#,#],...}
等 121 个条目。我目前正在尝试 Json.NET。我的问题是:
如何使用 Json.NET 导入本地文件?
我将如何着手对 json 键进行简单调用,return 它是适合 运行 的数组值,通过 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 文档 Deserialize a Dictionary, such a JSON object can be deserialized to some IDictionary<string, T>
for appropriate value type T
. And as explained in Deserialize a Collection 中所述,JSON 数组可以反序列化为适当项目类型的集合。
在 f# 中,我们使用 Map<'Key,'Value>
to represent a dictionary, and lists 来表示静态类型值的物化列表。因此,您的 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]
备注:
始终确保处理 disposable resources such as
StreamReader
after you are done with them. Theuse
关键字以确保在资源超出范围时自动发生这种情况。如果您希望搜索 无序集合 值,您可以使用
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
正如 Don Syme 在 Equality and Comparison Constraints in F# 中所解释的,
list
和set
都支持结构相等比较,这这就是为什么requiredValues = value
检查集合是否具有相同的 contents.