2016-03-02 1 views
2

В моей миссии по овладению F # Я создаю карманную игру. Я нахожусь в точке, где я хочу реализовать какой-то список рекордов.Q: F #: Итерировать через файл рекорда и выбрать верх 3

До сих пор я пишу Имя, оценка и Время в файл, который затем читает в приложение, где отображаются все предыдущие оценки. Да, это не идеально, так как список растет довольно быстро.

Я несколько хочу, чтобы выбрать лучшие 3 баллов, не заботясь о Имя или времени.

Вопрос: Должен ли я прочитать файл в массиве/списке и оттуда выбрать верхние баллы или есть лучший способ выбрать верхние баллы непосредственно из файла?

Указатели, коды, советы и рекомендации приветствуются.

let scoreFile = sprintf ("Name: %s\nTime: %i sec\nScore: %d\n\n") name stopWatch.Elapsed.Seconds finalScore 
let readExistingFile = File.ReadAllText ("hiscore.txt") 
File.WriteAllText ("hiscore.txt", scoreFile + readExistingFile) 
let msg = File.ReadAllText ("hiscore.txt") 
printfn "\nHighscores:\n\n%s\n\n\n\nPress ANY key to quit." msg 
+2

Вы можете просто сохранить только 3-е (или, может быть, несколько дополнительных), вместо того, чтобы хранить все высокие баллы. Просто прочитайте весь файл и напишите заменяющий файл с текущими топ-3 баллами. –

ответ

1

Должен ли я прочитать файл в массиве/список, а оттуда выбрать лучшие результаты или есть лучше способ выбрать лучшие результаты непосредственно из файла?

Если оценки уже не отсортированы по файлу, вам нужно будет просмотреть их все, чтобы узнать, что такое Top 3. Способ записи вашего файла прямо сейчас, разбор данных обратно может быть немного сложным - баллы хранятся на нескольких строках, поэтому вам придется это обработать.

Предполагая, что файл не должен быть удобным для людей, я бы выбрал вместо него список значений, разделенных запятыми. Человеку труднее читать, открывая файл, но это упрощает анализ в вашей программе .. Например, если линии выглядят Name,Time,Score, они могут быть разобраны, как это:

type ScoreData = { 
    Name : string 
    Time : string // could be a DateTime, using string for simplicity 
    Score : int 
} 

let readHighScores file = 
    File.ReadAllLines file 
    |> Array.choose (fun line -> 
     match line.Split ',' with 
     | [| name; time; score |] -> 
      { 
       Name = name 
       Time = time 
       Score = (int)score // This will crash if the score isn't an integer - see paragraph below. 
      } 
      |> Some 
     | _ -> 
      // Line doesn't match the expected format, we'll just drop it 
      None 
    ) 
    |> Array.sortBy (fun scoreData -> -scoreData.Score) // Negative score, so that the highest score comes first 
    |> Seq.take 3 

Это будет прочитать файл и вывод из трех крупнейших баллов. Использование Array.choose позволяет сохранять строки только в том формате, который вы ожидаете. Это также позволяет вам добавить дополнительную проверку по мере необходимости, например, чтобы убедиться, что оценка является целым числом и, возможно, разобрав Время в System.DateTime вместо того, чтобы хранить его как int.

Вы можете распечатать свои лучшие результаты, делая что-то вроде этого:

let highScores = readHighScores "hiscore.txt" 
printfn "High scores:" 
highScores 
|> Seq.iteri (fun index data -> 
    printfn "#%i:" (index + 1) 
    printfn " Name: %s" data.Name 
    printfn " Time: %s" data.Time 
    printfn " Score: %i" data.Score 
) 

Это вызывает ранее определенную функцию и печатает каждый из счетов, возвращенных - топ 3, в этом случае. Используя Seq.iteri, вы можете включить индекс в результат в дополнение к самим данным оценки. Используя некоторые данные, которые я сделал вверх, он заканчивает тем, как это:

High scores: 
#1: 
    Name: Awots 
    Time: 2015-06-15 
    Score: 2300 
#2: 
    Name: Roujo 
    Time: 2016-03-01 
    Score: 2200 
#3: 
    Name: Awots 
    Time: 2016-03-02 
    Score: 2100 

Теперь, может быть способ сделать это без загрузки всего файла сразу в памяти, но я не думаю, что было бы стоит того, если у вас действительно большой файл, и в этом случае вам может потребоваться сортировка или использование более подходящего метода хранения, например базы данных.

+1

Вау, я не мог попросить лучшего ответа. Престижность вам, Ружо, действительно! Это было для меня огромным открытием. Спасибо вам за то, что вы потратили время и силы! Просто хотелось указать, что время - это время, прошедшее в игре, так как мой план заключается в том, чтобы реализовать разные временные рамки, т.е. 10 секунд, 30 секунд или 60 секунд. – Awots

+1

@Awots Ahhh, понял. Похоже, он был там, в коде, который вы отправили, - я пропустил его в первый раз, извините.^_ ^ – Roujo

Смежные вопросы