(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

Reply via email to