I have a string:
{:id 1, :name "Ab Bc Cd", :sex "M", :birth "01.01.1999", :address "Street 1", :oms "0001"}
And i need to convert it to HashMap but
(hash-map my-str)
returns {}
So i splited it:
(s/split my-str ",")
And it returns
[:id 1 :name "Ab Bc Cd" :sex "M" :birth "01.01.1999" :address "Street 1" :oms "0001"]
Then
for [x my-arr]
(hash-map x)
returns
({} {} {} {} {} {})
How can i do this?
If you got this string intentionally, then use
clojure.edn/read-string
E.g.
user=> (require 'clojure.edn)
nil
user=> (clojure.edn/read-string (slurp "x.edn"))
{:id 1, :name "Ab Bc Cd", :sex "M", :birth "01.01.1999", :address "Street 1", :oms "0001"}
your example is almost there!
you can finish it with a call to
(into {} your-result-so-far)
into comes up a lot of you get into the habit of looking for it.
The shortest way would be clojure.core's read-string - it reads from the string and executes the command for building an object:
(def s "{:id 1, :name \"Ab Bc Cd\", :sex \"M\", :birth \"01.01.1999\", :address \"Street 1\", :oms \"0001\"}")
(read-string s)
;; => {:id 1, :name "Ab Bc Cd", :sex "M", :birth "01.01.1999", :address "Street 1", :oms "0001"}
The documentation says:
Reads one object from the string s. Optionally
include reader options, as specified in read. Note that read-string
can execute code (controlled by read-eval), and as such should be
used only with trusted sources. For data structure interop use
clojure.edn/read-string
Related
How would I sort
{
{:name "d" :id 2}
{:name "f" :id 3}
{:name "a" :id 1}
{:name "z" :id 9}
}
Alphabetically by name? Like this:
{
{:name "a" :id 1}
{:name "d" :id 2}
{:name "f" :id 3}
{:name "z" :id 9}
}
When in doubt, be sure to look at the Clojure CheatSheet.
In this case just use sort-by
(def data
[{:name "d" :id 2}
{:name "f" :id 3}
{:name "a" :id 1}
{:name "z" :id 9}])
(sort-by :name data) =>
({:name "a", :id 1}
{:name "d", :id 2}
{:name "f", :id 3}
{:name "z", :id 9})
Note that I had to fix your data to use square brackets [...]
I am new to clojure and need some help.
In clojurescript I build up a html table using a map (stored in atom) e.g.
[{:id 2, :category "Big bang theory", :name "The Big Bang!"}
{:id 3, :category "The big Lebowski", :name "Ethan Coen"}
{:id 4, :category "Chitty Chitty Bang Bang", :name "Roald Dahl"}]
I want to create a search that searches for a word (i.e. "ban") en return a map with those entries that have that word (or part of it) in one of its key values.
In case of "ban" it should return
[{:id 2, :category "Big bang theory", :name "The Big Bang!"}
{:id 4, :category "Chitty Chitty Bang Bang", :name "Roald Dahl"}]
Based on the above map the table updates with only those two entries.
I found some interesting solutions, but they all focus on one key (i.e. :category or :name) but not all keys in the map entry.
I think this tries to achieve the same, but I don't think someone gave the answer. Any help is appreciated :D
(def maps
[{:id 2, :category "Big bang theory", :name "The Big Bang!"}
{:id 3, :category "The big Lebowski", :name "Ethan Coen"}
{:id 4, :category "Chitty Chitty Bang Bang", :name "Roald Dahl"}])
(filter
#(some
(fn [v]
(when (string? v)
(-> v
(str/lower-case)
(str/includes? "ban"))))
(vals %))
maps)
After executing a query against the db, the return of the fuction is the list of maps:
({:id 1 :name "Book 1" :category "Drama"}
{:id 2 :name "Book 2" :category "Drama"}
{:id 3 :name "Book 3" :category "Poetry"}
{:id 4 :name "Book 4" :category "Poetry"}
{:id 5 :name "Book 5" :category "Fantasy"}
{:id 6 :name "Book 6" :category "Fantasy"}
{:id 7 :name "Book 7" :category "Fantasy"}
{:id 8 :name "Book 8" :category "Science fiction"}
{:id 9 :name "Book 9" :category "Science fiction"}
{:id 10 :name "Book 10" :category "Science fiction"}
...)
So, I group data by category and group-by function returns a persistent array-map contains strs keys and vector of maps as vals:
{"Fantasy" [{:category "Fantasy", :name "Book 5", :id 5}
{:category "Fantasy", :name "Book 6", :id 6}
{:category "Fantasy", :name "Book 7", :id 7}],
"Drama" [{:category "Drama", :name "Book 1", :id 1}
{:category "Drama", :name "Book 2", :id 2}],
"Poetry" [{:category "Poetry", :name "Book 3", :id 3}
{:category "Poetry", :name "Book 4", :id 4}],
"Science fiction" [{:category "Science fiction",
:name "Book 8",
:id 8}
{:category "Science fiction",
:name "Book 9",
:id 9}
{:category "Science fiction",
:name "Book 10",
:id 10}]}
Next, I do this:
(doseq [[k [{:keys [id name]} v]] data]
(println k)
(println id name))
The side-effect is:
Drama
1 Book1
Poetry
3 Book3
Fantasy
5 Book5
Science fiction
8 Book8
doseq returned only one value for each key.
How can I get the rest of the values?
The result must be:
Drama
1 Book1
2 Book2
Poetry
3 Book3
4 Book4
Fantasy
5 Book5
6 Book6
7 Book7
Science fiction
8 Book8
9 Book9
10 Book10
you can just make an inner loop like this:
(doseq [[k vs] data]
(println k)
(doseq [{:keys [id name]} vs]
(println id name)))
or using single doseq:
(doseq [[k vs] data
{:keys [id name] :as v} vs]
(when (= v (first vs))
(println k))
(println id name))
also there is one more dirty way to print outer loop string once:
(doseq [[k vs] data
:when (or (println k) true)
{:keys [id name] :as v} vs]
(println id name))
or even like this:
(doseq [[k vs] data
{:keys [id name] :as v} (do (println k) vs)]
(println id name))
I have array of hashes:
#array = [{:id => "1", :status=>"R"},
{:id => "1", :status=>"R"},
{:id => "1", :status=>"B"},
{:id => "1", :status=>"R"}]
How to detect, does it contain in hashes with the value of status "B"? Like in simply array:
#array = ["R","R","B","R"]
puts "Contain B" if #array.include?("B")
Use any?:
#array.any? { |h| h[:status] == "B" }
Arrays (enumerables actually) have a detect method. It returns a nil if it doesn't detect anything, so you can use it like Andrew Marshall's any.
#array = [{:id => "1", :status=>"R"},
{:id => "1", :status=>"R"},
{:id => "1", :status=>"B"},
{:id => "1", :status=>"R"}]
puts "Has status B" if #array.detect{|h| h[:status] == 'B'}
Just to add to what steenslag said:
detect doesn't always return nil.
You can pass in a lambda to execute (call) if detect does not 'detect' (find) an item. In other words, you can tell detect what to do if it can't detect (find) something.
To add to your example:
not_found = lambda { "uh oh. couldn't detect anything!"}
# try to find something that isn't in the Enumerable object:
#array.detect(not_found) {|h| h[:status] == 'X'}
will return "uh oh. couldn't detect anything!"
This means that you don't have to write this kind of code:
if (result = #array.detect {|h| h[:status] == 'X'}).nil?
# show some error, do something here to handle it
# (this would be the behavior you'd put into your lambda)
else
# deal nicely with the result
end
That's one major difference between any? and detect -- you can't tell any? what to do if it doesn't find any items.
This is in the Enumerable class. ref: http://ruby-doc.org/core/classes/Enumerable.html#M003123
I currently want to iterate over an array of Objects (2 properties: id & name) and check if the array contains a specific Id
How would I do this?
Enumerable#detect is ok, but I think that Enumerable#any? (which returns a boolean), is strictly what you asked for:
xs = [{:id => 1, :name => 'a'}, {:id => 2, :name => 'b'}]
puts xs.any? {|x| x[:id] == 1} # true
puts xs.any? {|x| x[:id] == 5} # false
Try detect
a = [{:id => 1, :name => 'a'}, {:id => 2, :name => 'b'}]
puts a.detect {|x| x[:id] == 1}