Clojure 组合两个载体(用几个罐的内容物填充容器)

Clojure 组合两个载体(用几个罐的内容物填充容器),clojure,Clojure,我有两个向量 (def container [{:no 1 :volume 10} {:no 2 :volume 20}]) (def cans [{:no 1 :volume 2} {:no 2 :volume 8} {:no 1 :volume 5} {:no 2 :volume 8}]) 我想把罐子装满容器,这样可以退回这样的东西: [{:no 1 :volume 10 :cans [{:no 1 :volume 2} {:no 2 :volume 8}]} {:no 2 :vol

我有两个向量

(def container [{:no 1 :volume 10} {:no 2 :volume 20}])
(def cans [{:no 1 :volume 2} {:no 2 :volume 8} {:no 1 :volume 5} {:no 2 :volume 8}])
我想把罐子装满容器,这样可以退回这样的东西:

[{:no 1 :volume 10
  :cans [{:no 1 :volume 2} {:no 2 :volume 8}]}
 {:no 2 :volume 20
  :cans [{:no 1 :volume 5} {:no 2 :volume 8}]}]
这样就可以跟踪哪个罐子进了哪个容器。我开始使用reduce,但如果不使用变异商店来存放剩余的罐头,我就无法了解如何做到这一点。有什么想法吗

更新


所谓装满,我的意思是在第一个容器中装入尽可能多的罐,直到装满或接近(罐的总体积不超过容器的体积),然后开始装满第二个容器,直到装满或接近,依此类推。

我们不需要为剩余的罐使用变异存储,因为reduce将序列作为参数,并通过累加函数进行reduce,在序列的每个元素上调用它

在下文中,我将容器分为已装/未装,并将每个罐插入最紧密的容器中(这有助于优化包装)

user>(def容器[{:编号1:卷10}{:编号2:卷20}])
#'用户/容器
用户>(def罐[{:编号1:卷2}{:编号2:卷8}{:编号1:卷5}{:编号2:卷8}])
#“用户/易拉罐
用户>
(def)集装箱运输
(让[容器(映射#(关联%:容量%:罐[])容器)
插入(fn[容器罐]
(->容器
(在[:容量](:卷can)中更新)
(在[:cans]conj-can]中更新)
蓄能器(fn[[填充]罐]
(让[[不匹配[拾取和取消拾取]]
(拆分为#)(<(:容量%)
(:容积罐)
(排序方式:容量填充)
拾取(插入拾取的罐)
仍在填充(混凝土未填充)]

(如果(那些
def
调用无效-我想你想让容器和罐子成为向量或列表?啊,对不起。填充,我的意思是在第一个容器中装入尽可能多的罐子,直到装满或尽可能接近,然后开始填充第二个容器,直到装满或尽可能接近,依此类推。我更新了这个问题。它有点复杂,w重新阅读这个问题-你喜欢在使用第二个容器之前完全填充第一个容器,还是更喜欢获得最佳包装?这些是不同的任务,我可能错误地假设了后者
user> (def container [{:no 1 :volume 10} {:no 2 :volume 20}])
#'user/container
user> (def cans [{:no 1 :volume 2} {:no 2 :volume 8} {:no 1 :volume 5} {:no 2 :volume 8}])
#'user/cans
user> 
(def containerized
  (let [containers (map #(assoc % :capacity (:volume %) :cans []) container)
        insert (fn [container can]
                 (-> container
                     (update-in [:capacity] - (:volume can))
                     (update-in [:cans] conj can)))
        accumulator (fn [[filled filling] can]
                      (let [[non-fits [picked & unpicked]]
                            (split-with #(< (:capacity %)
                                            (:volume can))
                                        (sort-by :capacity filling))
                           picked (insert picked can)
                           still-filling (concat non-fits unpicked)]
                        (if (<= (:capacity picked) 0)
                          [(conj filled picked) still-filling]
                          [filled (conj still-filling picked)])))
        filled (reduce accumulator
                       [[] containers]
                       cans)]
    (map #(dissoc % :capacity) (apply concat filled))))

#'user/containerized
user> (clojure.pprint/pprint containerized)
({:cans [{:volume 2, :no 1} {:volume 8, :no 2}], :volume 10, :no 1}
 {:cans [{:volume 5, :no 1} {:volume 8, :no 2}], :volume 20, :no 2})
nil