Как мне сделать для l oop, который просматривает JSON в F # - PullRequest
0 голосов
/ 18 апреля 2020

Используя F # Я пытаюсь просмотреть файл JSON и сравнить его массивы с одним массивом (случайно сгенерированных) чисел. Формат для json:

{"1":[#,#,#,#,#],"2":[#,#,#,#,#],...}

et c для 121 записи. Я сейчас пытаюсь Json. NET. Мои проблемы:

  • Как я могу импортировать локальный файл с помощью Json. NET?

  • Как мне начать делать простой вызов клавиши json, которая возвращает его значение массива, подходящее для его запуска через a для l oop?

Вот мой код того, как далеко я Вы получили:

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 #, но из того, что я нашел, невозможно сделать итерацию l oop, потому что я должен нажать на «ключ» с акцентами, инкапсулирующих число, чтобы прочитать его как 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())

1 Ответ

3 голосов
/ 18 апреля 2020

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.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...