首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >Hackerrank:打破记录

Hackerrank:打破记录
EN

Code Review用户
提问于 2020-10-22 14:38:47
回答 1查看 231关注 0票数 5

我正在学习Clojure,并且是一名排名较高的n00b,试图从书籍和在线教程中学习(但有时我担心我正在养成坏习惯,或者至少不是所有的好习惯)。在练习中,我在Hackerrank上做了打破纪录问题。

TL;DR问题描述:

For一个分数列表(按历史顺序排列),计算以前最好的分数被超过的次数,以及以前最差的分数被低估的次数。

在迭代语言中,使用只需遍历列表非常容易;但是Clojure不执行迭代,我决定在构造(尾部)递归解决方案时解决这个问题。为了让自己更容易,我首先用Java做了一个递归解决方案,然后我翻译了这个解决方案。总之,这是一个非常简单的递归函数,而不涉及火箭手术。

显然,我的代码可以工作,如包含的单元测试所示。不过,我所关注的事项如下:

  • 当放在Java代码旁边时,两者看起来非常相似。我是遵循“熟能生巧”的Clojure编程,还是只是笨拙的“逐字音译”?
  • 通过使用不同的Clojure构造,是否有更紧凑和/或更容易理解的区域?

您的关键输入将受到高度赞赏--关于单元测试的<#>including,因为这可以说是编程的一个重要部分,我想并行学习和实践。

代码:

代码语言:javascript
运行
复制
(ns hackerrank.breaking-records
  (:require [clojure.test :refer :all]))

(defrecord Record [min max countworse countbetter])

(defn recalc-record [rec newscore]
  (Record.
    (min newscore (:min rec))
    (max newscore (:max rec))
    (+ (:countworse rec) (if (> (:min rec) newscore) 1  0))
    (+ (:countbetter rec) (if (< (:max rec) newscore) 1  0))))

(defn accumulate [curr-record remaining-scores]
  (if (nil? (second remaining-scores))
    curr-record
    (recur (recalc-record curr-record (second remaining-scores)) (rest remaining-scores)))
)

(defn breaking-records [scores]
  (let [result (accumulate (Record. (first scores) (first scores) 0 0) scores)]
    (list (:countbetter result) (:countworse result))))

(deftest test-records
  (testing "edge cases"
    (is (= '(0 0) (breaking-records '())) "no games played yet")
    (is (= '(0 0) (breaking-records '(5))) "single game"))
  (testing "hackerrank examples"
    (is (= '(2 4) (breaking-records '(10 5 20 20 4 5 2 25 1))))
    (is (= '(4 0) (breaking-records '(3 4 21 36 10 28 35 5 24 42)))))
)
EN

回答 1

Code Review用户

回答已采纳

发布于 2020-10-22 19:14:10

我重写了您的解决方案,以使用更典型的Clojure特性。当您正在遍历数据并需要跟踪累积状态时,很难超过loop/recur。第一个例子是:

代码语言:javascript
运行
复制
(ns tst.demo.core
  (:use clojure.test))

(defn breaking-records
  [scores]
  ; this loop has 5 variables. Init all of them
  (loop [low         (first scores)
         high        (first scores)
         nworse      0
         nbetter     0
         score-pairs (partition 2 1 scores)]
    (if (empty? score-pairs)
      {:nbetter nbetter :nworse nworse}
      (let [curr-score-pair (first score-pairs)
            new-score       (second curr-score-pair)]
        ; start the next iteration with modified versions of the 5 loop vars
        (recur
          (min new-score low)
          (max new-score high)
          (if (< new-score low)
            (inc nworse)
            nworse)
          (if (< high new-score)
            (inc nbetter)
            nbetter)
          (rest score-pairs))))))

和单元测试:

代码语言:javascript
运行
复制
(deftest test-records
  (testing "edge cases"
    (is (= (breaking-records []) {:nbetter 0 :nworse 0}) "no games played yet")
    (is (= (breaking-records [5]) {:nbetter 0 :nworse 0}) "single game"))
  (testing "hackerrank examples"
    (is (= (breaking-records [10 5 20 20 4 5 2 25 1]) {:nbetter 2 :nworse 4}))
    (is (= (breaking-records [3 4 21 36 10 28 35 5 24 42]) {:nbetter 4 :nworse 0}))))

; ***** NOTE: it's much easier to use vectors like [1 2 3] instead of a quoted list `(1 2 3)

请见这份文件清单 (尤指)。Clojure CheatSheet。此外,模板项目作为一个整体展示了我是如何构造事物的。:)

帮助最大的函数是partition看医生

轻微重构

您可以通过使用更专门的函数(如reducecond-> )来简化它,并使其更加紧凑。此版本使用映射保持状态,使用reduce执行循环:

代码语言:javascript
运行
复制
(defn breaking-records
  [scores]
  (let [state-init     {:low     (first scores)
                        :high    (first scores)
                        :nworse  0
                        :nbetter 0}
        accum-stats-fn (fn [state score-pair]
                         ; Use map destructuring to pull out the 4 state variables
                         (let [{:keys [low high nworse nbetter]} state 
                               new-score (second score-pair)
                               state-new {:low     (min new-score low)
                                          :high    (max new-score high)
                                          :nworse  (cond-> nworse
                                                     (< new-score low) (inc))
                                          :nbetter (cond-> nbetter
                                                     (< high new-score) (inc))}]
                           state-new))
        state-final    (reduce accum-stats-fn
                         state-init
                         (partition 2 1 scores))
        result         (select-keys state-final [:nworse :nbetter])]
    result))
票数 1
EN
页面原文内容由Code Review提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://codereview.stackexchange.com/questions/251024

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档