I am trying to recursively call a function with arguments that are node :type folder using an if statement to conditionally filter them out. I am however getting the error:
Uncaught Error: No item :type in vector of length 3
I thought this might be because of empty :children vectors but even when there is a :type property in them, I still get the error. The error is kind of cryptic and I cannot see a vector without a :type keyword.
Here is my code:
(defn dispatch-nodes-to-state [node & {:keys [depth] :or {depth 0}}]
(re-frame/dispatch [:set-nodes (conj {:depth depth} node)])
(if (= (node :type) "folder")
(do
(println "It's a folder")
(recur (node :children) (inc depth)))
(println "it's a file")))
(defn traverse-tree [nodes]
(run! dispatch-nodes-to-state nodes))
(defn get-file-tree []
(go (let [file-tree (<! (http/get API-URL request-opts))]
(traverse-tree (get-in file-tree [:body :root])))))
Is there something obviously wrong with the code?
Here is a snippet of the data structure I'm traversing. Thanks in advance:
[{:depth 0, :type folder, :empty false, :name My Documents, :children [{:type file, :name My Text 1, :extension .txt, :preview In ipsum est, faucibus ac tempor vel, tincidunt ac leo. Vestibulum quis odio nisl. Nulla auctor erat a sem ullamcorper vulputate. Fusce efficitur tempus nulla, eget suscipit tortor imperdiet nec. Aenean finibus, ipsum ut pulvinar euismod, neque tellus vestibulum justo, sit amet volutpat justo lectus nec risus.} {:type folder, :empty false, :name My Music, :children [{:type folder, :empty false, :name Pop, :children [{:type folder, :empty false, :name Rock, :children [{:type folder, :empty true, :name Empty Folder, :children [{:type yes}]} {:type file, :name Lyrics, :extension .txt, :preview Curabitur molestie ex ligula, ac tincidunt nisi tempor sit amet. Nullam eget varius purus, nec lobortis urna. Pellentesque consequat est fringilla, mollis turpis at, consequat est. In sit amet lectus dui. Vestibulum sodales ligula at diam lacinia iaculis. Cras molestie dui at odio vestibulum feugiat.}]} {:type file, :name Song Lyrics, :extension .txt, :preview Nam venenatis nunc eget imperdiet laoreet. Vivamus luctus luctus neque in luctus. Donec convallis, elit non lobortis molestie, felis tellus molestie nunc, vel condimentum ante enim sit amet augue.}]} {:type file, :name Album Artwork, :extension .png, :preview photos.google.com/abc.jpg} {:type folder, :empty false, :name Acoustic, :children [{:type folder, :empty false, :name Guitar Music, :children [{:type file, :name Fav song lyrics, :extension .txt, :preview Mauris pharetra suscipit purus et molestie. Cras rhoncus est enim, pulvinar tristique orci sagittis non. Sed volutpat tellus id elit laoreet faucibus a quis eros. Sed cursus fermentum ultrices. Praesent blandit luctus feugiat. Nunc est massa, volutpat sed justo sagittis, ultricies pellentesque enim. Mauris lacinia enim ac erat sodales, in feugiat nulla auctor.}]} {:type file, :name song artwork, :extension .png, :preview photos.google.com/abc.jpg}]} {:type file, :name reminder, :extension .txt, :preview Aenean orci dui, dictum at odio sed, malesuada placerat erat. Aliquam eget risus nec lorem convallis commodo. Praesent tincidunt a ligula sed fringilla. Maecenas posuere sem a scelerisque auctor. Nam ultrices maximus elit, quis efficitur nunc auctor ac.}]} {:type file, :name Recipe, :extension .txt, :preview Aliquam bibendum lacus ex, at malesuada purus maximus eget. Mauris viverra diam vel turpis imperdiet dictum. Nam vel augue non diam egestas pulvinar nec nec odio. Nulla tincidunt interdum lorem, vitae tincidunt massa elementum vitae. Nam varius vitae nisl a ullamcorper. Integer dui mauris, vulputate ac sem ac, varius dapibus erat. Ut pharetra ultrices velit, mattis elementum velit varius in. Donec varius turpis purus, sit amet ultricies ipsum elementum nec.}]} {:depth 0, {:type file, :name My Text 1, :extension .txt, :preview In ipsum est, faucibus ac tempor vel, tincidunt ac leo. Vestibulum quis odio nisl. Nulla auctor erat a sem ullamcorper vulputate. Fusce efficitur tempus nulla, eget suscipit tortor imperdiet nec. Aenean finibus, ipsum ut pulvinar euismod, neque tellus vestibulum justo, sit amet volutpat justo lectus nec risus.} {:type folder, :empty false, :name My Music, :children [{:type folder, :empty false, :name Pop, :children [{:type folder, :empty false, :name Rock, :children [{:type folder, :empty true, :name Empty Folder, :children [{:type yes}]} {:type file, :name Lyrics, :extension .txt, :preview Curabitur molestie ex ligula, ac tincidunt nisi tempor sit amet. Nullam eget varius purus, nec lobortis urna. Pellentesque consequat est fringilla, mollis turpis at, consequat est. In sit amet lectus dui. Vestibulum sodales ligula at diam lacinia iaculis. Cras molestie dui at odio vestibulum feugiat.}]} {:type file, :name Song Lyrics, :extension .txt, :preview Nam venenatis nunc eget imperdiet laoreet. Vivamus luctus luctus neque in luctus. Donec convallis, elit non lobortis molestie, felis tellus molestie nunc, vel condimentum ante enim sit amet augue.}]} {:type file, :name Album Artwork, :extension .png, :preview photos.google.com/abc.jpg} {:type folder, :empty false, :name Acoustic, :children [{:type folder, :empty false, :name Guitar Music, :children [{:type file, :name Fav song lyrics, :extension .txt, :preview Mauris pharetra suscipit purus et molestie. Cras rhoncus est enim, pulvinar tristique orci sagittis non. Sed volutpat tellus id elit laoreet faucibus a quis eros. Sed cursus fermentum ultrices. Praesent blandit luctus feugiat. Nunc est massa, volutpat sed justo sagittis, ultricies pellentesque enim. Mauris lacinia enim ac erat sodales, in feugiat nulla auctor.}]} {:type file, :name song artwork, :extension .png, :preview photos.google.com/abc.jpg}]} {:type file, :name reminder, :extension .txt, :preview Aenean orci dui, dictum at odio sed, malesuada placerat erat. Aliquam eget risus nec lorem convallis commodo. Praesent tincidunt a ligula sed
This is what I'm trying to achieve in Javascript:
const traverseTree = (nodes, depth = 0) => {
nodes.forEach(node => {
updateNodes({...node, depth})
if (node.type === 'folder') {
traverseTree(node.children, depth + 1)
}
})
}
traverseTree(fileTree.root)
};
Update
I did make this work in the end by using doseq like in the answer below. However, I had to get rid of the function using run! and skip the error 2 fix below as suggested:
(defn dispatch-nodes-to-state [nodes & {:keys [depth] :or {depth 0}}]
(doseq [node nodes]
(if (= (node :type) "folder")
(do
(re-frame/dispatch [:set-nodes (conj {:depth depth} node)])
(dispatch-nodes-to-state (node :children) :depth (inc depth)))
(do
(re-frame/dispatch [:set-nodes (conj {:depth depth} node)])
(dispatch-nodes-to-state (node :children) :depth (inc depth))))))
(defn get-file-tree []
(go (let [file-tree (<! (http/get API-URL request-opts))]
(dispatch-nodes-to-state (get-in file-tree [:body :root])))))
You want only a single node in the dispatch… function, but you give a vector of nodes both in the initial call (maybe, don't know what run! actuall does) and in the recur. You need to branch out, e. g. by using mapv or doseq and not recur but an actually recursive call.
Also, you put the depth as keyword argument in the lambda list, but call it with the depth as positional parameter in the recur.
EDIT: What I meant:
(defn dispatch-nodes-to-state [node & {:keys [depth] :or {depth 0}}]
(re-frame/dispatch [:set-nodes (conj {:depth depth} node)])
(if (= (node :type) "folder") ; <-- Here is error #1
(do
(println "It's a folder")
(recur (node :children) (inc depth))) ; <-- Here is error #2
(println "it's a file")))
The error #1 is that in (node :type), node is a vector, not a map. This means that you passed a vector into this function instead of a map.
The error #2 is that in the recur form, you again pass a vector, and that you give the depth not as a keyword argument, but as second positional argument.
There are two possible remedies: either you accept a vector of nodes, or you pass only single nodes.
Accepting a vector of nodes seems to me mostly straightforward, assuming that the other parts are OK:
(defn dispatch-nodes-to-state [nodes & {:keys [depth] :or {depth 0}}]
(doseq [node nodes]
(re-frame/dispatch [:set-nodes (conj {:depth depth} node)])
(if (= (node :type) "folder")
(do
(println "It's a folder")
(dispatch-nodes-to-state (node :children) :depth (inc depth)))
(println "it's a file"))))
Here is how I would do it, without your re-frame details:
(ns tst.demo.core
(:use tupelo.core tupelo.test)
(:require
[clojure.walk :as walk]
[tupelo.string :as ts]))
I added 2 versions of your data
(def data-1
{:depth 0, :type "folder", :empty false, :name "My Documents",
:children [{:type "file", :name "My Text" 1, :extension ".txt, :preview" " In ipsum est, faucibus ac"}
{:type "folder", :empty false, :name "My Music",
:children [{:type "folder", :empty false, :name "Pop",
:children [{:type "folder", :empty false, :name "Rock",
:children [{:type "folder", :empty true, :name "Empty Folder", :children [{:type "yes"}]}
{:type "file", :name "Lyrics", :extension ".txt", :preview "Curabitur molestie ex ligula, ac tincidunt nisi"}]}
{:type "file", :name "Song Lyrics", :extension ".txt", :preview "Nam venenatis nunc eget imperdiet laoreet. Vivamus"}]}
{:type "file", :name "Album Artwork", :extension ".png", :preview "photos.google.com/abc.jpg"}]}
{:type "file", :name "Recipe", :extension ".txt", :preview " Aliquam bibendum lacus ex",}]})
and the 2nd version
(def data-2
{:type "folder",
:empty "false",
:name "My Documents",
:children [{:type "file",
:name "My Text 1",
:extension ".txt",
:preview "In ipsum est, faucibus ac tempor vel, tincidunt ac leo. Vestibulum quis odio nisl. Nulla auctor erat a "}
{:type "folder",
:empty "false",
:name "My Music",
:children [{:type "folder",
:empty "false",
:name "Pop",
:children [{:type "folder",
:empty "false",
:name "Rock",
:children [{:type "folder",
:empty "true",
:name "Empty Folder",
:children []}
{:type "file",
:name "Lyrics",
:extension ".txt",
:preview "Curabitur molestie ex ligula, ac tincidunt nisi tempor sit amet. Nullam eget varius at."}]}
{:type "file",
:name "Song Lyrics",
:extension ".txt",
:preview "Nam venenatis nunc eget imperdiet laoreet. Vivamus luctus luctus neque "}]}]}]})
basic code to print the name & depth using prewalk
(defn print-name-depth
[node]
(with-result node ; don't change node
(if (map? node)
(let [name (:name node)
depth (:depth node)]
(spyx [name depth])))))
How to recursively add depth to each node & its children
(defn add-depth-to-node
[depth node]
(glue node {:depth depth ; add/overwrite dept for current node
:children (let [depth-kids (inc depth)] ; new depth for child nodes
(forv [child (:children node)]
(add-depth-to-node depth-kids child)))}))
And run the whole thing in a test file (w/o actually testing, just printing)
(dotest
(newline)
(let [data-1b (spyx-pretty (add-depth-to-node 0 data-1))
>> (newline)
data-2b (spyx-pretty (add-depth-to-node 0 data-2))]
(newline)
(walk/prewalk print-name-depth data-1b)
(newline)
(walk/prewalk print-name-depth data-2b)))
And the results:
-----------------------------------
Clojure 1.10.1 Java 12.0.1
-----------------------------------
Testing tst.demo.core
(add-depth-to-node 0 data-1) =>
{:depth 0,
:type "folder",
:empty false,
:name "My Documents",
:children
[{:type "file",
:name "My Text",
1 :extension,
".txt, :preview" " In ipsum est, faucibus ac",
:depth 1,
:children []}
{:type "folder",
:empty false,
:name "My Music",
:children
[{:type "folder",
:empty false,
:name "Pop",
:children
[{:type "folder",
:empty false,
:name "Rock",
:children
[{:type "folder",
:empty true,
:name "Empty Folder",
:children [{:type "yes", :depth 5, :children []}],
:depth 4}
{:type "file",
:name "Lyrics",
:extension ".txt",
:preview "Curabitur molestie ex ligula, ac tincidunt nisi",
:depth 4,
:children []}],
:depth 3}
{:type "file",
:name "Song Lyrics",
:extension ".txt",
:preview "Nam venenatis nunc eget imperdiet laoreet. Vivamus",
:depth 3,
:children []}],
:depth 2}
{:type "file",
:name "Album Artwork",
:extension ".png",
:preview "photos.google.com/abc.jpg",
:depth 2,
:children []}],
:depth 1}
{:type "file",
:name "Recipe",
:extension ".txt",
:preview " Aliquam bibendum lacus ex",
:depth 1,
:children []}]}
2nd data set:
(add-depth-to-node 0 data-2) =>
{:type "folder",
:empty "false",
:name "My Documents",
:children
[{:type "file",
:name "My Text 1",
:extension ".txt",
:preview
"In ipsum est, faucibus ac tempor vel, tincidunt ac leo. Vestibulum quis odio nisl. Nulla auctor erat a ",
:depth 1,
:children []}
{:type "folder",
:empty "false",
:name "My Music",
:children
[{:type "folder",
:empty "false",
:name "Pop",
:children
[{:type "folder",
:empty "false",
:name "Rock",
:children
[{:type "folder",
:empty "true",
:name "Empty Folder",
:children [],
:depth 4}
{:type "file",
:name "Lyrics",
:extension ".txt",
:preview
"Curabitur molestie ex ligula, ac tincidunt nisi tempor sit amet. Nullam eget varius at.",
:depth 4,
:children []}],
:depth 3}
{:type "file",
:name "Song Lyrics",
:extension ".txt",
:preview
"Nam venenatis nunc eget imperdiet laoreet. Vivamus luctus luctus neque ",
:depth 3,
:children []}],
:depth 2}],
:depth 1}],
:depth 0}
printing the [name depth] for both data sets:
[name depth] => ["My Documents" 0]
[name depth] => ["My Text" 1]
[name depth] => ["My Music" 1]
[name depth] => ["Pop" 2]
[name depth] => ["Rock" 3]
[name depth] => ["Empty Folder" 4]
[name depth] => [nil 5]
[name depth] => ["Lyrics" 4]
[name depth] => ["Song Lyrics" 3]
[name depth] => ["Album Artwork" 2]
[name depth] => ["Recipe" 1]
[name depth] => ["My Documents" 0]
[name depth] => ["My Text 1" 1]
[name depth] => ["My Music" 1]
[name depth] => ["Pop" 2]
[name depth] => ["Rock" 3]
[name depth] => ["Empty Folder" 4]
[name depth] => ["Lyrics" 4]
[name depth] => ["Song Lyrics" 3]
Related
There is a map like this
{:buyers [{:name "James" :city "Berlin"} {:name "Jane" :city "Milan"}]
:sellers [{:name "Dustin" :city "Turin" :age "21"} {:name "Mark" :city "Milan"}]}
and I need to check only for :sellers that all the keys :name, :city and :age are present and if one is missing drop
that map all together and have a new structure as below:
{:buyers [{:name "James" :city "Berlin"} {:name "Jane" :city "Milan"}]
:sellers [{:name "Dustin" :city "Turin" :age "21"}]}
I came across validateur and I am trying to use it like:
(:require [validateur.validation :as v])
(def my-map {:buyers [{:name "James" :city "Berlin"} {:name "Jane" :city "Milan"}]
:sellers [{:name "Dustin" :city "Turin" :age "21"} {:name "Dustin" :city "Milan" :age "" } {:city "Rome" :age "22"}]})
(defn valid-seller? [mp]
(let [v-set (v/validation-set
(v/presence-of #{:name :city :age}))]
(fmap vec (v-set mp))))
(map valid-seller? (:sellers my-map))
=> ({} {:age ["can't be blank"]} {:name ["can't be blank"]})
But I do not know how to update my map so missing keys or nil values be dropped
To make the code more readable, I created a new predicate, valid-seller?, and put validation there. You can use any of these versions:
Pure Clojure:
(defn valid-seller? [m]
(every? #(contains? m %) [:name :city :age]))
Spec:
[org.clojure/spec.alpha "0.3.218"], require [clojure.spec.alpha :as spec]
(defn valid-seller? [m]
(spec/valid? (spec/keys :req-un [::name ::city ::age]) m))
Malli (if you also want to test type of values):
[metosin/malli "0.8.9"], require [malli.core :as malli]
(defn valid-seller? [m]
(malli/validate [:map
[:name :string]
[:city :string]
[:age :string]] m))
Then I used this predicate:
(update {:buyers [{:name "James" :city "Berlin"} {:name "Jane" :city "Milan"}]
:sellers [{:name "Dustin" :city "Turin" :age "21"} {:name "Mark" :city "Milan"}]}
:sellers
#(filter valid-seller? %))
=>
{:buyers [{:name "James", :city "Berlin"} {:name "Jane", :city "Milan"}],
:sellers ({:name "Dustin", :city "Turin", :age "21"})}
After your answer, I think you should use Malli, as it also checks the type of values. You can use some? for any non-nil value:
(defn valid-seller? [m]
(malli/validate [:map
[:name some?]
[:city some?]
[:age some?]] m))
(let [data {:buyers [{:name "James" :city "Berlin"} {:name "Jane" :city "Milan"}]
:sellers [{:name "Dustin" :city "Turin" :age "21"} {:name "Mark" :city "Milan"}]}]
(update data :sellers #(filter (every-pred :name :city :age) %)))
I am using the libpostal library to find an full address (street, city, state, and postal code) within a news article. libpostal when given input text:
There was an accident at 5 Main Street Boulder, CO 10566 -- which is at the corner of Wilson.
returns a vector:
[{:label "house", :value "there was an accident at 5"}
{:label "road", :value "main street"}
{:label "city", :value "boulder"}
{:label "state", :value "co"}
{:label "postcode", :value "10566"}
{:label "road", :value "which is at the corner of wilson."}
I am wondering if there is a clever way in Clojure to extract a sequence where the :label values occur in a sequence:
[road unit? level? po_box? city state postcode? country?]
where ? represents an optional value in the match.
You could do this with clojure.spec. First define some specs that match your maps' :label values:
(defn has-label? [m label] (= label (:label m)))
(s/def ::city #(has-label? % "city"))
(s/def ::postcode #(has-label? % "postcode"))
(s/def ::state #(has-label? % "state"))
(s/def ::house #(has-label? % "house"))
(s/def ::road #(has-label? % "road"))
Then define a regex spec e.g. s/cat + s/?:
(s/def ::valid-seq
(s/cat :road ::road
:city (s/? ::city) ;; ? = zero or once
:state ::state
:zip (s/? ::postcode)))
Now you can conform or valid?-ate your sequences:
(s/conform ::valid-seq [{:label "road" :value "Damen"}
{:label "city" :value "Chicago"}
{:label "state" :value "IL"}])
=>
{:road {:label "road", :value "Damen"},
:city {:label "city", :value "Chicago"},
:state {:label "state", :value "IL"}}
;; this is also valid, missing an optional value in the middle
(s/conform ::valid-seq [{:label "road" :value "Damen"}
{:label "state" :value "IL"}
{:label "postcode" :value "60622"}])
=>
{:road {:label "road", :value "Damen"},
:state {:label "state", :value "IL"},
:zip {:label "postcode", :value "60622"}}
For a given custom-formatter, parse refuses certain month values.
(require '[clj-time.core :as t]
'[clj-time.format :as f])
(let [custom-formatter (f/formatter "dd MMM yyyy")]
(f/parse custom-formatter "27 mar 2010")
(f/parse custom-formatter "27 dec 2010"))
The first parsereturns the expected result, #object[org.joda.time.DateTime 0x62a9d176 "2010-03-27T00:00:00.000Z"], while the second returns Actual: java.lang.IllegalArgumentException: Invalid format: "27 dec 2010" is malformed at "dec 2010".
I can't make sense of this behavior. What can possibly causes this issue?
Thanks for help.
update
Here's my project.cljfile
:dependencies [[org.clojure/clojure "1.7.0"]
[twitter-api "0.7.8"]
[cheshire "5.6.1"]
[clojure-csv/clojure-csv "2.0.1"]
[org.postgresql/postgresql "9.4-1206-jdbc42"]
[com.jolbox/bonecp "0.8.0.RELEASE"]
[org.clojure/java.jdbc "0.6.1"]
[java-jdbc/dsl "0.1.0"]
[org.slf4j/slf4j-nop "1.7.21"]
[clj-time "0.11.0"]
]
You likely need to specify a Locale for your formatter. You can check to see your default Locale with:
user=> (java.util.Locale/getDefault)
#object[java.util.Locale 0x4713d9a5 "en_US"]
See the results for different locales (including the error you are seeing):
user=> (require '[clj-time.core :as t]
#_=> '[clj-time.format :as f])
nil
user=> (let [custom-formatter (f/with-locale
(f/formatter "dd MMM yyyy")
java.util.Locale/ENGLISH)]
(f/parse custom-formatter "27 mar 2010"))
#object[org.joda.time.DateTime 0x3cfceae6 "2010-03-27T00:00:00.000Z"]
user=> (let [custom-formatter (f/with-locale
(f/formatter "dd MMM yyyy")
java.util.Locale/ITALY)]
(f/parse custom-formatter "27 mar 2010"))
#object[org.joda.time.DateTime 0x4f5e9955 "2010-03-27T00:00:00.000Z"]
user=> (let [custom-formatter (f/with-locale
(f/formatter "dd MMM yyyy")
java.util.Locale/CHINA)]
(f/parse custom-formatter "27 mar 2010"))
IllegalArgumentException Invalid format: "27 mar 2010" is malformed at "mar 2010" org.joda.time.format.DateTimeFormatter.parseDateTime (DateTimeFormatter.java:899)
In a Clojure program I've an array composed by maps containing peoples' names and emails.
e.g.
[
{ :name "John" :email "john#gmail.com" }
{ :name "Batman" :email "batman#gmail.com" }
{ :name "John Doe" :email "john#gmail.com" }
]
I'd like to remove the duplicate entries considering, for comparison purposes, pairs having the same e-mail to be equals. In the example above the output would be:
[
{ :name "John" :email "john#gmail.com" }
{ :name "Batman" :email "batman#gmail.com" }
]
What's the best way to achieve this in Clojure? Is there a way to let distinct knows what equals function to use?
Thanks.
yet another way to do it, kinda more idiomatic, i guess:
(let [items [{ :name "John" :email "john#gmail.com" }
{ :name "Batman" :email "batman#gmail.com" }
{ :name "John Doe" :email "john#gmail.com" }]]
(map first (vals (group-by :email items))))
output:
({:name "John", :email "john#gmail.com"}
{:name "Batman", :email "batman#gmail.com"})
that is how it works:
(group-by :email items) makes a map, whose keys are emails, and values are groups of records with this email
{"john#gmail.com" [{:name "John", :email "john#gmail.com"}
{:name "John Doe", :email "john#gmail.com"}],
"batman#gmail.com" [{:name "Batman", :email "batman#gmail.com"}]}
then you just need to take its vals (groups of records) and select firsts from them.
And another way is to create a sorted set by email, so it will treat all the records with equal emails as equal records:
(let [items [{ :name "John" :email "john#gmail.com" }
{ :name "Batman" :email "batman#gmail.com" }
{ :name "John Doe" :email "john#gmail.com" }]]
(into (sorted-set-by #(compare (:email %1) (:email %2))) items))
output:
#{{:name "Batman", :email "batman#gmail.com"}
{:name "John", :email "john#gmail.com"}}
don't really know which of them is more idiomatic and has a better performance. But i bet on the first one.
This would do it: https://crossclj.info/fun/medley.core/distinct-by.html.
The function in the link goes through every value lazily and stores everything it's seen. If the value in the coll is already seen, it does not add it.
You could then call this as: (distinct-by #(% :email) maps), where maps is your vector of people-maps.
A distinct-by can easily be implemented as
(defn distinct-by [f coll]
(let [groups (group-by f coll)]
(map #(first (groups %)) (distinct (map f coll)))))
For the example case this can be used like
(distinct-by :email
[{:name "John" :email "john#gmail.com"}
{:name "Batman" :email "batman#gmail.com"}
{:name "John Doe" :email "john#gmail.com"}])
I have created a table "sampletable". I am trying to display the name of the columns. I tried adding the text but it still doesn't show the names.
(def sampletable
(seesaw/table :model
[:columns [{:key :name, :text "Name"} :likes]
:rows [["Bobby" "Laura Palmer"]
["Agent Cooper" "Cherry Pie"]
{:likes "Laura Palmer" :name "James"}
{:name "Big Ed" :likes "Norma Jennings"}]]))
Any help would be appreciated.
Try this
(require '[seesaw.table])
(def sampletable
(seesaw/table
:model (seesaw.table/table-model
:columns [{:key :name, :text "Name"} :likes]
:rows [["Bobby" "Laura Palmer"]
["Agent Cooper" "Cherry Pie"]
{:likes "Laura Palmer" :name "James"}
{:name "Big Ed" :likes "Norma Jennings"}])))