Manipulate string from File Stream in Elixir - stream

I am new to Elixir.
I am trying to take text from a File to turn into a graph.
The file is formatted as such:
1 2
1 3
2 3
Each number being the ID of connected nodes.
How can I take the 2 values from the String.split/1 function to somewhere else in the program ? This is what I had so far:
File.stream!("../text_file")
|> Stream.map( &(String.replace(&1, "\n", "")))
|> Enum.each(String.split/1)
It will only output the :ok atom, but it will print the content if I swap String.split/1 for IO.puts/1

Enum.each/2 is meant to be used with functions where you don't care about the return value (usually functions with only side effects, like IO.puts). If you want to collect the returned data, you need Enum.map/2. Also, if you want to delete trailing whitespace, you should use String.trim_trailing/1)
File.stream!("a")
|> Stream.map(&String.trim_trailing/1)
|> Enum.map(&String.split/1)
|> IO.inspect
Output:
[["1", "2"], ["1", "3"], ["2", "3"]]

Related

What does parameter a and b mean in an array of elements in Ruby?

I'm practicing the sort function, the target is an array (ary) of a sentence. An example method I have seen is to build and use a block, and finally arrange the elements (words) in the array from short to long, and from a to z.
But I don't understand why there are two parameters a and b in this example, why should we find out a.length and b.length first? This is the original code:
ary = %w(
Ruby is a open source programming language with a afocus on simplicity and productivity.
)
call_num = 0
sorted = ary.sort do |a, b|
call_num += 1
a.length <=> b.length
end
puts "Sort results: #{sorted}" #=>["a", "a", "on", "is", "and", "Ruby", "open", "with", "afocus", "source", "language", "simplicity", "programming", "productivity."]
puts "Number of array elements: #{ary.length}" #=> 14
puts "Number of calls to blocks: #{call_num}" #=>30
To sort the following array of words by their length Ruby has to basically compare each word in the array to each other word (Note that this is not exactly how sorting works internally but in the context of this example we can assume that sorting works like this).
ary = %w(
Ruby is a open source programming language with a afocus on simplicity and productivity.
)
That means in the first step Ruby will need to compare the words Ruby and is and has to decide how to sort those two words, then is and a, then a and open.
Those two words in each step of the comparison are the two block parameters a and b. a.length <=> b.length will then tell Ruby how to sort those two parameters (words).
See Comparable and Enumerable#sort

Q: F#: Iterate through highscore file and pick top 3

On my mission to master F# I'm creating a pocket game.
I'm at the point where I want to implement some sort of a highscore list.
So far I'm writing Name, Score and Time to a file which then reads in to the application displaying all previous scores. Yes, this isn't ideal as the list grows pretty quick.
I somewhat want to pick the top 3 scores, not caring about Name or Time.
Question: Should I read the file into an array/list and from there pick out the top scores or is there a nicer way to pick out the top scores directly from the file?
Pointers, Code, Tips and Tricks are warmly welcome.
let scoreFile = sprintf ("Name: %s\nTime: %i sec\nScore: %d\n\n") name stopWatch.Elapsed.Seconds finalScore
let readExistingFile = File.ReadAllText ("hiscore.txt")
File.WriteAllText ("hiscore.txt", scoreFile + readExistingFile)
let msg = File.ReadAllText ("hiscore.txt")
printfn "\nHighscores:\n\n%s\n\n\n\nPress ANY key to quit." msg
Should I read the file into an array/list and from there pick out the top scores or is there a nicer way to pick out the top scores directly from the file?
Unless the scores are already sorted in the file, you'll have to look through them all to find out what the Top 3 is. The way your file is written right now, parsing the data back might be a bit hard - scores are stored on multiple lines, so you'd have to handle that.
Assuming the file doesn't have to be human-friendly, I'd go with a list of comma-separated values instead. It's harder for a human to read by opening the file, but it makes it a lot easier to parse in your program. For example, if the lines looks like Name,Time,Score, they can be parsed like this:
type ScoreData = {
Name : string
Time : string // could be a DateTime, using string for simplicity
Score : int
}
let readHighScores file =
File.ReadAllLines file
|> Array.choose (fun line ->
match line.Split ',' with
| [| name; time; score |] ->
{
Name = name
Time = time
Score = (int)score // This will crash if the score isn't an integer - see paragraph below.
}
|> Some
| _ ->
// Line doesn't match the expected format, we'll just drop it
None
)
|> Array.sortBy (fun scoreData -> -scoreData.Score) // Negative score, so that the highest score comes first
|> Seq.take 3
This will read through your file and output the three largest scores. Using Array.choose allows you to only keep lines that match the format you're expecting. This also lets you add extra validation as needed, such as making sure that the score is an integer and perhaps parsing the Time into a System.DateTime instead of storing it as an int.
You can then print your high scores by doing something like this:
let highScores = readHighScores "hiscore.txt"
printfn "High scores:"
highScores
|> Seq.iteri (fun index data ->
printfn "#%i:" (index + 1)
printfn " Name: %s" data.Name
printfn " Time: %s" data.Time
printfn " Score: %i" data.Score
)
This calls the previously defined function and prints each of the scores returned - the top 3, in this case. Using Seq.iteri, you can include the index in the output in addition to the score data itself. Using some data I made up, it ends up looking like this:
High scores:
#1:
Name: Awots
Time: 2015-06-15
Score: 2300
#2:
Name: Roujo
Time: 2016-03-01
Score: 2200
#3:
Name: Awots
Time: 2016-03-02
Score: 2100
Now, there might be a way to do this without loading the entire file at once in memory, but I don't think it'd be worth it unless you have a really large file - in which case you might want to either keep it sorted or use a more fit storage method like a database.

How to PARSE a sequence of items where items not in blocks are handled like single element blocks?

