Exercises in programming style with Scala - scala

I've started to read the "Exercises in programming style" book recently and one of the tasks there is to implement each programming style in a language of your choice. I decided to go with Scala (I'm fairly new to it) and I'm already stuck with the first "good old school" style. The constraints are:
Very small amount of primary memory, typically orders of magnitude smaller than the data that needs to be processed/generated. (The example sets the limit to 1024 cells)
No labels -- i.e. no variable names or tagged memory addresses. All we have is memory that is addressable with numbers.
Original example (which reads a file line by line and counts the words) is in Python and goes like this:
data = []
data.append([]) # data[1] is line (max 80 characters)
data.append(None) # data[2] is index of the start_char of word
data.append(0) # data[3] is index on characters, i = 0
data.append(False) # data[4] is flag indicating if word was found
data.append('') # data[5] is the word
data.append('') # data[6] is word,NNNN
data.append(0) # data[7] is frequency
...
f = open(sys.argv[1])
# Loop over input file's lines
while True:
data[1] = [f.readline()]
...
So we see there are some variables (f and data) but the main idea is to keep it to a minimum and use python array as a bunch of "memory addresses".
Is it even possible to implement old-school-programming style (no variable names or tagged memory addresses) in Scala? Specifically is there a way to avoid "line" variable when reading file content?
for (line <- Source.fromFile("example.txt").getLines) {
println(line.toUpperCase)
}
Reading the file content into an array similar to the original example doesn't work because it's doesn't have an extractor (value data is not a case class, nor does it have an unapply/unapplySeq member).
P.S. I'm very well aware of the fact that the whole task is probably a 5-liner in Scala but that's not the point.

Sure you can abstain from introducing variables besides the data-array (and solve the problem imperative-style). Simply put everything into your array instead of assigning it to a local variable.
Obviously, the code will be a nightmare, because the array won't be typed and you won't have any meaningful names for any of your data, but I'm assuming that's what you're aiming for with this exercise.
import scala.io.Source
/**
* data 0 : file as line iterator
* data 1 : index of first unused data cell
* data 2 : current line
* data 3 : index of the first letter of the current word
* data 4 : index of the last letter of the current word
* data 5 : current word
* data 6 : temp index to find already initialized words
* data 7 : flag: Word found
* data 8, 10, 12, ... words
* data 9, 11, 13, ... frequencies
*/
object GoodOldSchool {
def main(args: Array[String]): Unit = {
val data: Array[Any] = new Array[Any](1024)
data(0) = Source.fromFile(args(0)).getLines()
data(1) = 8 // first free cell
while (data(0).asInstanceOf[Iterator[String]].hasNext) {
data(2) = data(0).asInstanceOf[Iterator[String]].next()
data(3) = 0 // index first letter of current word
data(4) = 0 // index last letter of current word
// find index last letter of current word
while (data(4).asInstanceOf[Int] < data(2).asInstanceOf[String].length) {
// find the next space (we ignore punctuation)
while (data(4).asInstanceOf[Int] < data(2).asInstanceOf[String].length && data(2).asInstanceOf[String].charAt(data(4).asInstanceOf[Int]) != ' ') {
data(4) = data(4).asInstanceOf[Int] + 1
}
data(5) = data(2).asInstanceOf[String].substring(data(3).asInstanceOf[Int], data(4).asInstanceOf[Int]) // current word
data(6) = 8 // cell index
data(7) = false // word already found
8 until data(1).asInstanceOf[Int] by 2 foreach { _ =>
// Here, we do a case-sensitive word comparison
if (data(5) == data(data(6).asInstanceOf[Int])) {
data(data(6).asInstanceOf[Int] + 1) = data(data(6).asInstanceOf[Int] + 1).asInstanceOf[Int] + 1 // increment frequency
data(7) = true
}
data(6) = data(6).asInstanceOf[Int] + 2
}
if (data(7) == false) {
// create new frequency, because word was not discovered before
data(data(1).asInstanceOf[Int]) = data(5) // set word
data(data(1).asInstanceOf[Int] + 1) = 1 // set frequency
data(1) = data(1).asInstanceOf[Int] + 2 // used up two cells, update index of next free cell
}
// move to next word
data(3) = data(4).asInstanceOf[Int] + 1
data(4) = data(3)
}
}
data foreach println // let's have a look at our result
}
}

To get the total words count in the given file, the following scala code can be used:
Source.fromFile("example.txt")
.getLines.map { line => line.trim.split(" ").length}
.reduceLeft { _ + _ }

Related

Exporting output results from a model into the input of a different model

