For loop for array in Pharo Smalltalk - oop

I'm trying to make an array with random numbers (just 0 or 1), but when I run it, it just prints this: End of statement list encountered ->
This is my code:
GenList
| lista |
lista := Array new: 31.
1 to: 30 do: [ :i | lista at: i put: 2 atRandom - 1]
^lista
What can I do?

Some interesting things to consider:
1. The method selector doesn't start with a lowercase letter
It is a tradition for selectors to start with a lowercase letter. In this sense, genLista would be more correct than GenLista.
2. The method selector includes the abbreviated word 'gen'
For instance, genLista could be renamed to genereLista o listaAlAzar (if you decide to use Spanish)
3. The Array named lista has 31 elements, not 30
The result of Array new: 31 is an array of 31 elements. However, the code below it only fills 30 of them, leaving the last one uninitialized (i.e., nil). Possible solution: lista := Array new: 30.
4. A dot is missing causing a compilation error
The code
1 to: 30 do: [ :i | lista at: i put: 2 atRandom - 1]
^lista
does not compile because there is no dot indicating the separation between the two sentences. Note that the error happens at compilation time (i.e., when you save the method) because the return token ^ must start a statement (i.e., it cannot be inlined inside a statement).
There are other cases where a missing dot will not prevent the code from compiling. Instead, an error will happen at runtime. Here is a (typical) example:
1 to: 10 do: [:i | self somethingWith: i] "<- missing dot here"
self somethingElse
the missing dot will generate the runtime error self not understood by block.
5. There is a more expressive way of generating 0s and 1s at random
The calculation 2 atRandom - 1 is ok. However, it forces the reader to mentally do the math. A better way to reveal your intention would have been
#(0 1) atRandom
6. When playing with random numbers don't forget to save the seed
While it is ok to use atRandom, such a practice should only be used with "toy" code. If you are developing a system or a library, the recommended practice is to save the seed somewhere before generating any random data. This will allow you to reproduce the generation of random quantities later on for the sake of debugging or confirmation. (Note however, that this will not suffice for making your program deterministically reproducible because unordered (e.g. hashed) collections could form differently in successive executions.)

Related

Can one create a standalone method/function (without any class)

