(responses inline)
On Sat, 15 Dec 2012, mond wrote:
I have defined these types of records for modelling a simple shopping cart:
; An item in the cart
(defrecord Item [id name product quantity purchased])
; The product that relates to the item in the cart
(defrecord Product [id name description prices])
; A price definition
(defrecord Price [price tax-rate currency])
; Sample items
(def items [
(->Item 1 "Brogues" "P-123" 1 true)
(->Item 2 "Underpants" "P-345" 1 false)
(->Item 3 "Shirt" "P-678" 1 true)
])
; Sample products
(def products [
(->Product "P-123" "Brogues" "Men's Leather Slip on
Brogues" (->Price 93.00 21 "EURO"))
(->Product "P-345" "Underpants" "CK Y Fronts" (->Price
23.50 21 "EURO"))
(->Product "P-678" "Shirt" "Slim Fit White Vest Shirt"
(->Price 45.99 21 "EURO"))
(->Product "P-1231" "Table" "Coffee Table" (->Price 375 21
"EURO"))
(->Product "P-3451" "Chairs" "Set of Four(4) chairs"
(->Price 200 21 "EURO"))
(->Product "P-6781" "TableCloth" "Classic red and white
checks 2m x 2m" (->Price 17.99 21 "EURO"))
])
My requirement is to combine data from the two collections such that I can
show the detailed product information for any item, for example:
(->Item 3 "Shirt" "Slim Fit White Vest Shirt" (->Price 45.99 21
"EURO") 1 true)
When I tried to use merge-with union I had an error which surprised me
since I thought records are also maps:
user=> (merge-with union items products)
ClassCastException user.Product cannot be cast to java.util.Map$Entry
clojure.core/key (core.clj:1465)
It looks like your second response worked around it, but for anyone
following along: merge-with takes two or more maps, and uses the
function you pass to merge the values of common keys. So, the error is
caused because merge-with expects items and products to be maps (not
vectors of map-like things).
On Sat, 15 Dec 2012, mond wrote:
I think I am close to answering this myself (which is always nice!)
I have done the necessary joins with map and I can return a product
description
user=> (map (fn [item product] (= (:product item (:id product)))
(:description product)) items products)
("Men's Leather Slip on Brogues" "CK Y Fronts" "Slim Fit White Vest Shirt")
The (= (:product item (:id product))) here is being ignored.
It "works" because your example arrays happen to have the items and
products lined up properly (first three products match the items
in order):
(map (fn [item product]
(= (:product item (:id product))) ; the result of this comparison is
thrown away
(:description product) ; this is the value that is returned
) items products)
If you want to match things up, you might be better off creating maps
for each category of thing:
; (with items and products as you'd defined them before)
(def product->item (zipmap (map :product items) items))
;=> {"P-123" #user.Item{...}, "P-345" #user.Item{...}, ...}
(def id->product (zipmap (map :id products) products))
;=> {"P-123" #user.Product{...}, "P-345" #user.Product{...}, ...}
(def combined (merge-with union product->item id->product))
;=> {"P-123" #user.Product{... with :quantity and :purchased },
; "P-1231" #user.Product{... with no Item keys ...}, ...etc.
Or a purchased status for the matching item
user=> (map (fn [item product] (= (:product item (:id product)))
(:purchased item)) items products)
(true false true)
But I have my knickers in a twist when I want to get more than one
value out or a combination of values.
user=> (map (fn [item product] (= (:product item (:id product))) (:id item
:description product)) items products)
(user=> IllegalArgumentException Wrong number of args passed to keyword:
:id clojure.lang.Keyword.throwArity (Keyword.java:85)
So does anyone have the last bit of syntax to help me take back a list
of values from the inputs?
Other than the matching issue (the = form isn't being used -- see
above), the problem with what you've written is that you want a map,
rather than a list:
(map (fn [item product] {:id item :description product}) items products)
Or if you really want a list, you need to quote it:
(map (fn [item product] '(:id item :description product)) items products)
--
Best,
Ben
--
You received this message because you are subscribed to the Google
Groups "Clojure" group.
To post to this group, send email to clojure@googlegroups.com
Note that posts from new members are moderated - please be patient with your
first post.
To unsubscribe from this group, send email to
clojure+unsubscr...@googlegroups.com
For more options, visit this group at
http://groups.google.com/group/clojure?hl=en