首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >更好地发挥收藏功能

更好地发挥收藏功能
EN

Stack Overflow用户
提问于 2020-12-03 11:39:51
回答 3查看 137关注 0票数 6

在回答一个问题时,我无意中遇到了这个问题:

代码语言:javascript
运行
复制
(def x [7 4 8 9 10 54 55 2 23 30 12 5])

(defn insert-x 
  ([sorted-coll x] 
   (insert-x sorted-coll x 
     (if (= (type sorted-coll) clojure.lang.PersistentVector) [] '())))

  ([sorted-coll x acc]
  (let [is-vector  (= (type sorted-coll) clojure.lang.PersistentVector)
        format-it  #(into (if is-vector [] '()) %)
        compare   (if is-vector < >)]
    (cond 
      (empty? sorted-coll) (format-it (cons x acc))

      (compare (peek sorted-coll) x) 
      (format-it (concat 
                   ((if is-vector identity reverse) sorted-coll) 
                   (conj acc x)))

      :else (recur (pop sorted-coll) x (cons (peek sorted-coll) acc))))))

(defn bubble-sort [coll]
  "Insert x into a sorted collection"
  (reduce insert-x [] coll))

(bubble-sort x)
;; => [2 4 5 7 8 9 10 12 23 30 54 55]

代码可以做它应该做的事情。

然而,insert-x并不那么优雅。如何以对所有集合都有效的方式编写insert-x?使它更简单/更优雅?向量应该返回向量,列表应该返回列表等等。

EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2020-12-03 16:56:22

我猜你想得太多了。

您有两项任务:

输入向量的排序collection

  • return向量和输入列表的

中正确位置的

  1. 插入项

首先,我会像这样重写insert-x --例如:

代码语言:javascript
运行
复制
(defn insert-x [sorted-coll x]
  (let [[l r] (split-with #(<= % x) sorted-coll)]
    `(~@l ~x ~@r)))

注意,它所做的与您的变体差不多相同:取值直到所需的位置,然后将左右两个部分与它们之间的x连接起来。注意,它总是生成与输入类型无关的排序正确的列表。

代码语言:javascript
运行
复制
user> (insert-x [1 3 5 7 9] 10)
;;=> (1 3 5 7 9 10)

user> (insert-x [1 3 5 7 9] 0)
;;=> (0 1 3 5 7 9)

user> (insert-x [1 3 5 7 9] 4)
;;=> (1 3 4 5 7 9)

因此,接下来需要的就是减少输入并返回正确类型的结果:

代码语言:javascript
运行
复制
(defn my-sort [coll]
  (let [sorted (reduce insert-x () coll)]
    (if (vector? coll)
      (vec sorted)
      sorted)))

user> (my-sort '(0 3 1 4 2 5 10 7))
;;=> (0 1 2 3 4 5 7 10)

user> (my-sort [0 3 1 4 2 5 10 7])
;;=> [0 1 2 3 4 5 7 10]

user> (my-sort ())
;;=> ()

user> (my-sort [])
;;=> []
票数 5
EN

Stack Overflow用户

发布于 2020-12-03 11:57:19

您需要的是让insert-x处理常规列表(即。( '()或nil)并重写bubble-sort以使用empty函数创建与输入相同的类型。

empty返回相同类型的空集合:

代码语言:javascript
运行
复制
(class (empty [1 2]))
;; => clojure.lang.PersistentVector
(class (empty #{1 2}))
;; => clojure.lang.PersistentHashSet
(class (empty '(1 2)))
;; => clojure.lang.PersistentList$EmptyList

您的bubble-sort可以这样看:

代码语言:javascript
运行
复制
(defn bubble-sort [coll]
  "Insert x into a sorted collection"
  (into (empty coll) (reduce insert-x nil coll)))

这样您就可以摆脱insert-x中的所有类型检查。

票数 5
EN

Stack Overflow用户

发布于 2020-12-03 17:33:58

谢谢你们俩!

我接受了你的两个答案,并产生了这样的解决方案:

代码语言:javascript
运行
复制
(defn insert-x [sq x]
  (apply concat (interleave (split-with #(<= % x) sq) [[x] []])))

(defn bubble-sort [sq]
  ((if (vector? sq) vec identity)
   (reduce insert-x () sq)))

测试:

代码语言:javascript
运行
复制
user=> (bubble-sort '(0 2 8 3 9 7))
(0 2 3 7 8 9)
user=> (bubble-sort [0 2 8 3 9 7])
[0 2 3 7 8 9]

或者更好的可读性:

代码语言:javascript
运行
复制
(defn insert [q x]
  (let [[l r] (split-with #(< % x) sq)] 
    (concat l [x] r)))

(defn bubble-sort [sq]
  ((if (vector? sq) vec identity) 
   (reduce insert () sq)))

或者:

代码语言:javascript
运行
复制
(defn insert [sq x]
  (let [[l r] (split-with #(< % x) sq)] 
    `(~@l ~x ~@r)))

(defn intoo [x sq] ;; direction neutral `into`
  (into x (into x sq))) 

(defn bubble-sort [sq]
  (intoo (empty sq) (reduce insert () sq)))

需要intoo是因为

代码语言:javascript
运行
复制
(into () '(1 2 3)) ;;=> '(3 2 1)
(into () [1 2 3])  ;;=> '(3 2 1)
(into [] '(1 2 3)) ;;=> [1 2 3]
(into [] [1 2 3])  ;;=> [1 2 3]
# `into` uses `conj` underneath!

连续应用两次into修复如下:

代码语言:javascript
运行
复制
(into () (into () '(1 2 3))) ;; '(1 2 3)
(into () (into () [1 2 3]))  ;; '(1 2 3)
(into [] (into [] '(1 2 3))) ;; [1 2 3]
(into [] (into [] [1 2 3]))  ;; [1 2 3]

因此,intoo是一种方向中立的into版本。

实际上,最有效的intoo版本可能是:

代码语言:javascript
运行
复制
(defmacro intoo [x sq]
  (if (vector? x)
      `(into ~x ~sq)
      `(reverse (into ~x ~sq))))

;; user=> (intoo () '(1 2 3))
;; (1 2 3)
;; user=> (intoo () [1 2 3])
;; (1 2 3)
;; user=> (intoo [] [1 2 3])
;; [1 2 3]
;; user=> (intoo [] '(1 2 3))
;; [1 2 3]

;; or as a function:
(defn intoo [x & args]
  (if (vector? x)
      (apply into x args)
      (reverse (apply into x args))))
票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/65125283

复制
相关文章

相似问题

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