I am trying to understand smalltalk. Is it possible to have a standalone method/function, which is not part of any particular class, and which can be called later:
amethod ['amethod called' printNl].
amethod.
Above code gives following error:
simpleclass.st:1: expected Eval, Namespace or class definition
How can I use Eval or Namespace as being suggested by error message?
I tried following but none work:
Eval amethod [...
amethod Eval [...
Eval amethod Eval[... "!"
Eval [... works but I want to give a name to the block so that I can call it later.
Following also works but gets executed immediately and does not execute when called later.
Namespace current: amethod ['amethod called' printNl].
Thanks for your insight.
In Smalltalk the equivalent to a standalone method is a Block (a.k.a. BlockClosure). You create them by enclosing Smalltalk expressions between square brackets. For example
[3 + 4]
To evaluate a block, you send it the message value:
[3 + 4] value
which will answer with 7.
Blocks may also have arguments:
[:s | 3 + s]
you evaluate them with value:
[:s | 3 + s] value: 4 "answers with 7"
If the block has several sentences, you separate them with a dot, as you would do in the body of a method.
Addendum
Blocks in Smalltalk are first class objects. In particular, one can reference them with variables, the same one does with any other objects:
three := 3.
threePlus := [:s | three + s].
for later use
threePlus value: 4 "7"
Blocks can be nested:
random := Random new.
compare := [:p :u | u <= p]
bernoulli60 := [compare value: 0.6 value: random next].
Then the sequence:
bernoulli60 value. "true"
bernoulli60 value. "false"
...
bernoulli60 value. "true"
will answer with true about 60% of the times.
Leandro's answer, altough being correct and with deep smalltalk understanding, is answering what you asked for, but I think, not 100% sure thou, you are actually asking how to "play" around with a code without the need to create a class.
In my eyes want you want is called a Workspace (Smalltalk/X and Dolphin) (it can have different names like Playground in Pharo Smalltalk).
If you want to play around you need to create a local variable.
| result |
result := 0. "Init otherwise nil"
"Adding results of a simple integer factorial"
1 to: 10 do: [ :integer |
result := result + integer factorial
].
Transcript show: result.
Explanation:
I'm using a do: block for 1-10 iterration. (:integer is a block local variable). Next I'm, showing the result on Transcript.

Understanding GNU Smalltalk Closure

The following piece of code is giving the error error: did not understand '#generality'
pqueue := SortedCollection new.
freqtable keysAndValuesDo: [:key :value |
(value notNil and: [value > 0]) ifTrue: [
|newvalue|
newvalue := Leaf new: key count: value.
pqueue add: newvalue.
]
].
[pqueue size > 1] whileTrue:[
|first second new_internal newcount|
first := pqueue removeFirst.
second := pqueue removeFirst.
first_count := first count.
second_count := second count.
newcount := first_count + second_count.
new_internal := Tree new: nl count: newcount left: first right: second.
pqueue add: new_internal.
].
The inconsistency is in the line pqueue add: new_internal. When I remove this line, the program compiles. I think the problem is related to the iteration block [pqueue size > 1] whileTrue: and pqueue add: new_internal.
Note: This is the algorithm to build the decoding tree based on huffman code.
error-message expanded
Object: $<10> error: did not understand #generality
MessageNotUnderstood(Exception)>>signal (ExcHandling.st:254)
Character(Object)>>doesNotUnderstand: #generality (SysExcept.st:1448)
SmallInteger(Number)>>retryDifferenceCoercing: (Number.st:357)
SmallInteger(Number)>>retryRelationalOp:coercing: (Number.st:295)
SmallInteger>><= (SmallInt.st:215)
Leaf>><= (hzip.st:30)
optimized [] in SortedCollection class>>defaultSortBlock (SortCollect.st:7)
SortedCollection>>insertionIndexFor:upTo: (SortCollect.st:702)
[] in SortedCollection>>merge (SortCollect.st:531)
SortedCollection(SequenceableCollection)>>reverseDo: (SeqCollect.st:958)
SortedCollection>>merge (SortCollect.st:528)
SortedCollection>>beConsistent (SortCollect.st:204)
SortedCollection(OrderedCollection)>>removeFirst (OrderColl.st:295)
optimized [] in UndefinedObject>>executeStatements (hzip.st:156)
BlockClosure>>whileTrue: (BlkClosure.st:328)
UndefinedObject>>executeStatements (hzip.st:154)
Object: $<10> error: did not understand #generality
MessageNotUnderstood(Exception)>>signal (ExcHandling.st:254)
Character(Object)>>doesNotUnderstand: #generality (SysExcept.st:1448)
SmallInteger(Number)>>retryDifferenceCoercing: (Number.st:357)
SmallInteger(Number)>>retryRelationalOp:coercing: (Number.st:295)
SmallInteger>><= (SmallInt.st:215)
Leaf>><= (hzip.st:30)
optimized [] in SortedCollection class>>defaultSortBlock (SortCollect.st:7)
SortedCollection>>insertionIndexFor:upTo: (SortCollect.st:702)
[] in SortedCollection>>merge (SortCollect.st:531)
SortedCollection(SequenceableCollection)>>reverseDo: (SeqCollect.st:958)
SortedCollection>>merge (SortCollect.st:528)
SortedCollection>>beConsistent (SortCollect.st:204)
SortedCollection(OrderedCollection)>>do: (OrderColl.st:64)
UndefinedObject>>executeStatements (hzip.st:164)
One learning we can take from this question is to acquire the habit of reading the stack trace trying to make sense of it. Let's focus in the last few messages:
1. Object: $<10> error: did not understand #generality
2. MessageNotUnderstood(Exception)>>signal (ExcHandling.st:254)
3. Character(Object)>>doesNotUnderstand: #generality (SysExcept.st:1448)
4. SmallInteger(Number)>>retryDifferenceCoercing: (Number.st:357)
5. SmallInteger(Number)>>retryRelationalOp:coercing: (Number.st:295)
6. SmallInteger>><= (SmallInt.st:215)
7. Leaf>><= (hzip.st:30)
8. optimized [] in SortedCollection class>>defaultSortBlock (SortCollect.st:7)
Each of these lines represents the activation of a method. Every line represents a message and the sequence of messages goes upwards (as it happens in any Stack.) The full detail of every activation can be seen in the debugger. Here, however, we only are presented with the class >> #selector pair. There are several interesting facts we can identify from this summarized information:
In line 1 we get the actual error. In this case we got a MessageNotUnderstood exception. The receiver of the message was the Character $<10>, i.e., the linefeed character.
Lines 2 and 3 confirm that the not understood message was #generality.
Lines 4, 5 and 6 show the progression of messages that ended up sending #generality to the wrong object (linefeed). While 4 and 5 might look obscure for the non-experienced Smalltalker, line 6 has the key information: some SmallInteger received the <= message. This message would fail because the argument wasn't the appropriate one. From the information we already got we know that the argument was the linefeed character.
Line 7 shows that SmallInteger >> #<= came from the way the same selector #<= is implemented in Leaf. It tells us that a Leaf delegates #<= to some Integer known to it.
Line 8 says why we are dealing with the comparison selector #<=. The reason is that we are sorting some collection.
So, we are trying to sort a collection of Leaf objects which rely on some integers for their comparison and somehow one of those "integers" wasn't a Number but the Character linefeed.
If we take a look at the Smalltalk code with this information in mind we see:
The SortedCollection is pqueue and the Leaf objects are the items being added to it.
The invariant property of a SortedCollection is that it always has its elements ordered by a given criterion. Consequently, every time we add: an element to it, the element will be inserted in the correct position. Hence the comparison message #<=.
Now let's look for #add: in the code. Besides of the one above, there is another below:
new_internal := Tree new: nl count: newcount left: first right: second.
pqueue add: new_internal.
This one is interesting because is where the error happens. Note however that we are not adding a Leaf here but a Tree. But wait, it might be that a Tree and a Leaf belong to the same hierarchy. In fact, both Tree and Leaf represent nodes in an acyclic graph. Moreover, the code confirms this idea when it reads:
Leaf new: key count: value.
...
Tree new: nl count: newcount left: first right: second.
See? Both Leaf and Tree have some key (the argument of new:) and some count. In addition, Trees have left and right branches, which Leafs not (of course!)
So, in principle, it would be ok to add instances of Tree to our pqueue collection. This cannot be what causes the error.
Now, if we look closer to the way the Tree is created we can see a suspicious argument nl. This is interesting because of two reasons: (i) the variable nl is not defined in the part of the code we were given and (ii) the variable nl is the key that will be used by the Tree to respond to the #<= message. Therefore, nl must be the linefeed character $<10>. Which makes a lot of sense because nl is an abbreviation of newline and in the Linux world newlines are linefeeds.
Conclusion: The problem seems to be caused by the wrong argument nl used for the Tree's key.

In Smalltalk, if x is an array, and x at: 3 put: 123 will work, then how can (x at: 3) + 1 work?

That is, if we look at it as all objects and messages, then
"Did this earlier: x := Array new: 20"
x at: 3 put: 123 "this will put 123 into slot 3"
can work only if x at: 3 return like a "cell" object, so the cell can take in an Interger object, which is 123. (or, so that the cell object can let some myContent property point to the 123 object)
Then in this case, how can
y := (x at: 3) + 567
work? Because how does a cell deal with the + message? Is it that somehow the cell object thinks it doesn't know how to handle the + message, so it looks into its content (maybe by something like self myContent) and then return it? How does it work? I wonder also if there is a Design Pattern name for it.
x at: 3 put: 123 sends at:put: selector to x.
There is well defined priority for selectors
unary (1 negated)
binary (1 + 2)
keyword (at:put:)
The number of "arguments" for keywords selector is not relevant, it will always be interpreted as a single keyword selector, so detect:ifFound:ifNone: will be interpreted as a single selector which is sent to the object rather than three separate selectors.
Now if you want to change the priority, or put one keyword selector inside another, you have to enclose it in parens.
So your x at: 3 put: 123 contains only one message: at:put:; if you actually want to send put: to the value present at position 3, you need to put it in parens (x at: 3) put: 123, which is also consistent with your observation about (x at: 3) + 567.
Equivalent syntax from other languages would be x.atPositionInsert(3, 123), and x.atPosition(3) + 567.
There is no "cell" object. x at: 3 put: 123 puts the Integer 123 into the Collection x at index 3. x (the Collection, which may be of some more concrete type such as an Array) is responsible for storing the object and retrieving it when supplied with the appropriate index, but it doesn't create and store a different object. The internal workings of the Collection x are opaque from the point of view of the user of x- you don't know how x is storing the Integer in question - you only know that when you send the message at: with argument 3 to x you're going to get back what was stored there earlier - i.e. you'll get back 123. So there's no "cell" object which has to interpret + - the Integer 123 is what's handling the + message.
It is very much possible to create classes which interpret arbitrary messages sent to them. In versions of Smalltalk (e.g. Dolphin, Visual Smalltalk) I've worked with this is done by implementing the 'special' message doesNotUnderstand:.
Hope this helps.
I might add to Peter's answer that the parenthesis is like parens in other languages, it forces the expression in parens to be evaluated first. If there are multiple parens then evaluation goes left to right.
So
y := (x at: 3) + 567
For (x at: 3) is evaluated first which yields 123. 123 + 567 is evaluated second which yields 690 and y is set to 690.

Conditional swapping of items in an array

I have a collection of items of type A, B, and C.
I would like to process the collection and swap all A and B pairs, but if there is C (which is also a collection), I want to process that recursively.
So
#(A1 A2 B1 B2 A3 #(A4 A5 B3) )
would be translated into
#(A1 B1 A2 B2 A3 #(A4 B3 A5) )
The swap isn't transitive so #(A1 B1 B2) will be translated into #(B1 A1 B2) and not #(B1 B2 A1).
I wanted to use overlappingPairsDo: but the problem is that the second element is always processed twice.
Can this be achieved somehow with Collection API without resorting to primitive forloops?
I am looking for readable, not performant solution.
I think my solution below should do what you're after, but a few notes up front:
The "requirements" seem a bit artificial - as in, I'm having a hard time imagining a use case where you'd want this sort of swapping. But that could just be my lack of imagination, of course, or due to your attempt to simplify the problem.
A proper solution should, in my opinion, create the objects required so that code can be moved where it belongs. My solution just plunks it (mostly) in a class-side method for demonstration purposes.
You're asking for this to be "achieved somehow with [the] Collection API without resorting to primitive for[-]loops" - I wouldn't be so quick to dismiss going down to the basics. After all, if you look at the implementation of, say, #overlappingPairsDo:, that's exactly what they do, and since you're asking your question within the pharo tag, you're more than welcome to contribute your new way of doing something useful to the "Collections API" so that we can all benefit from it.
To help out, I've added a class SwapPairsDemo with two class-side methods. The first one is just a helper, since, for demonstration purposes, we're using the Array objects from your example, and they contain ByteSymbol instances as your A and B types which we want to distinguish from the C collection type - only, ByteSymbols are of course themselves collections, so let's pretend they're not just for the sake of this exercise.
isRealCollection: anObject
^anObject isCollection
and: [anObject isString not
and: [anObject isSymbol not]]
The second method holds the code to show swapping and to allow recursion:
swapPairsIn: aCollection ifTypeA: isTypeABlock andTypeB: isTypeBBlock
| shouldSwapValues wasJustSwapped |
shouldSwapValues := OrderedCollection new: aCollection size - 1 withAll: false.
aCollection overlappingPairsWithIndexDo: [:firstItem :secondItem :eachIndex |
(self isRealCollection: firstItem)
ifTrue: [self swapPairsIn: firstItem ifTypeA: isTypeABlock andTypeB: isTypeBBlock]
ifFalse: [
shouldSwapValues at: eachIndex put: ((self isRealCollection: secondItem) not
and: [(isTypeABlock value: firstItem)
and: [isTypeBBlock value: secondItem]])
]
].
(self isRealCollection: aCollection last)
ifTrue: [self swapPairsIn: aCollection last ifTypeA: isTypeABlock andTypeB: isTypeBBlock].
wasJustSwapped := false.
shouldSwapValues withIndexDo: [:eachBoolean :eachIndex |
(eachBoolean and: [wasJustSwapped not])
ifTrue: [
aCollection swap: eachIndex with: eachIndex + 1.
wasJustSwapped := true
]
ifFalse: [wasJustSwapped := false]
]
That's a bit of a handful, and I'd usually refactor a method this big, plus you might want to take care of nil, empty lists, etc., but hopefully you get the idea for an approach to your problem. The code consists of three steps:
Build a collection (size one less than the size of the main collection) of booleans to determine whether two items should be swapped by iterating with overlappingPairsWithIndexDo:.
This iteration doesn't handle the last element by itself, so we need to take care of this element possibly being a collection in a separate step.
Finally, we use our collection of booleans to perform the swapping, but we don't swap again if we've just swapped the previous time (I think this is what you meant by the swap not being transitive).
To run the code, you need to supply your collection and a way to tell whether things are type "A" or "B" - I've just used your example, so I just ask them whether they start with those letters - obviously that could be substituted by whatever fits your use case.
| collection target isTypeA isTypeB |
collection := #(A1 A2 B1 B2 A3 #(A4 A5 B3) ).
target := #(A1 B1 A2 B2 A3 #(A4 B3 A5) ).
isTypeA := [:anItem | anItem beginsWith: 'A'].
isTypeB := [:anItem | anItem beginsWith: 'B'].
SwapPairsDemo swapPairsIn: collection ifTypeA: isTypeA andTypeB: isTypeB.
^collection = target
Inspecting this in a workspace returns true, i.e. the swaps on the collection have been performed so that it is now the same as the target.
Here's a solution without recursion that uses a two step approach:
result := OrderedCollection new.
#(1 3 4 6 7)
piecesCutWhere: [ :a :b | a even = b even ]
do: [ :run |
result addAll: ((result isEmpty or: [ result last even ~= run first even ])
ifTrue: [ run ]
ifFalse: [ run reverse ]) ].
result asArray = #(1 4 3 6 7) "--> true"
So first we split the collection wherever we see the possibility for swapping. Then, in the second step, we only swap if the last element of the result collection still allows for swapping.
Adding recursion to this should be straight forward.

Algorithm for 'Syncing' 2 Arrays

Array 1 | Array 2
=================
1 | 2
2 | 3
3 | 4
5 | 5
| 6
What is a good algorithm to 'sync' or combine Array 2 into Array 1? The following needs to happen:
Integers in Array 2 but not in Array 1 should be added to Array 1.
Integers in both Arrays can be left alone.
Integers in Array 1 but not in Array 2 should be removed from Array 1.
I'll eventually be coding this in Obj-C, but I'm really just looking for a pseudo-code representation of an efficient algorithm to solve this problem so feel free to suggest an answer in whatever form you'd like.
EDIT:
The end result I need is bit hard to explain without giving the backstory. I have a Cocoa application that has a Core Data entity whose data needs to be updated with data from a web service. I cannot simply overwrite the contents of Array 1 (the core data entity) with the content of Array 2 (the data parsed from the web into an array) because the Array 1 has relationships with other core data entities in my application. So basically it is important that integers contained in both Arrays are not overwritten in array one.
Array1 = Array2.Clone() or some equivalent might be the simplest solution, unless the order of elements is important.
I'm kind of guessing since your example leaves some things up in the air, but typically in situations like this I would use a set. Here's some example code in Obj-C.
NSMutableSet *set = [NSMutableSet set];
[set addObjectsFromArray:array1];
[set addObjectsFromArray:array2];
NSArray *finalArray = [[set allObjects] sortedArrayUsingSelector:#selector(compare:)];
(Assuming this is not a simple Array1 = Array2 question,) if the arrays are sorted, you're looking at a single O(n+m) pass over both arrays. Point to the beginning of both arrays, then advance the pointer containing the smaller element. Keep comparing the elements as you go and add/delete elements accordingly. The efficiency of this might be worth the cost of sorting the arrays, if they aren't already such.
In my approach, You will need Set data structure. I hope you can find some implementations in Obj-C.
Add all elements of Array1 to Set1
and do the same for Array2 to Set2.
Loop through elements of Array1.
Check if it is contained in Set2
(using provided method.) If it is
not, removed the element from Set1.
Loop through elements of Array2. If it
is not existed in Set1 yet, add it
to Set1.
All elements of Set1 is now your "synced" data.
The algorithm complexity of "contains","delete", and "add" operation of "Set" on some good implementation, such as HashSet, would give you the efficiency you want.
EDIT: Here is a simple implementation of Set assumed that the integer are in limited range of 0 - 100 with every elements initialized to 0, just to give more clear idea about Set.
You first need to define array bucket of size 101. And then for ..
contains(n) - check if bucket[n] is 1 or not.
add(n) - set bucket[n] to 1.
delete(n) - set bucket[n] to 0.
You say:
What is a good algorithm to 'sync' or combine Array 2 into Array 1? The following needs to happen:
Integers in Array 2 but not in Array 1 should be added to Array 1.
Integers in both Arrays can be left alone.
Integers in Array 1 but not in Array 2 should be removed from Array 1.
Here's some literal algorithmic to help you (python):
def sync(a, b):
# a is array 1
# b is array 2
c = a + b
for el in c:
if el in b and el not in a:
a.append(el) # add to array 1
elif el in a and el not in b:
a.remove(el) # remove from array 1
# el is in both arrays, skip
return a # done
Instead of "here's what needs to happen", try describing the requirements in terms of
"here's the required final condition". From that perspective it appears that the desired end-state is for array1 to contain exactly the same values as array2.
If that's the case, then why not the equivalent of this pseudocode (unless your environment has a clone or copy method)?
array1 = new int[array2.length]
for (int i in 0 .. array2.length - 1) {
array1[i] = array2[i]
}
If order, retention of duplicates, etc. are issues, then please update the question and we can try again.
Well, if the order doesn't matter, you already have your algorithm:
Integers in Array 2 but not in Array 1 should be added to Array 1.
Integers in both Arrays can be left alone.
Integers in Array 1 but not in Array 2 should be removed from Array 1.
If the order of the integers matter, what you want is a variation of the algorithms that determine the "difference" between two strings. The Levenshtein algorithm should suit your well.
However, I suspect you actually want the first part. In that case, what exactly is the question? How to find the integers in an array? Or ... what?
Your question says nothing about order, and if you examine your three requirements, you'll see that the postcondition says that Array2 is unchanged and Array1 now contains exactly the same set of integers that is in Array2. Unless there's some requirement on the order that you're not telling us about, you may as well just make a copy of Array2.