跳轉到內容

Sway 參考手冊/陣列和列表

來自華夏公益教科書

Sway 內建了三種主要的資料結構陣列列表物件。資料結構只是一個資訊位[1]集合,它們以某種方式粘合在一起形成一個整體。這些位中的每一個都可以單獨訪問。通常,這些位之間也存在某種關係,因此資料結構是將所有這些相關位打包在一起的便捷方式。

陣列是一種資料結構,它具有以下屬性:每個資訊位都可以像其他位一樣快速訪問。要建立陣列,可以使用array函式

   var a = array(42,64.0,"hello",:world);

此呼叫將建立一個數組,將四個專案或元素打包在一起。變數a被建立並設定為指向該包。

要訪問單個元素,可以使用“方括號”表示法或“點”表示法。例如,以下是如何訪問陣列中的第一個專案

   sway> a[0];
   INTEGER: 42
    
   sway> a . 0
   INTEGER: 42

注意,陣列索引(方括號之間或點後的數字稱為索引)是從零開始的。也就是說,第一個元素位於索引 0,第二個元素位於索引 1,依此類推。通常,由於“點”的高優先順序,不會將“點表示法”用於陣列。例如

   a[row * cols + col]

與以下內容不同

   a . row * cols + col

在後者中,檢索row索引處的元素,然後乘以cols,最後將該數字加到col。為了使後者與前者相同,需要對索引計算進行括號化

   a . (row * cols + col)

使用方括號表示法,括號化會自動執行。

也可以對陣列進行賦值

   sway> a[0] = :forty-two;
   SYMBOL: :forty-two
    
   sway> a[0];
   SYMBOL: :forty-two

您也可以檢視陣列的尾部。陣列的尾部是沒有第一個元素或頭部元素的陣列。

   sway> tail(a);
   ARRAY: [64.000000000,"hello",:world]
    
   sway> tail(a)[0];
   REAL_NUMBER: 64.000000000

如果不斷取陣列的尾部,最終會得到:null:

   sway>tail(tail(tail(tail(a))));
   SYMBOL: :null;

分配空陣列

[編輯 | 編輯原始碼]

可以分配一個數組,而無需指定實際元素

   var b = alloc(10);

這將建立一個包含十個元素的陣列(索引範圍從零到九)。

   sway> b[0];
   SYMBOL: :null;

每個元素都初始化為 :null。

列表是一種資料結構,它具有以下屬性:可以透過在列表中的任何位置新增或刪除元素來延長或縮短它。這種靈活性的折衷方案是,列表中較後面的元素比較前面的元素需要更長時間訪問。建立和訪問列表中的元素與陣列非常相似

   var a = list(42,64.0,"hello",:world);
    
   sway> a[2];
   STRING: "hello"
   
   sway> a[3] = 13;
   INTEGER: 13

要使列表變長,可以輕鬆地將一個元素新增到現有列表的前面,以建立一個新列表

   var b = "apple" join a;
   LIST: ("apple",42,64.000000000,"hello",:world)

列表可以共享元素

[編輯 | 編輯原始碼]

需要注意的是,上面的ab共享元素,對a的更改將影響b

   sway> a[1] = :pie;
   SYMBOL: :pie
    
   sway> a;
   LIST: (42,:pie,"hello",:world);
    
   sway> b;
   LIST: ("apple",42,:pie,"hello",:world);

使b獨立於a是一項看起來比實際更簡單的任務。以下是一個嘗試執行此操作的函式

   function join*(item,items)
       {
       function copy(stuff)
           {
           if (stuff == :null,:null,stuff[0] join copy(tail(stuff)));
           }
       item join copy(items);
       }

這在某些情況下有效

   var x = list(:apples,:pears,:bananas);
   var y = :kumquats join* x;               //note join*, not join
   
   x[1] = :persimmons;
   sway> x;
   LIST: (:apples,:persimmons,:bananas);
    
   sway> y;
   LIST: (:kumquats,:apples,:pears,:bananas);

問題在於,join*進行的複製是淺複製。也就是說,複製了傳入的列表,但沒有複製元素。對於符號列表,不需要複製元素,但這並非總是如此

   var m = list(2,3,4);
    
   sway> var p = list(1,m,5);
   LIST: (1,(2,3,4),5)
   sway> var q = 0 join* p;       // note, join*, not join
   LIST: (0,1,(2,3,4),5)

到目前為止,您理解了嗎?不僅q共享p的元素,它們還共享m的元素。考慮以下操作

   p[1][1] = 333; 

我們更改了p的第一個元素的第一個元素

   sway> p;
   LIST: (1,(2,333,4),5)
    
   sway> q;
   LIST: (0,1,(2,333,4),5)

透過p進行的更改仍然更改了q。要解決這個問題,需要進行深複製,其中複製列表的元素,並複製元素的元素,依此類推。

更改列表的尾部

[編輯 | 編輯原始碼]

可以使用tail=函式更改列表的尾部

   var a = list(1,2,3);
    
   a tail= list(222,333);
   sway> a;
   LIST: (1,222,333);

您可以在任何型別的列表上使用tail=,即使是透過tail生成的列表

   var b = list(1,2,3);
    
   tail(b) tail= list(333);
   sway> b;
   LIST: (1,2,333);

插入到列表中間

[編輯 | 編輯原始碼]

可以使用join、tail和tail=的組合將元素插入列表中間。以下是如何在第一個元素之後插入一個專案

   var c = list(1,3,4);
   c tail= (3 join tail(c));
   sway> c;
   LIST: (1,2,3,4);

需要括號來確保c的尾部沒有設定為數字 3,並且結果與c的尾部連線在一起。

這種插入方法會更改原始列表。也可以透過編寫插入函式來建立一個包含插入元素的新列表

   function insert(item,items,index)
       {
       if (index == 0)
           {
           item join items; //put the item at the head of the list
           }
       else
           {
           items[0] join insert(item,tail(items),index - 1);
           }
       }
   var d = list(1,3,4);
   var e = insert(2,d,1); //insert at the second element
   sway> d;
   LIST: (1,3,4);
   sway> e;
   LIST: (1,2,3,4);

請注意,insert組合了插入元素之前的元素的淺複製,並建立了插入元素之後元素的共享。

將在下一章中討論物件。

  1. 非正式意義上的位,而不是零和一。


輸入和輸出 · 物件

華夏公益教科書