I'm trying to build a model of a factory using the personal learning edition of AnyLogic. Since this version has a limited number of blocks per model, building the full factory on a single model is presenting itself as an impossible task. In order to surpass this issue I want to split the factorys main processes into different models, which means I'll have to feed the output of process A into the input of process B.
My question is: how can I export a time stamped output of a model into the input of a different model?
Thank you in advance.
You have 2 options
Option 1: Through an Excel file (or txt file)
Simply link an Excel file in your model, using the object from the connectivity palette
Then you can get the data using code similar to below
int excelRow = 2;
String sheetName = "Sheet1!";
String cellName = sheetName + "A" + excelRow;
while (excelFile.cellExists( cellName )) {
int x = (int)excelFile.getCellNumericValue( sheetName + "A" + excelRow);
int b = (int)excelFile.getCellNumericValue( sheetName + "B" + excelRow);
int c = (int)excelFile.getCellNumericValue( sheetName + "C" + excelRow);
boolean d = excelFile.getCellBooleanValue( sheetName + "D" + excelRow);
excelRow ++; // Increase the row that we will lookup in the Excel
}
Just a while loop where you go from one excel line to the next as long as the line exists, and then do what ever is needed with the data
Option 2: AnyLogic Internal DB
Simply import your excel sheet to the AnyLogic DB and then loop over the entries in the table using a for loop
List<Tuple> rows = selectFrom(db_table).list();
for (Tuple row : rows) {
traceln(
row.get( db_table.db_column )
);
}

Better way to find sums in a grid in Swift

