Thursday, November 5, 2015

Arrays and Indexers in Ceylon



Ceylon 1.2 was finally released, you can see the announcement and the new stuff included on the new release here: http://www.ceylon-lang.org/blog/2015/10/29/ceylon-1-2-0/.  This version looks really impressive doesn't it?. Anyway, I took advantage of this 1 year long await to finally come up, me too, with a new post, et voilà! today's post is about Arrays and Indexers in Ceylon.

Ceylon does not have primitives, nor arrays, but you have sequences (read only arrays), generics Array and Java's interop arrays. In this post i used Array instead of CharArray, IntArray and ObjectType interop arrays.

For the Java interop arrays, you can get some documentation in these 2 pages:
http://ceylon-lang.org/documentation/1.0/reference/interoperability/java-from-ceylon/#java_array_types_milestone_5
http://ceylon-lang.org/documentation/1.0/reference/interoperability/type-mapping/

There isn't either Indexers in Ceylon, as a built in feature of the language, however, you can implement some interfaces have a syntax sugar array[index], which behind the scenes is the usual array.get(index) method call. More info here:
http://www.ceylon-lang.org/documentation/1.2/tour/sequences/

Here below you will find a very easy to follow program, that demonstrate arrays and indexer, by implementing some simple tasks that will make you grasp the idea of those 2 features real quick. The main goal of this post, is not really teaching arrays because, come on, you probably already know "all" about them, in fact, it is more to show you how you do that in Ceylon, in this case, compared to all other 22 languages on future posts, which essentially, is the real aim behind this blog.

By the way, if you missed my (not so) recent post (anymore), "New Series - Arrays and Indexers", check it out. It has more details about the following program, and a bunch of definitions for the concepts used on this, and the following, posts. Or you can check my previous posts about arrays in Java just to compare.

I encourage you to copy the code below and try it yourself, normally, all programs you find in this blog are source code complete, just paste it on your IDE and run it.

There is room for improvement of the code, using generics is one example, but Generics, Collections, lambdas, etc. will have their own "series" of posts.


//module.ceylon
native("jvm") module com.carlosqt.hello "1.0.0" {
 import java.base "8";
 import ceylon.interop.java "1.2.0";
}


//run.ceylon
import java.lang {  
 Str=String { 
  format 
 }
 ,Int=Integer
 ,Chr=Character
 /*,CharArray
  ,IntArray */
}
/*import ceylon.interop.java {
 createJavaIntArray
}*/
import java.util {
 Random
}