I've got a situation where I want an equivalence, such that:
[
{Foo}
http://example.com/some/stuff.html
separator
]
...is handled just as if you had written:
[
[{Foo}]
[http://example.com/some/stuff.html]
[separator]
]
Adding a little to the complexity is that if you put the item in a block, then it can have arguments:
[
[{Foo} /some-refinement]
[http://example.com/some/stuff.html {stuff caption} 3]
[separator dashed-line]
]
I'd like a PARSE-based engine that can run the same handler for {Foo}, [{Foo}], and [{Foo} /some-refinement] (let's call it STRING-HANDLER), and have it merely invoked with the right number of parameters.
To write this without PARSE is easy... a single element is wrapped in a temporary block (in the case it's not a block). Then the first item is tested in a CASE statement. But I'd like to convert this to be PARSE-based, where one branch uses INTO while another does not, without repeating code.
It will need to support nesting, so you might wind up processing something like:
[http://example.com/some/stuff.html [{Foo} /some-refinement] 3]
I hope the following can be the basis for your solution.
The following performs exactly the same in both R2 and R3. PARSE's 'into operation is VERY different between the two so I put a simple guard [.here.: block! :.here.] which fixes different bug situations in both platforms.
I used hook functions which allow to cleanly separate the data browsing from the data evaluation. If you look closely, you will notice that the =enter-block?=: rule is global and that the code which switches its meaning is setup BEFORE running the emit-value function... so in some cases, you might actually want to use emit-value to setup a different rule.
note that I'm not assuming any kind of known structure as your explanation seems to be meant for unstructured datasets.
Also note that test B is setup as a string, so we can use the wrapper directly on string input data:
rebol [
author: "Maxim Olivier-Adlhoch"
date: 2014-02-08
license: "public domain"
]
A: [
[{Foo}]
[http://example.com/some/stuff.html]
[separator]
]
B: {[
{Foo}
http://example.com/some/stuff.html
separator
]}
C: [
[{Foo} /some-refinement]
[http://example.com/some/stuff.html {stuff caption} 3]
[separator dashed-line]
]
D: [http://example.com/some/stuff.html [{Foo} /some-refinement] 3]
depth: ""
enter-block: func [][
prin depth
print "["
append depth "^-"
]
quit-block: func [][
remove depth
prin depth
print "]"
]
emit-value: func [value][
prin depth
probe value
]
=enter-block?=: none
=block=: [
(
=enter-block?=: [into =block=] ; we enter blocks by default
enter-block
)
some [
.here.: block! :.here. ; only enter blocks (R3/R2 compatible)
(if 1 = length? .value.: first .here. [ =enter-block?=: [skip] emit-value first .value. ])
=enter-block?=
| set .value. skip ( emit-value .value. )
]
(quit-block)
]
STRING-HANDLER: func [data][
if string? data [
data: load data
]
parse data =block=
]
STRING-HANDLER A
STRING-HANDLER B
STRING-HANDLER C
STRING-HANDLER D
ask "press enter to quit ..."

Sorting an array in Ruby (Special Case)

I have an array in Ruby which has values as follows
xs = %w(2.0.0.1
2.0.0.6
2.0.1.10
2.0.1.5
2.0.0.8)
and so on. I want to sort the array such that the final result should be something like this :
ys = %w(2.0.0.1
2.0.0.6
2.0.0.8
2.0.1.5
2.0.1.10)
I have tried using the array.sort function, but it places "2.0.1.10" before "2.0.1.5". I am not sure why that happens
Using a Schwartzian transform (Enumerable#sort_by), and taking advantage of the lexicographical order defined by an array of integers (Array#<=>):
sorted_ips = ips.sort_by { |ip| ip.split(".").map(&:to_i) }
Can you please explain a bit more elaborately
You cannot compare strings containing numbers: "2" > "1", yes, but "11" < "2" because strings are compared lexicographically, like words in a dictionary. Therefore, you must convert the ip into something than can be compared (array of integers): ip.split(".").map(&:to_i). For example "1.2.10.3" is converted to [1, 2, 10, 3]. Let's call this transformation f.
You could now use Enumerable#sort: ips.sort { |ip1, ip2| f(ip1) <=> f(ip2) }, but check always if the higher abstraction Enumerable#sort_by can be used instead. In this case: ips.sort_by { |ip| f(ip) }. You can read it as "take the ips and sort them by the order defined by the f mapping".
Split your data into chunks by splitting on '.'. There is no standard function to do it as such so you need to write a custom sort to perform this.
And the behaviour you said about 2.0.1.10 before 2.0.1.5 is expected because it is taking the data as strings and doing ASCII comparisons, leading to the result that you see.
arr1 = "2.0.0.1".split('.')
arr2 = "2.0.0.6".split('.')
Compare both arr1 and arr2 element by element, for all the data in your input.

How can I teach Tcl to automatically print my object with a proc I provide?

I have an object that Tcl shows in the console as being its object id. How can I extend Tcl such that whenever objects of my type are printed, a special proc is automatically called that I provide to print their contents instead of just giving the object id?
Some more details: I am emulating a lisp list in Tcl which is built up out of cons cells that each have a car and a cdr. The list of 1 "two" 3 would be created with:
(cons 1 (cons "two" (cons 3 nil)))
which creates 3 cons cells. The top cons cell that has 1 in its car has a pointer to the second cons cell that has "two" in its car, etc.
With this representation, I wish for the above sample list to print out as:
(1 "two" 3)
I assume you're working at the C level. Basically, you register a function to do this in your Tcl_ObjType structure, in the updateStringProc field. Your function will need to produce a string rendering of your overall value (stored in a ckalloced string in the bytes field of the Tcl_Obj); how to do so is up to you.

Resources