I have an app with a 6x7 grid that lets the user input values. After each value is obtained the app checks to find if any of the consecutive values create a sum of ten and executes further code (which I have working well for the 4 test cases I've written). So far I've been writing if statements similar to the below:
func findTens() {
if (rowOneColumnOnePlaceHolderValue + rowOneColumnTwoPlaceHolderValue) == 10 {
//code to execute
} else if (rowOneColumnOnePlaceHolderValue + rowOneColumnTwoPlaceHolderValue + rowOneColumnThreePlaceHolderValue) == 10 {
//code to execute
} else if (rowOneColumnOnePlaceHolderValue + rowOneColumnTwoPlaceHolderValue + rowOneColumnThreePlaceHolderValue + rowOneColumnFourPlaceHolderValue) == 10 {
//code to execute
} else if (rowOneColumnOnePlaceHolderValue + rowOneColumnTwoPlaceHolderValue + rowOneColumnThreePlaceHolderValue + rowOneColumnFourPlaceHolderValue + rowOneColumnFivePlaceHolderValue) == 10 {
//code to execute
}
That's not quite halfway through row one, and it will end up being a very large set of if statements (231 if I'm calculating correctly, since a single 7 column row would be 1,2-1,2,3-...-2,3-2,3,4-...-67 so 21 possibilities per row). I think there must be a more concise way of doing it but I've struggled to find something better.
I've thought about using an array of each of the rowXColumnYPlaceHolderValue variables similar to the below:
let rowOnePlaceHolderArray = [rowOneColumnOnePlaceHolderValue, rowOneColumnTwoPlaceHolderValue, rowOneColumnThreePlaceHolderValue, rowOneColumnFourPlaceHolderValue, rowOneColumnFivePlaceHolderValue, rowOneColumnSixPlaceHolderValue, rowOneColumnSevenPlaceHolderValue]
for row in rowOnePlaceHolderArray {
//compare each element of the array here, 126 comparisons
}
But I'm struggling to find a next step to that approach, in addition to the fact that those array elements then apparently because copies and not references to the original array anymore...
I've been lucky enough to find some fairly clever solutions to some of the other issues I've come across for the app, but this one has given me trouble for about a week now so I wanted to ask for help to see what ideas I might be missing. It's possible that there will not be another approach that is significantly better than the 231 if statement approach, which will be ok. Thank you in advance!
Here's an idea (off the top of my head; I have not bothered to optimize). I'll assume that your goal is:
Given an array of Int, find the first consecutive elements that sum to a given Int total.
Your use of "10" as a target total is just a special case of that.
So I'll look for consecutive elements that sum to a given total, and if I find them, I'll return their range within the original array. If I don't find any, I'll return nil.
Here we go:
extension Array where Element == Int {
func rangeOfSum(_ sum: Int) -> Range<Int>? {
newstart:
for start in 0..<count-1 {
let slice = dropFirst(start)
for n in 2...slice.count {
let total = slice.prefix(n).reduce(0,+)
if total == sum {
return start..<(start+n)
}
if total > sum {
continue newstart
}
if n == slice.count && total < sum {
return nil
}
}
}
return nil
}
}
Examples:
[1, 8, 6, 2, 8, 4].rangeOfSum(10) // 3..<5, i.e. 2,8
[1, 8, 1, 2, 8, 4].rangeOfSum(10) // 0..<3, i.e. 1,8,1
[1, 8, 3, 2, 9, 4].rangeOfSum(10) // nil
Okay, so now that we've got that, extracting each possible row or column from the grid (or whatever the purpose of the game is) is left as an exercise for the reader. 🙂

Is there a way to only keep the last two saved values of the recursion in a dictionary and delete the rest?

i am using memoization to save the last calculated values of fibonacci numbers in a dictionary. Since (i suppose) that we don't need all of the values that were previously calculated in our dictionary so, i want to delete them. specifically i only want to keep only the last two calculated fibonacci numbers, is there a way to do it?
import sys
sys.setrecursionlimit(10000)
cache = {}
def fib(n):
if n in cache:
return cache[n]
elif n <= 2:
value = 1
else:
value = fib(n-1) + fib(n-2)
cache[n] = value
return value
print(fib(1000))
ok i found it.
cache = {}
for x in range(1, 1000001):
if x > 4:
cache.pop(x-3, x-4)
if x <= 2:
value = 1
cache[x] = value
else:
value = cache[x - 1] + cache[x - 2]
cache[x] = value
print(value)

Sorting an array into a 'histogram'

I am a fairly new software Engineering student, so my knowledge is limited.
I have been given a task to sort an array, which in this case is a set of lottery numbers to give a graph like output in the console, I could do this using a whole bunch of match statements but feel there must be a better way.
this is the exact brief given:
Suppose that the following declaration defines the number of times that each of the national lottery balls (1 ..49) has been drawn over a given period.
var lottery = Array(23,16,18,19,26,13,22, /* 1 .. 7 */
20,14,22,18,21,15,17, /* 8 .. 14 */
24,15,18,20,13,14,20, /* 15 .. 21 */
18,22,20,16,19,11,20, /* 22 .. 28 */
16,28,22,20,15,17,17, /* 29 .. 35 */
21,21,19,20,14,22,25, /* 36 .. 42 */
19,17,26,18,20,23,12); /* 43 .. 49 */
write a program to print a histogram showing the information graphically using stars like so:
1 (23) | **********************
2 (16) | ************
and so on..
any hints/ advice on how to accomplish this would be appreciated as it has stumped me thus far. I am not asking for an exact solution just some guidance on what methods i could use to accomplish them as it is likely I have not come across them.
Thank you and have a good day.
Edit - the first way I completed the task.
object lottery {
def main(args: Array[String]): Unit = {
var lotteryIndex = 1
var lottery = Array(23,16,18,19,26,13,22, /* 1 .. 7 */
20,14,22,18,21,15,17, /* 8 .. 14 */
24,15,18,20,13,14,20, /* 15 .. 21 */
18,22,20,16,19,11,20, /* 22 .. 28 */
16,28,22,20,15,17,17, /* 29 .. 35 */
21,21,19,20,14,22,25, /* 36 .. 42 */
19,17,26,18,20,23,12); /* 43 .. 49 */
scala.util.Sorting.quickSort(lottery)
var i = 1
while(i < lottery.length){
if(lottery(i) != lottery(i-1)){
print("\n" + lotteryIndex + " (" + lottery(i) + ") | " + "*")
i += 1
lotteryIndex += 1
}else{
print("*")
i += 1
}
}
}
}
This is fairly straightforward. Each value in the array is the frequency count of the index, so you need to be able to create a string of asterisks ('*') whose length is the same as the frequency count. This can be achieved any number of ways, but perhaps the simplest is to define a function as follows:
def ast(fc: Int) = "*" * fc
Where fc is the frequency count and the number of asterisks required. So, for example, if fc is 5, the result of this expression will be "*****".
Next we need a function that creates a line of output, given a ball number (bn) and the corresponding frequency count (fc):
def line(bn: Int, fc: Int) = f"$bn%2d ($fc%2d) | ${ast(fc)}%s"
Let's explain what's happening here. The f prefix to the string tells Scala that it contains string formatting information and must be interpolated. (Refer to this explanation for further information.)
Whenever a $ is encountered, whatever follows is treated as an expression that needs to converted to a string in the output. If the expression isn't a simple one such as just a variable or value name (if it's a function call, for example), then the expression must be wrapped inside braces (e.g. ${...}). If a % follows the expression, then it identifies the format of the expression in a manner similar to the C language std::printf function.
So: $bn%2d converts the integer value bn into a two-digit decimal string; $fc%2d converts the integer value fc into a two-digit decimal string; and ${ast(fc)}%s calls the function ast passing fc as an argument, and then inserts the resulting string into the output. (The %s is redundant in this latter case.)
(Note: One of the comments on your original question specifies a format of %2s. While this correctly formats the output to two characters, it doesn't check that the argument type is integer, and is, therefore, not recommended.)
Now we need to iterate through the array to call this latter function for each member of the array...
Firstly, note that we need the index as well as the value (the ball number is the array index + 1, since arrays are 0-based). The first step is to convert lottery from an Array[Int] into an Array[(Int, Int)] via the zipWithIndex method. This takes each index-value pair in the lottery array, and combines them into a tuple (with the value first, then the index), placing the result in another array.
We can then map each tuple value in the result to a line of output as follows:
val lines = lottery.zipWithIndex.map {
case (fc, idx) => line(idx + 1, fc)
}
The above is a way of breaking open the tuple using a partial function. If you don't mind using tuple access members, this can also be achieved more tersely (but also more obfuscatedly) using:
val lines = lottery.zipWithIndex.map(p => line(p._2 + 1, p._1))
where p is a tuple of array index and frequency count. Choose whichever method you prefer.
Finally, we can iterate on the result to print out each line of the result:
lines.foreach(println)
This latter is a shorthand for:
lines.foreach(l => println(l))
So, putting this all together, we end up with the following:
object Lottery
extends App {
// Lottery data
val lottery = Array(23,16,18,19,26,13,22, /* 1 .. 7 */
20,14,22,18,21,15,17, /* 8 .. 14 */
24,15,18,20,13,14,20, /* 15 .. 21 */
18,22,20,16,19,11,20, /* 22 .. 28 */
16,28,22,20,15,17,17, /* 29 .. 35 */
21,21,19,20,14,22,25, /* 36 .. 42 */
19,17,26,18,20,23,12) /* 43 .. 49 */
// Get a string of asterisks of the required length.
def ast(fc: Int) = "*" * fc
// Get a line of the histogram from a ball number and frequency count.
def line(bn: Int, fc: Int) = f"$bn%2d ($fc%2d) | ${ast(fc)}%s"
// Get each line of output for the histogram.
val lines = lottery.zipWithIndex.map {
case (fc, idx) => line(idx + 1, fc)
}
// Print each line of the histogram
lines.foreach(println)
}
Note that we haven't sorted the histogram (the code as it stands matches the output specified in your brief). If you need to have balls listed in descending order of frequency count, simply sort the zipped array using the frequency count:
val lines = lottery.zipWithIndex.sortBy(-_._1).map {
case (fc, idx) => line(idx + 1, fc)
}
sortBy takes a function used as the sort value. Here, we take the frequency count and make it negative to reverse the order of the sort (if you want it sorted in ascending order of frequency count, remove the - sign).
Note that we must sort the array after zipping with the index, otherwise we'll lose the ball number association.
Some further observations:
In Scala, the use of var is heavily discouraged. Prefer val instead. (It's possible to write code that never uses var at all.)
objects (other than package objects) should typically have a capital first letter by convention.
Extending scala.App allows the object's constructor to become the main method of the program, and simplifies matters.
Unsorted output (which matches your brief):
1 (23) | ***********************
2 (16) | ****************
3 (18) | ******************
4 (19) | *******************
5 (26) | **************************
...
Sorted output:
30 (28) | ****************************
5 (26) | **************************
45 (26) | **************************
42 (25) | *************************
15 (24) | ************************
...
UPDATE
In response to your comment about needing a frequency count of the frequency counts (if I understand you correctly), here's how you would do that:
To get the frequency of each value, there are (again) many ways to do this. In this particular case, I'm going to use a foldLeft operation.
You can think of foldLeft as an accumulation operation: the first argument identifies a zero value—the initial value of the accumulator—while the second is a function which is applied to each member of the container (the Array). This latter function itself takes two arguments: the current accumulator value, and the value of the current element, and it returns a new accumulator value.
In this case, I'm going to use foldLeft to build an associative array (a SortedMap, which keeps its keys sorted in ascending order) that links each frequency count to the number of times that it occurs. (In this SortedMap, the _key_s are the frequency counts, and the value associated with each key is the frequency of that frequency count.)
Here's what that looks like (I've broken it down into a number of steps to make it more comprehensible):
// Required import.
import scala.collection.immutable.SortedMap
// Our initial, empty map, which reports a frequency of zero if a key is not present.
// Note that a `SortedMap` keeps its keys sorted.
val zero = SortedMap.empty[Int, Int].withDefaultValue(0)
// Iterate through the frequency counts (`fc`) in the `lottery` array. `fm` is the current
// status of our map.
val freq = lottery.foldLeft(zero) {(fm, fc) =>
// Determine the new count for this frequency count.
val newCount = fm(fc) + 1
// Create an association from the frequency count to this new count.
val assoc = fc -> newCount
// Add this association to the map, resulting in a new map. Any existing association
// will be replaced.
fm + assoc
}
If you've followed that, here's a terser version:
val freq = lottery.foldLeft(SortedMap.empty[Int, Int].withDefaultValue(0)) {(fm, fc) =>
fm + (fc -> (fm(fc) + 1))
}
Now all that remains is to create the histogram lines and print them:
val lines = freq.map {
case (k, v) => line(k, v)
}
lines.foreach(println)
(Note: The definition of the arguments for the line method need tweaking in light of the changes, but the behavior is identical.)
Output:
11 ( 1) | *
12 ( 1) | *
13 ( 2) | **
14 ( 3) | ***
15 ( 3) | ***
16 ( 3) | ***
17 ( 4) | ****
18 ( 5) | *****
19 ( 4) | ****
20 ( 8) | ********
21 ( 3) | ***
22 ( 5) | *****
23 ( 2) | **
24 ( 1) | *
25 ( 1) | *
26 ( 2) | **
28 ( 1) | *

Efficiently way to read binary files in scala

I'm trying to read a binary file (16 MB) in which I have only integers coded on 16 bits. So for that, I used chunks of 1 MB which gives me an array of bytes. For my own needs, I convert this byte array to a short array with the following function convert but reading this file with a buffer and convert it into a short array take me 5 seconds, is it a faster way than my solution ?
def convert(in: Array[Byte]): Array[Short] = in.grouped(2).map {
case Array(one) => (one << 8 | (0 toByte)).toShort
case Array(hi, lo) => (hi << 8 | lo).toShort
} .toArray
val startTime = System.nanoTime()
val file = new RandomAccessFile("foo","r")
val defaultBlockSize = 1 * 1024 * 1024
val byteBuffer = new Array[Byte](defaultBlockSize)
val chunkNums = (file.length / defaultBlockSize).toInt
for (i <- 1 to chunkNums) {
val seek = (i - 1) * defaultBlockSize
file.seek(seek)
file.read(byteBuffer)
val s = convert(byteBuffer)
println(byteBuffer size)
}
val stopTime = System.nanoTime()
println("Perf of = " + ((stopTime - startTime) / 1000000000.0) + " for a duration of " + duration + " s")
16 MB easily fits in memory unless you're running this on a feature phone or something. No need to chunk it and make the logic harder.
Just gulp the whole file at once with java.nio.files.Files.readAllBytes:
val buffer = java.nio.files.Files.readAllBytes(myfile.toPath)
assuming you are not stuck with Java 1.6. (If you are stuck with Java 1.6, pre-allocate your buffer size using myfile.size, and use read on a FileInputStream to get it all in one go. It's not much harder, just don't forget to close it!)
Then if you don't want to convert it yourself, you can
val bb = java.nio.ByteBuffer.wrap(buffer)
bb.order(java.nio.ByteOrder.nativeOrder)
val shorts = new Array[Short](buffer.length/2)
bb.asShortBuffer.get(shorts)
And you're done.
Note that this is all Java stuff; there's nothing Scala-specific here save the syntax.
If you're wondering why this is so much faster than your code, it's because grouped(2) boxes the bytes and places them in an array. That's three allocations for every short you want! You can do it yourself by indexing the array directly, and that will be fast, but why would you want to when ByteBuffer and friends do exactly what you need already?
If you really really care about that last (odd) byte, then you can use (buffer.length + 1)/2 for the size of shorts, and tack on a if ((buffer.length) & 1 == 1) shorts(shorts.length-1) = ((bb.get&0xFF) << 8).toShort to grab the last byte.
A couple of issues pop out:
If byteBuffer is always going to be 1024*1024 size then the case Array(one) in convert will never actually be used and therefore pattern matching is unnecessary.
Also, you can avoid the for loop with a tail recursive function. After the val byteBuffer = ... line you can replace the chunkNums and for loop with:
#scala.annotation.tailrec
def readAndConvert(b: List[Array[Short]], file : RandomAccessFile) : List[Array[Short]] = {
if(file.read(byteBuffer) < 0)
b
else {
file.skipBytes(1024*1024)
readAndConvert(b.+:(convert(byteBuffer)), file)
}
}
val sValues = readAndConvert(List.empty[Array[Short]], file)
Note: because list preppending is much faster than appending the above loop gets you the converted value in reverse order from the reading order in the file.