web-dev-qa-db-ja.com

マップからnil値を削除しますか?

Nilの値を含む可能性のあるClojureマップがあり、それらを削除する関数を作成しようとしていますが、あまり成功していません(これは初めてです)。

例えば。:

(def record {:a 1 :b 2 :c nil})
(merge (for [[k v] record :when (not (nil? v))] {k v}))

これにより、一連のマップが作成されますが、これはマージから期待したものではありません。

({:a 1} {:b 2})

私はを頂きたい:

{:a 1, :b 2}
28
edoloughlin

your forリスト内包表記はマップのリストを返すため、このリストをオプションの引数としてマージ関数に適用する必要があります。

user> (apply merge (for [[k v] record :when (not (nil? v))] {k v}))
{:b 2, :a 1}      

マップをシーケンスとしてフィルタリングし、マップに結合することによる、より簡潔なソリューション:

user> (into {} (filter second record))
{:a 1, :b 2}  

削除しないでくださいfalse値:

user> (into {} (remove (comp nil? second) record))
{:a 1, :b false}  

dissocを使用して、まったく新しいマップを作成する代わりに、永続的なデータ共有を許可します。

user> (apply dissoc                                                                                            
       record                                                                                                  
       (for [[k v] record :when (nil? v)] k))
{:a 1, :b 2}  
56
Jürgen Hötzel

ネストされたマップで機能するものは次のとおりです。

(defn remove-nils
  [m]
  (let [f (fn [[k v]] (when v [k v]))]
    (postwalk (fn [x] (if (map? x) (into {} (map f x)) x)) m)))
7
Eelco

あなたはそれを地図に押しつぶすことができます:

(into {} (remove (fn [[k v]] (nil? v)) {:a 1 :b 2 :c nil}))
=> {:a 1 :b 2}
5
thnetos

@Eelcoの答えのバリエーション:

(defn remove-nils [m]
  (let [f (fn [x]
            (if (map? x)
              (let [kvs (filter (comp not nil? second) x)]
                (if (empty? kvs) nil (into {} kvs)))
              x))]
    (clojure.walk/postwalk f m)))

@ broma0の要点として、空のマップはすべて削除されます。

user> (def m {:a nil, :b 1, :c {:z 4, :y 5, :x nil}, :d {:w nil, :v nil}})
user> (remove-nils m)
{:b 1, :c {:z 4, :y 5}}
user> (remove-nils {})
nil
5
Marklar

JürgenHötzelソリューションがnil/falseの問題を修正するように改良されました

(into {} (filter #(not (nil? (val %))) {:a true :b false :c nil}))

@thnetosソリューションの少し短いバージョン

(into {} (remove #(nil? (val %)) {:a true :b false :c nil}))
4
Xavi

reduce-kvを使用してキーを削除することもできます

(reduce-kv (fn [m key value]
                (if (nil? value)
                  (dissoc m key)
                  m))
            {:test nil, :test1 "hello"}
            {:test nil, :test1 "hello"})
2
Pardeep Singh

ユルゲンの(フィルターの2番目のレコード)アプローチは、最も気の利いたClojure Trickに投票しますが、今回はselect-keysを使用して、別の方法で投げたいと思いました。

user> (select-keys record (for [[k v] record :when (not (nil? v))] k))
{:b 2, :a 1}
2

Reduceを使用できます。

user> (reduce (fn [m [k v]] (if (nil? v) m (assoc m k v))) {} record)
{:b 2, :a 1}

何らかの理由で順序を維持したい場合(通常、マップでは重要ではありません)、dissocを使用できます。

user> (reduce (fn [m [k v]] (if (nil? v) (dissoc m k) m)) record record)
{:a 1, :b 2}
1
Jonathan Tran

これがマップとベクトルで機能するものです:

(defn compact
  [coll]
  (cond
    (vector? coll) (into [] (filter (complement nil?) coll))
    (map? coll) (into {} (filter (comp not nil? second) coll))))
1
Noam Ben Ari