"Run the module `com.carlosqt.hello`."
shared void run() {
 // Single-dimensional Array(s)  
 printTitle("Reverse Array Elements");  
 
 // Declare and Initialize Array of Chars
 //value letters = CharArray(5); // Java interop
 value letters = Array<Character>.ofSize(5, ' ');
 letters.set(0, 'A');  
 letters.set(1, 'E'); 
 letters.set(2, 'I'); 
 letters.set(3, 'O'); 
 letters.set(4, 'U'); 
  
 printArray(letters);
 Array<Character> inverse_letters = reverseChar(letters);  
 printArray(inverse_letters);
 
 printTitle("Sort Integer Array Elements");
 
 // Declare and Initialize Array of Integers
 //IntArray numbers = IntArray(10, 8, 3, 1, 5) 
 //value x = createJavaIntArray({10, 8, 3, 1, 5});
 
 value numbers = Array<Integer|String>({10, 8, 3, 1, 5});
 printArray(numbers);
 value ordered_numbers = bubbleSort(numbers);   
 printArray(ordered_numbers);  
 
 printTitle("Sort String Array Elements");
 
 // Declare and Initialize and Array of Strings
 value names = Array<String|Integer>({
  "Damian",  
  "Rogelio",  
  "Carlos",  
  "Luis",  
  "Daniel"}
 ); 
 
 printArray(names);  
 value ordered_names = bubbleSort(names);  
 printArray(ordered_names);  
 
 // Multi-dimensional Array (Matrix row,column)  
 
 printTitle("Transpose Matrix"); 
 
 /* Matrix row=2,col=3 
  * A =  [6  4 24] 
  *      [1 -9  8] 
  */
 value matrix = Array<Array<Integer>>({
  Array<Integer>({6, 4, 24}),
  Array<Integer>({1, -9, 8})
 });
  
 printMatrix(matrix);
 value transposed_matrix = transposeMatrix(matrix);  
 printMatrix(transposed_matrix);
 
 // Jagged Array (Array-of-Arrays)  
 
 printTitle("Upper Case Random Array & Graph Number of Elements");
 
 /* 
    * Creating an array of string arrays using the String.Split method 
    * instead of initializing it manually as follows: 
    * 
    * value text = Array<Array<String>>({ 
    *      Array<Integer>({"word1", "word2", "wordN"}), 
    *      Array<Integer>({"word1", "word2", "wordM"}),
    *      ... 
    *      ) 
    * 
    * Text extract from: "El ingenioso hidalgo don Quijote de la Mancha" 
    * 
    */  
 value text = Array<Array<String>>({  
  Array<String>("Hoy es el día más hermoso de nuestra vida, querido Sancho;".split()),
  Array<String>("los obstáculos más grandes, nuestras propias indecisiones;".split()),
  Array<String>("nuestro enemigo más fuerte, miedo al poderoso y nosotros mismos;".split()),
  Array<String>("la cosa más fácil, equivocarnos;".split()),
  Array<String>("la más destructiva, la mentira y el egoísmo;".split()),
  Array<String>("la peor derrota, el desaliento;".split()),
  Array<String>("los defectos más peligrosos, la soberbia y el rencor;".split()),
  Array<String>("las sensaciones más gratas, la buena conciencia...".split())
 });  
 
 printJaggedArray(text);  
 upperCaseRandomArray(text);  
 printJaggedArray(text);  
 graphJaggedArray(text);  
 
 // Array Exceptions  
 
 printTitle("Common Array Exceptions");  
 
 //printCommonArrayExceptions(null) // Null-Safety  
 printCommonArrayExceptions(text);
 
 // Accessing Class Array Elements through Indexer  
 
 printTitle("Alphabets");  
 
 
 value vowels = Alphabet(5);  
 vowels.set(0, 'a');  
 vowels.set(1, 'e');  
 vowels.set(2, 'i');  
 vowels.set(3, 'o');  
 vowels.set(4, 'u');  
 
 print("\nVowels = {``",".join({vowels.get(0), vowels.get(1)
  , vowels.get(2), vowels.get(3), vowels.get(4)})``}");
   
 value en = Alphabet.initstr("abcdefghijklmnopqrstuvwxyz");  
 print("English Alphabet = {``en.string``}");  
 
 print("Alphabet Extract en[9..19] = {``Alphabet.initarr(en.slice(9, 10))``}");  
 
 value word1 = "".join({en.get(6), en.get(14), en.get(14), en.get(3)});  
 value word2 = "".join({en.get(1), en.get(24), en.get(4)});
 value word3 = "".join({en.get(4), en.get(21), en.get(4), en.get(17),  
  en.get(24), en.get(14), en.get(13), en.get(4)});
 
 print("\n``word1`` ``word2``, ``word3``!");  
}

Array<Character> reverseChar(Array<Character> arr) {
 variable Integer i = !arr.empty then arr.size-1 else 0;  
 value reversed = Array<Character>.ofSize(arr.size, ' ');
 for (j in 0..i) {  
  if(exists c = arr.get(j)) {
   reversed.set(i, c);
  }
  i--;
 }  
 return reversed;  
}  

Array<Integer|String> bubbleSort(Array<Integer|String> arr) {
 if(!arr.empty) {   
  variable Integer|String swap;
  for(i in arr.indexes()) {  
   for(j in 0..arr.size - 2) {
    if(exists l = arr.get(j), exists r = arr.get(j+1)) {
     if (is Integer l, is Integer r,  l > r) {
      swap = l;
      arr.set(j, r);
      arr.set(j+1, swap);
     } else if (is String l, is String r, l > r) {
      swap = l;
      arr.set(j, r);
      arr.set(j+1, swap);
     }
    }
   }
  }
 }
 return arr;
}

Array<Array<Integer>> transposeMatrix(Array<Array<Integer>> m) {  
 /* Transposing a Matrix 2,3 
  * 
  * A =  [6  4 24]T [ 6  1] 
  *      [1 -9  8]  [ 4 -9] 
  *                 [24  8] 
  */
 if(!m.empty, exists r = m.get(0), exists c = r.get(0)) { 
  value transposed = Array<Array<Integer>>.ofSize(r.size, Array<Integer>.ofSize(m.size, 0));
  for(i in r.indexes()) {
   transposed.set(i, Array<Integer>.ofSize(m.size, 0));
  }
  for(i in m.indexes()) {     
     for(j in r.indexes()) {     
      //transposed[j][i] = m[i][j];      
      if (exists a = m.get(i), exists v = a.get(j), 
       exists tr = transposed.get(j)) {
        tr.set(i, v);
    }
   }
  }
  return transposed;
 }
 else {
  return m;
 }
}  

