Basically, I have used slurp to get the contents of a file that is supposed to be a database. I've split the data already once and have a vector that contains all the information correctly. Now I would like to split each element in the vector again. This would give me a vector of vectors. My problem is I can't seem to find the right way to iterate through the vector and make my changes. The changes either don't work or are not stored in the vector.
Using doseq:
(doseq [x tempVector]
(clojure.string/split x #"|")
)
If I add a print statement in the loop it prints everything spaced out with no changes.
What am I doing wrong?
The str/split function returns a new vector of strings, which you need to save. Right now it is being generated and then discarded. You need something like this:
(ns xyz
(:require
[clojure.string :as str]))
(def x "hello there to you")
(def y (str/split x #" ")) ; save result in `y`
(def z (str/split x #"e")) ; save result in `z`
y => ["hello" "there" "to" "you"]
z => ["h" "llo th" "r" " to you"]
You can read clojure basics online here: https://www.braveclojure.com .
I recommend buying the book as it has more stuff than the online version.
If you have several strings in a vector, you can use the map function to split each of them in turn:
(def my-strings
["hello is there anybody in there?"
"just nod if you can hear me"
"is there anyone at home?"])
(def my-strings-split
(mapv #(str/split % #" ") my-strings))
my-strings-split =>
[["hello" "is" "there" "anybody" "in" "there?"]
["just" "nod" "if" "you" "can" "hear" "me"]
["is" "there" "anyone" "at" "home?"]]
To restructure your slurped lines of text into a collection of vectors of words you could do something like:
(use '[clojure.string :as str :only [split]])
(defn file-as-words [filename re]
(let [lines (line-seq (clojure.java.io/reader filename))
line-words (vec (mapv #(str/split %1 re) lines))]
line-words))
Here we define a function which first uses line-seq to slurp the file in and break it into a collection of lines, then we map an anonymous function which invokes clojure.string/split on each line in the initial collection, breaking each line up into a collection of words delimited by the passed-in regular expression. The collection of vectors-of-words is returned.
For example, let's say we have a file named /usr/data/test.dat which contains
Alice,Eating,001
Kitty,Football,006
May,Football,004
If we invoke file-as-words by using
(file-as-words "/usr/data/test.dat" #",")
you get back
[["Alice" "Eating" "001"] ["Kitty" "Football" "006"] ["May" "Football" "004"]]
Related
Question from a total newbie with Clojure. Task is pretty simple, but I'm having hard time finding the best way to do this - I need to set up input, where user could give me a list (user should determine how long) of natural numbers and the program should just return a sum of these numbers.
Maybe this is totally wrong already:
(defn inputlist[naturallist]
(println "Enter list of natural numbers:")
(let[naturallist(read-line)] ))
Here is one way of doing it:
> lein new app demo
> cd demo
Edit the project.clj and src/demo/core.clj so they look as follows:
> cat project.clj
(defproject demo "0.1.0-SNAPSHOT"
:description "FIXME: write description"
:url "http://example.com/FIXME"
:license {:name "Eclipse Public License"
:url "http://www.eclipse.org/legal/epl-v10.html"}
:dependencies [[org.clojure/clojure "1.9.0"]
[org.clojure/tools.reader "1.1.3.1"] ]
:main ^:skip-aot demo.core
:target-path "target/%s"
:profiles {:uberjar {:aot :all}})
> cat src/demo/core.clj
(ns demo.core
(:require
[clojure.tools.reader.edn :as edn]
[clojure.string :as str] ))
(defn -main []
(println "enter numbers")
(let [input-line (read-line)
num-strs (str/split input-line #"\s+")
nums (mapv edn/read-string num-strs)
result (apply + nums) ]
(println "result=" result)))
with result
> lein run
enter numbers
1 2 3 <= you type this, then <enter>
input-line => "1 2 3"
num-strs => ["1" "2" "3"]
nums => [1 2 3]
result => 6
You may wish to start looking at some beginner books as well:
Brave Clojure
Living Clojure
Programming Clojure
The Clojure CheatSheet
The quickest way to do this I can think of is
#(apply + (map #(Integer/parseInt %) (re-seq #"\d+" (read-line))))
This defines an anonymous function which:
(read-line) - reads a line of text, hopefully containing numbers separated by non-numeric characters. So you type in something like "123 456 789"
(re-seq #"\d+" ...) - uses the regular expression \d+ to search for strings of consecutive digits. Each string of consecutive digits is added to a sequence, which is subsequently returned. So, for example, if you type in 123, 456, 789 the re-seq function will return the sequence '("123" "456" "789").
(map #(Integer/parseInt %) ...) - invokes the anonymous function #(Integer/parseInt %) for each element in the list returned by the re-seq invocation, creating another list of the results. So if the input is '("123" "456" "789") the output will be '(123 456 789).
(apply + ...) - applies the + function to the list of numbers, summing them up, and returns the sum.
Et voila! The end result is, you type in a string of numbers, separated by non-numeric characters, you get back the sum of those numbers. If you want to be a little neater, promote code re-use, and in general make this a bit more useful you could break this up into separate functions:
(defn parse-string-list [s]
(re-seq #"\d+" s))
(defn convert-seq-of-int-strings [ss]
(map #(Integer/parseInt %) ss))
(defn sum-numbers-in-seq [ss]
(apply + ss))
Invoking this in a Lisp-y way would look something like
(sum-numbers-in-seq (convert-seq-of-int-strings (parse-string-list (read-line))))
or, in a more Clojure-y way
(-> (read-line)
(parse-string-list)
(convert-seq-of-int-strings)
(sum-numbers-in-seq))
Best of luck.
Welcome to Clojure—and StackOverflow!
Here's how to do it:
(defn input-numbers-and-sum []
(print "Enter list of natural numbers: ")
(flush)
(->> (clojure.string/split (read-line) #"\s+")
(map #(Integer/parseInt %))
(reduce +)))
Here's how it works:
Calling print rather than println avoids printing a newline character at the end of the line. This way, the user's input will appear on the same line as your prompt.
Since there was no newline, you have to call flush to force the output buffer containing the prompt to be printed.
split splits what the user typed into a sequence of strings, divided where a regular expression matches. You have to say clojure.string/split rather than just split because split is not in Clojure's core library. clojure.string/ specifies the library. #"\s+" is a regular expression that matches any number of consecutive whitespace characters. So, if your user types " 6 82 -15 ", split will return ["6" "82" "-15"].
map calls the standard Java library function Integer.parseInt on each of those strings. Integer/parseInt is Clojure's Java interop syntax for calling a static method of a Java class. The #(...) is terse syntax that defines an anonymous function; the % is the argument passed to that function. So, given the sequence of strings above, this call to map will return a sequence of integers: [6 82 -15].
reduce calls the + function repeatedly on each element of the sequence of integers, passing the sum so far as an argument along with the next integer. map and reduce actually take three arguments; the next paragraph tells how the third paragraph gets filled in.
->> is the "thread-last macro". It rewrites the code inside it, to pass the output of each expression but the last as the last argument of the following expression. The result is:(reduce + (map #(Integer/parseInt %) (clojure.string/split (read-line) #"\s+")))Most people find the version with ->> much easier to read.
That might seem like a lot to do something very simple, but it's actually bread and butter once you're used to Clojure. Clojure is designed to make things easy to combine; map, reduce, and ->> are especially useful tools for hooking other functions together.
I've included links to the documentation. Those are worth a look; many contain typical examples of use.
There are other ways to parse numbers, of course, some of which are shown in the answers to this question. What I've written above is an "idiomatic" way to do it. Learn that, and you'll know a lot of the everyday, must-know techniques for programming in Clojure.
Yep, readline is the correct way to do it.
But each element from readlines is essentially an instance of java.lang.Character , and since you want the sum, you'd prefer to convert them to integer before summing the elements of list.
(defn input-list
[]
(print "Enter list of natural numbers")
(let [nums (read-line)]
(reduce + (map #(Integer/parseInt %) (clojure.string/split nums #"\s+")))
This might not be the most idiomatic way to do it, but feel free to tweak it.
Also, please do clean up on your variable/function names.
Edit : (Integer/parseInt %) might cause an error if used directly since the input is an instance of characters, not string. So we can use clojure.string/split to convert user input to a sequence of strings, and use Integer/parseInt % for conversion.
In fact, a more readable version can be written using thread-first macros :
(defn input-list []
(print "Enter list of natural numbers: ")
(->> (clojure.string/split (read-line) #"\s+")
(map #(Integer/parseInt %))
(reduce +)))
This is a more clojurey way to do it.
If you don't care about negative scenarios (wrong input, syntax issues), the quickest solution would be to evaluate the user's input putting it into parens:
(defn sum-ints []
(let [input (read-line)
ints (read-string (str "(" input ")"))]
(reduce + 0 ints)))
Usage:
user=> (sum-ints)
1 2 3 4 5
15
The read-string function evaluates an text expression (1 2 3 4 5) in that case. Since numeral literals turn into numbers, the result will be just a list of numbers.
So I know this isn't the best method of solving this issue, but I'm trying to go through a list of lines from an input file, which end up being expressions. I've got a list of expressions, and each expression has it's own list thanks to the split-the-list function. My next step is to replace characters with id, ints with int, and + or - with addop. I've got the regexes to find whether or not my symbols match any of those, but when I try and replace them, I can only get the last for loop I call to leave any lasting results. I know what it stems down to is the way functional programming works, but I can't wrap my head around the trace of this program, and how to replace each separate type of input and keep the results all in one list.
(def reint #"\d++")
(def reid #"[a-zA-Z]+")
(def readdop #"\+|\-")
(def lines (into () (into () (clojure.string/split-lines (slurp "input.txt")) )))
(defn split-the-line [line] (clojure.string/split line #" " ))
(defn split-the-list [] (for [x (into [] lines)] (split-the-line x)))
(defn tokenize-the-line [line]
(for [x line] (clojure.string/replace x reid "id"))
(for [x line] (clojure.string/replace x reint "int"))
(for [x line] (clojure.string/replace x readdop "addop")))
(defn tokenize-the-list [] (for [x (into [] (split-the-list) )] (tokenize-the-line x)))
And as you can probably tell, I'm pretty new to functional programming, so any advice is welcome!
You're using a do block, which evaluates several expressions (normally for side effects) and then returns the last one. You can't see it because fn (and hence defn) implicitly contain one. As such, the lines
(for [x line] (clojure.string/replace x reid "id"))
(for [x line] (clojure.string/replace x reint "int"))
are evaluated (into two different lazy sequences) and then thrown away.
In order for them to affect the return value, you have to capture their return values and use them in the next round of replacements.
In this case, I think the most natural way to compose your replacements is the threading macro ->:
(for [x line]
(-> x
(clojure.string/replace reid "id")
(clojure.string/replace reint "int")
(clojure.string/replace readdop "addop")))
This creates code which does the reid replace with x as the first argument, then does the reint replace with the result of that as the first argument and so on.
Alternatively you could do this by using comp to compose anonymous functions like (fn [s] (clojure.string/replace s reid "id") (partial application of replace). In the imperative world we get pretty used to running several procedures that "bash the data in place" - in the functional world you more often combine several functions together to do all the operations and then run the result.
Question:How to I turn Read-Line into a usable vector to pass in to another function to do work.
(defn iAcceptUserInputAsAVector [a b c] ( )) ; I do work with the userInput as a vector
(defn input []
(let [userKeyboardInput ( read-line)]
(
[userKeyboardInput]; doesnt work I tried (vector userKeyboardInput)
)
)
)
Update 1: My Progress so far thanks to noisesmith
(defn input []( let [userKeyBoardInput [(read-line)]]
(println userKeyBoardInput)
))
Update 2 My current solution and working... I imagine it can be done so much better
(defn split-by-whitespace [s]
(clojure.string/split s #"\s+"))
(defn input []
( let [userKeyBoardInput [(split-by-whitespace(read-line))]]
;Then insanity below is because I have to convert to integers, list then a vector. Why? map returns list
;which I dont need instead I need a vector []
;Also the initial entry is returned as [[]] which I need to convert to [] for map to be able to take
;it as parameter. There probably a better way. Show me...
(def x (into[](map #(Integer/parseInt %) (into [](flatten [userKeyBoardInput])))))
(println x)
(myLoopFunc x); basically it takes my vector and does something .. not important
))
Parenthesis are not a grouping construct in Clojure.
There are two major errors in your code:
((read-line)) this gets a string via read-line and then attempts to execute it. This will fail, strings do not implement IFn.
([userKeyboardInput]) if the code even got this far, this would fail as well, because you can't call a vector as a function without providing any arguments.
In clojure, wrapping something in parens usually means you want to execute it as a function. Adding extraneous parens will easily break things.
I will comment on how to improve your current solution (source code comments removed, linenumbers added):
01: (defn split-by-whitespace [s]
02: (clojure.string/split s #"\s+"))
03:
04: (defn input []
05: ( let [userKeyBoardInput [(split-by-whitespace(read-line))]]
06: (def x (into[](map #(Integer/parseInt %) (into [](flatten [userKeyBoardInput])))))
07: (println x)
08: (myLoopFunc x)
09:
10: ))
The function split-by-whitespace looks good. Note that it already returns a vector. (Suppose read-line returned "6 34 12". Then split-by-whitespace will give you ["6" "34" "12"]). So when you call it in line 5, you do not need the [] around your call, because you don't want a vector in a vector. Therefore, you no longer need flatten. You can just map over the vector you already have. Then a function that did the desired transformation for you would look like this:
(defn string->number-vector ; name is verbose but meaning is clear :)
[s]
(into []
(map #(Integer/parseInt %)
(split-by-whitespace s))))
And you might call it with (myLoopFunc (string->number-vector (read-line))).
Iam new to clojure and need some help to get a value out of a lazy sequence.
You can have a look at my full data structure here: http://pastebin.com/ynLJaLaP
What I need is the content of the title:
{: _content AlbumTitel2}
I managed to get a list of all _content values:
(def albumtitle (map #(str (get % :title)) photosets))
(println albumtitle)
and the result is:
({:_content AlbumTitel2} {:_content test} {:_content AlbumTitel} {:_content album123} {:_content speciale} {:_content neues B5 Album} {:_content Album Nr 2})
But how can I get the value of every :_content?
Any help would be appreciated!
Thanks!
You could simply do this
(map (comp :_content :title) photosets)
Keywords work as functions, so the composition with comp will first retrieve the :title value of each photoset and then further retrieve the :_content value of that value.
Alternatively this could be written as
(map #(get-in % [:title :_content]) photosets)
A semi alternative solution is to do
(->> data
(map :title)
(map :_content))
This take advances of the fact that keywords are functions and the so called thread last macro. What it does is injecting the result of the first expression in as the last argument of the second etc..
The above code gets converted to
(map :_content (map :title data))
Clearly not as readable, and not easy to expand later either.
PS I asume something went wrong when the data was pasted to the web, because:
{: _content AlbumTitel2}
Is not Clojure syntax, this however is:
{:_content "AlbumTitel2"}
No the whitespace after :, and "" around text. Just in case you might want to paste some Clojure some other time.
I have the following string
layout: default
title: Envy Labs
What i am trying to do is create map from it
layout->default
title->"envy labs"
Is this possible to do using sequence functions or do i have to loop through each line?
Trying to get a regex to work with and failing using.
(apply hash-map (re-split #": " meta-info))
user> (let [x "layout: default\ntitle: Envy Labs"]
(reduce (fn [h [_ k v]] (assoc h k v))
{}
(re-seq #"([^:]+): (.+)(\n|$)" x)))
{"title" "Envy Labs", "layout" "default"}
The _ is a variable name used to indicate that you don't care about the value of the variable (in this case, the whole matched string).
I'd recommend using clojure-contrib/duck-streams/read-lines to process the lines then split the fields from there. I find this method is usually more robust to errors in the file.