2

リストのリストと値があります。私の目標は、述語に一致する最初のリスト (例: > リストの最初の項目) に値が変換される (新しい最初の項目) リストの新しいリストです。述語に一致するリストがない場合、値がリストの最後にある新しいリストを「開始」するようにします。

if my list is: ['(2 3 4) '(4 5 6 7) '(5 6 7)]
and my value: 3
and my predicate: (comp (partial < my-value) first)
then my result should be: ['(2 3 4) '(3 4 5 6 7) '(5 6 7)]

if my value was: 10
my result should be: ['(2 3 4) '(4 5 6 7) '(5 6 7) '(10)]

この問題は私を混乱させます。なぜなら、私の命令的な心は、それがどれほど簡単であるべきかを教え続けているからです。これはこれまでの私の試みです:

(defn add-to-first-list-that-matches [func value]
  (loop [result []
         remaining-lists list-of-lists
         value-to-add value]
    (if (empty? remaining-lists)
      result
      (let [current-list (first remaining-lists)
            value-matches? (func value-to-add current-list)
            new-list (if value-matches? (conj value-to-add current-list) current-list)]
        (recur (conj new-list result)
               (rest remaining-lists)
               (if-not value-matches? value-to-add nil))))))

(クラッシュします) Clojure 式の魔法について教えてください :)

ところで。これを最長増加部分列問題の一部として解きたいと思います。

4

4 に答える 4

4

これは loop-recur を使用します。

(defn add-to-ll
  [ll pred value]
  (loop [[current & unprocessed] ll
         processed []]
    (cond
     (pred current) (concat processed
                            [(cons value current)]
                            unprocessed)
     (empty? unprocessed) (concat processed
                                  [current]
                                  [[value]])
     :else (recur unprocessed
                  (conj processed current)))))


 (def l-l1 [[2 3 4] [4 5 6 7] [5 6 7]])
 (add-to-ll l-l1 (comp (partial < 10) first) 10)
 => ([2 3 4] [4 5 6 7] [5 6 7] [10])

 (add-to-ll l-l1 (comp (partial < 3) first) 3)
 => ([2 3 4] (3 4 5 6 7) [5 6 7])

split-with を使用することもできます

(defn add-to-ll
  [ll pred value]
  (let [[first-lists [to-change & rest-lists]] (split-with (complement pred) ll)]
    (if to-change
      (concat first-lists [(cons value to-change)] rest-lists)
      (concat ll [[value]]))))

パフォーマンスに関しては、最初のソリューションは少し速く実行する必要があります。

于 2013-07-30T13:07:39.430 に答える
3

古いレイジーシーケンス:

(defn add-to-first-match
  [pred x coll]
  (lazy-seq
    (if-let [s (seq coll)]
      (let [fst (first s)]
        (if (pred fst)
          (cons (conj fst x) (rest s))
          (cons fst (add-to-first-match pred x (rest s)))))
      (cons (list x) nil))))

注: さらにlist引数に抽出して、たとえばvector要素コンストラクターとしても許可することができます。

于 2013-07-30T13:58:19.343 に答える
1

これは、reduce を使用してより簡潔に答える私の試みです。

(defn add-to-first-list-that-matches
  [value lists]
  (let [pred (comp (partial < value) first)
        [found result] (reduce (fn [[found result] el]
                                 (if (and (not found) (pred el))
                                   [true (conj result (cons value el))]
                                   [found (conj result el)]))
                               [false []]
                               lists)]
    (if found
      result
      (conj result (list value)))))

複数の値 (一致が見つかったかどうかを示すブール値と、構築中の変更されたデータ構造) を運ぶために、reduce でベクトルのイディオムを使用しています。また、さまざまな条件を要素ごとに 1 つの if に結合することもできました。さらに、ネストされた条件や複数分岐条件ではなく、最終事後条件を追加することもできました。

これがあなたの例でどのように機能するかです:

user> (add-to-first-list-that-matches 3 ['(2 3 4) '(4 5 6 7) '(5 6 7)])
[(2 3 4) (3 4 5 6 7) (5 6 7)]
user> (add-to-first-list-that-matches 10 ['(2 3 4) '(4 5 6 7) '(5 6 7)])
[(2 3 4) (4 5 6 7) (5 6 7) (10)]
于 2013-07-30T21:16:30.307 に答える
1
(defn find-index
  "find index of the first item in s matching predicate `pred`"
  [pred s]
  (first (keep-indexed (fn [index item]
                         (if (pred item)
                           index
                           nil))
                       s)))

(defn update-first-match
  "update first item in s that matches `pred` using (f item args*)"
  [s pred f & args]
  (apply update-in s [(or (find-index pred s)
                          (count s))]
         f args))


(def my-lists
  ['(2 3 4) '(4 5 6 7) '(5 6 7)])

(defn add-to-first-list-less-than
  [l n]
  (update-first-match l #(< n (first %)) conj n))

;; usage:

(update-first-match my-lists #(< 5 (first %)) conj 5)

;; or
(add-to-first-list-less-than my-lists 5)
于 2013-07-30T13:19:08.713 に答える