void upperCaseRandomArray(Array<Array<String>> arr) { 
 value r = Random();
 value i = Integer(r.nextInt(arr.size));
 if(exists s = arr.get(i)) {
  for (j in s.indexes()) {  
   //arr[i][j] = arr[i][j].toUpperCase()
   if(exists m = s.get(j)) {
    s.set(j, m.uppercased);
   }
  }
 }
}

/**/
//void printArrayChar(CharArray|IntArray|StringArray arr) {
// Using Union Types to print all types of Array content
void printArray(Array<Character>|Array<Integer>|Array<String>|Array<Integer|String> arr) {
 String arrtype; 
 if(!arr.empty, exists t = arr.get(0)) { 
  arrtype = className(t); 
 } else { 
  arrtype = "empty";
 } 
 print("\nPrint Array Content ``className(arr)``<``arrtype``>[``arr.size``]");
 
 for (i in 0..arr.size-1) {
  print(format(" array [%2d] = %2s", Int(i), Str(arr.get(i)?.string)));
 }
}

void printMatrix(Array<Array<Integer>> m) {   
 if(!m.empty, exists r = m.get(0), exists c = r.get(0)) { 
  print("\nPrint Matrix Content ``className(m)``<``className(r)``<``className(c)``>>[``m.size``,``r.size``]");
 
  for(i in m.indexes()) {
   if (exists e = m.get(i)) {  
    for(j in e.indexes()) {      
     if (exists f = e.get(j)) {
      print(format(" array [%2d,%2d] = %2d", Int(i), Int(j), Int(f)));
     }  
    }  
   }
  }  
 }   
}  

void graphJaggedArray(Array<Array<String>> arr) {  
    /* When using Arrays, we can use foreach-like instead of for-like loop: 
     * 
     * for (i in arr.indexes()) 
     *   for (j in arr.indexes()) 
     * 
    */  
    print("\nPrint Text Content ``className(arr)``");
    if(!arr.empty) {  
     variable Integer lineCount = 1;
     variable String line = "";  
     for(s in arr) {  
         //print(format("Line%2s|", Int(lineCount)));
         line = "Line ``lineCount``|";  
         for(w in s) {  
             //print(format("%3s", Chr('*')));
             line += " * ";
         }  
         //print(" (``s.size``)");
         line += " (``s.size``)";
         print(line);
         lineCount += 1;
  }  
 }
}  

void printJaggedArray(Array<Array<String>> arr) {  
    print("\nPrint Jagged Array Content ``className(arr)``");
    if(!arr.empty) { 
     //variable StringBuilder line;
     for(i in arr.indexes()) {  
         value line = StringBuilder();
         if(exists r = arr.get(i)) {  
          for(j in r.indexes()) {          
              if(exists s = r.get(j)) {      
               line.append(" ").append(s);
              }  
          }  
          if (line.string == line.string.uppercased) {  
              line.append(" <-- [UPPERCASED]");
          }          
          print(line);
         }
     }
 }  
}  

void printCommonArrayExceptions(Array<Array<String>> arr) {  
 try {
  if(exists i = arr.get(0)) {  
   i.set(100, "hola");
  }
 } catch(AssertionError e) {  
  print("\nException: \n``className(e)``\n``e.message``\n");  
 }  
}  

void printTitle(String message) {  
 print("");  
 print("=".repeat(54));  
 print(message);  
 print("=".repeat(54));  
}  

class Alphabet {
 // Array field
 shared Array<Character> letters; //= Array<Character>.ofSize(size, ' ');

 // Constructors  
 // Only one default constructor
 shared new(Integer size) {
  this.letters = Array<Character>.ofSize(size, ' ');  
 }   
 // and 2 more named constructors
 shared new initstr(String list) {
  this.letters = Array<Character>(list.uppercased); 
 }
 
 shared new initarr(Array<Character> arr) {
  this.letters = arr;
 }

 shared Integer size() 
  => this.letters.size;
 
 // Overridden Method
 
 // No indexers, using methods instead.
 "Gets the item at the specified index"
 shared Character get(Integer index) {
  if(exists l = letters.get(index)) {
   return l;
  } else {
   return ' ';
  }
 }
 
 "Sets the item at the specified index"
 shared void set(Integer index, Character element) {
  if(!letters.empty, exists l = letters.get(index)) {
   letters.set(index, element.uppercased);   
  }
 }
  
 // Overriden (refined)
 "Java's toString"
 shared actual String string 
  => ".".join(letters);
  
  // Method  
  "Returns a subset of this alphabet"
  shared Array<Character> slice(Integer start, Integer len) 
   //=> Array<Character>(letters.sublist(start, start+len-1));  
  => letters[start..start+len-1];  
  
}


The output:





























































































Voilà, that's it. Next post in the following days (or months haha).

No comments:

Post a Comment