英文:
Update values of keys in a sequence of maps from the values of first map's keys
问题
我有一系列类似这样的地图:
({:autoNo "1" :title "Title1" :47652 ("name1") :47653 ("name2" "name3")} {:autoNo nil :title nil :47652 nil :47653 nil})
只有第一个地图包含文件上传字段键:47652
和:47653
的值,而第二个地图中相同键的值为nil
。我希望文件上传字段键每个地图只有一个文件值,就像这样:
({:autoNo "1" :title "Title1" :47652 "name1" :47653 "name2"} {:autoNo nil :title nil :47652 nil :47653 "name3"})
您可以看到,正如:47652
在seq
中只有一个值,所以它的值得到了更新,而同一键在序列中的下一个地图中的值保持为nil
。对于:47653
具有多个值,第一个地图中的键包含第一个值,即"name2"
,而序列中下一个地图中的相同键包含下一个值,即"name3"
。
为了实现这一点,我创建了一个函数,如下所示:
(defn update-file-upload-field-values
[conversation-instances]
(let [file-field-ids [:47652 :47653]]
(first (map (fn [x]
(map
#(update %1 x (fn [z] (str %2)))
conversation-instances ((first conversation-instances) x)))
file-field-ids))))
其中conversation-instances
与开始时提到的地图序列相同。
我的解决方案未能达到预期的效果。它返回了这个:
({:autoNo "1" :title "Title1" :47652 "name1" :47653 ("name2" "name3")})
这与开头显示的预期输出不同。
英文:
I have a sequence of maps like this:
({:autoNo "1" :title "Title1" :47652 ("name1") :47653 ("name2" "name3")} {:autoNo nil :title nil :47652 nil :47653 nil})
Only the first map contains the values for file-upload-field keys :47652
and :47653
whereas the value of same keys in the second map is nil
. What I want is file-upload-field keys having only one name of file value per map like this:
({:autoNo "1" :title "Title1" :47652 "name1" :47653 "name2"} {:autoNo nil :title nil :47652 nil :47653 "name3"})
You can see above as :47652
have only one value in the seq
so its value get updated whereas the value of the same key in the next map remains nil
. For :47653
having multiple values, the key in first map contains the first value i.e. "name2"
whereas the same key in the second map of the sequence contains the next value i.e. "name3"
.
To achieve so I have created a function like this:
(defn update-file-upload-field-values
[conversation-instances]
(let [file-field-ids [:47652 :47653]]
(first (map (fn [x]
(map
#(update %1 x (fn [z] (str %2)))
conversation-instances ((first conversation-instances) x)))
file-field-ids))))
where conversation-instances
is the same sequence of maps stated at the beginning.
My solution is not working as expected. It is returning this:
({:autoNo "1" :title "Title1" :47652 "name1" :47653 ("name2" "name3")})
Which is different from the expected output shown at the beginning.
答案1
得分: 0
你使用 map
函数同时处理两个序列(conversation-instances
和 ((first conversation-instances) x)
的结果),因此结果的长度将取决于它们中最短的那个。我还认为你可以用 assoc
替换 update
。
使用两层嵌套的 map
结合 first
也会产生一些你可能不想要的结果。我建议你逐步编写函数,逐步在 REPL 中测试,这样你就知道你的函数是否达到了预期的效果。
你可以使用 reduce
来解决这个问题。我的 update-maps
函数类似于你的内部 map
,只是我添加了 reduce
来重复执行它以处理每个给定的键:
(def data '({:autoNo "1" :title "Title1" :47652 ("name1") :47653 ("name2" "name3")}
{:autoNo nil :title nil :47652 nil :47653 nil}))
(defn update-maps [coll k]
(let [values-seq (k (first coll))]
(mapv #(assoc %1 k %2)
coll
(concat values-seq (repeat nil)))))
(defn keys-fn [coll]
(let [ks [:47652 :47653]]
(reduce update-maps
coll
ks)))
(keys-fn data)
=>
[{:autoNo "1", :title "Title1", :47652 "name1", :47653 "name2"} {:autoNo nil, :title nil, :47652 nil, :47653 "name3"}]
英文:
You call map
with two sequences (conversation-instances
and the result of ((first conversation-instances) x)
), so the result will be as long as the shortest of them. I also think you can replace update
with assoc
.
Two nested map
s with first
also create some result you probably don't want. I suggest you to write your functions step by step, testing each increment in REPL, so you know whether your function does what you expect.
You can use reduce
to solve this. My update-maps
is similar to your inner map
, I just added reduce
to repeat it for each given key:
(def data '({:autoNo "1" :title "Title1" :47652 ("name1") :47653 ("name2" "name3")}
{:autoNo nil :title nil :47652 nil :47653 nil}))
(defn update-maps [coll k]
(let [values-seq (k (first coll))]
(mapv #(assoc %1 k %2)
coll
(concat values-seq (repeat nil)))))
(defn keys-fn [coll]
(let [ks [:47652 :47653]]
(reduce update-maps
coll
ks)))
(keys-fn data)
=>
[{:autoNo "1", :title "Title1", :47652 "name1", :47653 "name2"} {:autoNo nil, :title nil, :47652 nil, :47653 "name3"}]
答案2
得分: 0
(require 'com.rpl.specter :as s)
(use 'plumbing.core)
(let [data '({:autoNo "1" :title "Title1" :47652 ("name1") :47653 ("name2" "name3")}
{:autoNo nil :title nil :47652 nil :47653 nil})]
(->> data
(s/transform (s/subselect 展开收缩)]) aconcat)
(s/transform (s/subselect 展开收缩)]) aconcat)))
英文:
(require '[com.rpl.specter :as s])
(use '[plumbing.core])
(let [data '({:autoNo "1" :title "Title1" :47652 ("name1") :47653 ("name2" "name3")}
{:autoNo nil :title nil :47652 nil :47653 nil})]
(->> data
(s/transform (s/subselect 展开收缩)]) aconcat)
(s/transform (s/subselect 展开收缩)]) aconcat)))
答案3
得分: 0
基本上,你可以这样做:
```clojure
(map assoc 数据
(repeat :47652)
(concat (:47652 (first 数据)) (repeat nil))
(repeat :47653)
(concat (:47653 (first 数据)) (repeat nil)))
为了消除重复,你可以这样做:
(defn ks-vs [[k vs]]
[(repeat k) (concat vs (repeat nil))])
(defn 处理 [[头 :as 数据]]
(->> (select-keys 头 [:47652 :47653])
(mapcat ks-vs)
(apply map assoc 数据)))
(处理 数据)
这基本上是基于相同方法的更抽象的变体。
英文:
basically, what you could do is something like this:
(map assoc data
(repeat :47652)
(concat (:47652 (first data)) (repeat nil))
(repeat :47653)
(concat (:47653 (first data)) (repeat nil)))
;;=> ({:autoNo "1", :title "Title1", :47652 "name1", :47653 "name2"}
;; {:autoNo nil, :title nil, :47652 nil, :47653 "name3"})
to get rid of repetition you can do something like that:
(defn ks-vs [[k vs]]
[(repeat k) (concat vs (repeat nil))])
(defn process [[head :as data]]
(->> (select-keys head [:47652 :47653])
(mapcat ks-vs)
(apply map assoc data)))
(process data)
;;=> ({:autoNo "1", :title "Title1", :47652 "name1", :47653 "name2"}
;; {:autoNo nil, :title nil, :47652 nil, :47653 "name3"})
which is basically more abstract variant based on the same approach.
答案4
得分: 0
抱歉,我只能为您提供代码部分的翻译:
我讨厌回答与所问不同的问题,但在您的问题中,列表中的第二个映射似乎是从第一个派生出来的,因此不需要。
此外,许多(但并非所有)当前的答案似乎包含硬编码的信息,即键或最大项的长度。
我认为有3种解决方案:
1. 循环递归
2. 惰性映射
3. 有状态的传递器。
说到这里,我将提供一个“惰性”的解决方案,其中键和长度都没有硬编码:
(->> '{:autoNo "1" :title "Title1" :47652 ("name1") :47653 ("name2" "name3" "name4") :9999 ("foo9" "bar9")}
(mapcat (fn [[k v]]
[(repeat k)
(if (coll? v)
(concat v (repeat nil))
(cons v (repeat nil)))]))
(apply map hash-map)
(take-while #(some second %)))
这应该产生类似以下的结果:
[{:47652 "name1" :47653 "name2" :9999 "foo" :autoNo "1" :title "Title1"}
{:47652 nil :47653 "name3" :9999 "bar" :autoNo nil :title nil}
{:47652 nil :47653 "name4" :9999 nil :autoNo nil :title nil}]
英文:
I hate to answer a question other than what was asked but in your question, the second map in the list appears to be derived from the first and is thus not needed.
Also many (but not all) of the current answers appear to hardcoded information i.e. keys or length of maximum items.
I think there are 3 solutions:
- loop recur
- lazy mapping
- stateful transducer.
That being said I'll offer up a "lazy" solution that has neither the keys or lengths hard coded in:
(->> '{:autoNo "1" :title "Title1" :47652 ("name1") :47653 ("name2" "name3" "name4") :9999 ("foo9" "bar9")}
(mapcat (fn [[k v]]
[(repeat k)
(if (coll? v)
(concat v (repeat nil))
(cons v (repeat nil)))]))
(apply map hash-map)
(take-while #(some second %)))
which should yield something like:
[{:47652 "name1" :47653 "name2" :9999 "foo" :autoNo "1" :title "Title1"}
{:47652 nil :47653 "name3" :9999 "bar" :autoNo nil :title nil}
{:47652 nil :47653 "name4" :9999 nil :autoNo nil :title nil}]
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论