如何在smalltalk中制作排序方法

how to make a sorting method in smalltalk

我正在尝试在smalltalk 中创建一种新的排序方法。有人知道如何将此排序 java 代码更改为 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; 
      }           
}

简答:

你不必。

要对数组进行排序,只需向其发送消息 #asSortedCollection。例如,在工作区中检查:

#(7 2 8 5) asSortedCollection

长答案:

因为我假设您想了解如果您确实需要[=],您将如何在 Smalltalk 中实现您的 Java 代码47=],这里有一个相对 "literal translation" 你可以在工作区中测试(在 Pharo 中测试,应该也可以在 Squeak 中工作):

| 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

显然,您的版本有一些变化,例如使用显式命名,这是 Smalltalk 的标志性约定之一(特别是,indexOfSmallest 应该比 first 更清晰,这是具有误导性,因为它不一定是第一个索引),并缩小了您称为 firsttemp 的变量的范围。如果您在使用 "translation".

时遇到问题,请参阅@Leandro 对使用您自己的变量名的版本的回答

如果代码存在于一个方法中,我可能会把它放在 SequenceableCollection 层次结构中(或者如果您想覆盖其他行为,您可能想将您的代码作为子类添加到其中), 它的开头可能看起来像这样:

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

再次注意,我是故意更改名称的,因为我不认为 selectionSort 是该方法功能的描述性名称,而且我不会使用集合作为参数存在于其他地方的方法 - 如何进行排序的知识属于 集合本身

不过,我相信您可以很容易地想出一个更好的自己的答案。例如,您可以尝试向 SequenceableCollection 实例发送消息 sort: 并将排序块作为参数传递,您可以在其中指定元素的排序方式。

这里是逐行翻译。行号不是代码的一部分。

 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]

备注:

  1. 没有参数类型声明。没有答案类型。
  2. 块临时 ij 在块内声明(第 3 行和第 5 行)。在 Smalltalk 中,索引集合是基于 1 的。
  3. num.length() -> num size。减少 for 循环转化为 to:by:do: 消息。
  4. 赋值 = 变为 := 并且 0 变为 1(参见上面的行注释 2。)
  5. 增加 for 循环转化为 to:do: 消息。
  6. 评论用双引号括起来。
  7. [j] 转换为 at: j 消息。 if 转换为 ifTrue: 消息。
  8. temp 可以在第一个块中声明:do: [:i | | temp |....
  9. num[j] = temp也变成发消息at:put:.
  10. 同上 9。另请注意,您可以在第 9 行和第 10 行使用级联语法:

    num
        at: first put: (num at: i);
        at: i put: temp
    
  11. 不需要回答num因为已经被方法修改了。但是,请参阅源自 Amos 的回答的有趣讨论:.