Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

how to make a sorting method in smalltalk

I am trying to make a new sorting method in smalltalk. Anyone know how to change this sorting java code to squeak?

public static void SelectionSort ( int [ ] num )
{
     int i, j, first, temp;  
     for ( i = num.length - 1; i > 0; i - - )  
     {
          first = 0;   //initialize to subscript of first element
          for(j = 1; j <= i; j ++)   //locate smallest element between positions 1 and i.
          {
               if( num[j] < num[first] )         
                 first = j;
          }
          temp = num[first];   //swap smallest found with element in position i.
          num[first] = num[ i ];
          num[i] = temp; 
      }           
}
like image 364
programmingGirl Avatar asked Dec 10 '22 23:12

programmingGirl


2 Answers

Short answer:

You don't have to.

To sort an array, just send it the message #asSortedCollection. For instance, inspect this in a workspace:

#(7 2 8 5) asSortedCollection

Long answer:

Since I assume you want to see how you would implement the equivalent of your Java code in Smalltalk if you really had to, here's a relatively "literal translation" you can test in a workspace (tested in Pharo, should work in Squeak as well):

| someNumbers |
someNumbers := #(7 2 8 5) copy. "See comments below for an explanation."
someNumbers size to: 1 by: -1 do: [:eachOuterIndex |
    | indexOfSmallest swapValue |
    indexOfSmallest := 1.
    1 to: eachOuterIndex do: [:eachInnerIndex |
        (someNumbers at: eachInnerIndex) < (someNumbers at: indexOfSmallest)
            ifTrue: [ indexOfSmallest := eachInnerIndex ]
        ].
    swapValue := someNumbers at: indexOfSmallest.
    someNumbers at: indexOfSmallest put: (someNumbers at: eachOuterIndex).
    someNumbers at: eachOuterIndex put: swapValue.
    ].
^someNumbers

Clearly, there are a few changes from your version, such as using explicit naming, which is one of Smalltalk's hallmark conventions (in particular, indexOfSmallest should be clearer than first, which is misleading since it's not necessarily the first index), and decreasing the scope of the variables you called first and temp). See @Leandro's answer for a version that uses your own variable names if you have trouble with the "translation".

If the code were to live in a method, I would probably put it in the SequenceableCollection hierarchy (or maybe you'd want to add yours as a subclass in there if you want to override other behaviour), and the start of it could look something like this:

copySortedDescending
    "Answer a copy of the receiver, sorted in descending order."

    | copy |
    copy := self copy.
    copy size to: 1 by: -1 do: [:eachOuterIndex |
        "... and so on..."
        ].
    ^copy

Again, note that I'm deliberately changing the name, because I don't think selectionSort is a descriptive name of what the method does, and I wouldn't use a collection as an argument to a method living somewhere else - the knowledge of how to do the sorting belongs on the collection itself.

I'm sure you could come up with a better roll-your-own-answer very easily, though. For instance, you could try sending a SequenceableCollection instance the message sort: and pass a sort block as an argument, in which you could specify how you want your elements to be sorted.

like image 185
Amos M. Carpenter Avatar answered Dec 29 '22 17:12

Amos M. Carpenter


Here is a line by line translation. Row numbers are not part of the code.

 1. selectionSort: num
 2.    | first temp |
 3.    num size to: 1 by: -1 do: [:i |
 4.        first := 1. "initialize to subscript of first element"
 5.        1 to: i do: [:j |
 6.            "locate smallest element between positions 1 and i"
 7.            (num at: j) < (num at: first) ifTrue: [first := j]].
 8.        temp := num at: first. "swap smallest with element in position i"
 9.        num at: first put: (num at: i).
10.        num at: i put: temp]

Remarks:

  1. No argument type declaration. No answer type.
  2. Block temporaries i and j declared inside blocks (lines 3 and 5). In Smalltalk, indexed collections are 1 based.
  3. num.length() -> num size. Decreasing for loop translates into to:by:do: message.
  4. Assignment = becomes := and 0 becomes 1 (see line remark 2 above.)
  5. Increasing for loop translates into to:do: message.
  6. Comments are enclosed between double quotes.
  7. [j] translates into the at: j message. if translates into an ifTrue: message.
  8. temp could have been declared in the first block: do: [:i | | temp |....
  9. num[j] = temp also becomes a message sending at:put:.
  10. Idem 9. Note also that you could have used the cascade syntax for lines 9 and 10:

    num
        at: first put: (num at: i);
        at: i put: temp
    
  11. No need to answer num because it's been modified by the method. See, however, the interesting discussion originated in Amos' answer: Why shouldn't I store into literal arrays in Smalltalk?.

like image 21
Leandro Caniglia Avatar answered Dec 29 '22 17:12

Leandro Caniglia