Pemrograman D - Rentang

Rentang adalah abstraksi dari akses elemen. Abstraksi ini memungkinkan penggunaan sejumlah besar algoritme pada sejumlah besar jenis wadah. Rentang menekankan bagaimana elemen kontainer diakses, sebagai kebalikan dari bagaimana kontainer diimplementasikan. Rentang adalah konsep yang sangat sederhana yang didasarkan pada apakah suatu tipe mendefinisikan himpunan fungsi anggota tertentu.

Rentang adalah bagian integral dari irisan D. D adalah implementasi dari rentang RandomAccessRange yang paling kuat, dan ada banyak fitur rentang di Phobos. Banyak algoritma Phobos mengembalikan objek jarak temporer. Misalnya, filter () memilih elemen yang lebih besar dari 10 dalam kode berikut benar-benar mengembalikan objek rentang, bukan larik.

Rentang angka

Rentang angka cukup umum digunakan dan rentang angka ini berjenis int. Beberapa contoh rentang angka ditampilkan di bawah ini -

// Example 1 
foreach (value; 3..7)  

// Example 2 
int[] slice = array[5..10];

Phobos Ranges

Rentang yang terkait dengan struct dan antarmuka kelas adalah rentang phobos. Phobos adalah runtime resmi dan pustaka standar yang disertakan dengan kompiler bahasa D.

Ada berbagai jenis rentang yang meliputi -

  • InputRange
  • ForwardRange
  • BidirectionalRange
  • RandomAccessRange
  • OutputRange

InputRange

Rentang paling sederhana adalah rentang input. Rentang lainnya membawa lebih banyak persyaratan di atas rentang yang menjadi dasarnya. Ada tiga fungsi yang dibutuhkan InputRange -

  • empty- Ini menentukan apakah kisaran tersebut kosong; itu harus mengembalikan nilai true ketika kisaran dianggap kosong; false jika tidak.

  • front - Ini memberikan akses ke elemen di awal rentang.

  • popFront() - Mempersingkat rentang dari awal dengan menghapus elemen pertama.

Contoh

import std.stdio; 
import std.string; 
 
struct Student { 
   string name; 
   int number; 
   
   string toString() const { 
      return format("%s(%s)", name, number); 
   } 
}
  
struct School { 
   Student[] students; 
}
struct StudentRange {
   Student[] students; 
   
   this(School school) { 
      this.students = school.students; 
   } 
   @property bool empty() const { 
      return students.length == 0; 
   } 
   @property ref Student front() { 
      return students[0]; 
   } 
   void popFront() { 
      students = students[1 .. $]; 
   } 
}

void main() { 
   auto school = School([ Student("Raj", 1), Student("John", 2), Student("Ram", 3)]);
   auto range = StudentRange(school); 
   writeln(range);  
   
   writeln(school.students.length);
   
   writeln(range.front); 
   
   range.popFront;  
   
   writeln(range.empty); 
   writeln(range); 
}

Ketika kode di atas dikompilasi dan dijalankan, itu menghasilkan hasil sebagai berikut -

[Raj(1), John(2), Ram(3)] 
3 
Raj(1) 
false 
[John(2), Ram(3)]

ForwardRange

ForwardRange juga memerlukan bagian fungsi anggota simpan dari tiga fungsi InputRange lainnya dan mengembalikan salinan rentang saat fungsi simpan dipanggil.

import std.array; 
import std.stdio; 
import std.string; 
import std.range;

struct FibonacciSeries { 
   int first = 0; 
   int second = 1; 
   enum empty = false;   //  infinite range  
   
   @property int front() const { 
      return first; 
   } 
   void popFront() { 
      int third = first + second; 
      first = second; 
      second = third; 
   }
   @property FibonacciSeries save() const { 
      return this; 
   } 
}
  
void report(T)(const dchar[] title, const ref T range) {
   writefln("%s: %s", title, range.take(5)); 
} 

void main() { 
   auto range = FibonacciSeries(); 
   report("Original range", range);
   
   range.popFrontN(2); 
   report("After removing two elements", range); 
   
   auto theCopy = range.save; 
   report("The copy", theCopy);
   
   range.popFrontN(3); 
   report("After removing three more elements", range); 
   report("The copy", theCopy); 
}

Ketika kode di atas dikompilasi dan dijalankan, itu menghasilkan hasil sebagai berikut -

Original range: [0, 1, 1, 2, 3] 
After removing two elements: [1, 2, 3, 5, 8] 
The copy: [1, 2, 3, 5, 8] 
After removing three more elements: [5, 8, 13, 21, 34] 
The copy: [1, 2, 3, 5, 8]

BidirectionalRange

BidirectionalRange juga menyediakan dua fungsi anggota di atas fungsi anggota ForwardRange. Fungsi belakang yang mirip dengan depan, menyediakan akses ke elemen terakhir dari jangkauan. Fungsi popBack mirip dengan fungsi popFront dan menghapus elemen terakhir dari rentang.

Contoh

import std.array; 
import std.stdio; 
import std.string; 

struct Reversed { 
   int[] range; 
   
   this(int[] range) { 
      this.range = range; 
   } 
   @property bool empty() const { 
      return range.empty; 
   }
   @property int front() const { 
      return range.back;  //  reverse 
   }
   @property int back() const { 
      return range.front; // reverse 
   } 
   void popFront() { 
      range.popBack(); 
   }
   void popBack() { 
      range.popFront(); 
   } 
} 
 
void main() { 
   writeln(Reversed([ 1, 2, 3])); 
}

Ketika kode di atas dikompilasi dan dijalankan, itu menghasilkan hasil sebagai berikut -

[3, 2, 1]

RandomAccessRange tak terbatas

opIndex () juga diperlukan jika dibandingkan dengan ForwardRange. Selain itu, nilai fungsi kosong akan diketahui pada waktu kompilasi sebagai false. Contoh sederhana dijelaskan dengan rentang kotak ditunjukkan di bawah ini.

import std.array; 
import std.stdio; 
import std.string; 
import std.range; 
import std.algorithm; 

class SquaresRange { 
   int first;  
   this(int first = 0) { 
      this.first = first; 
   }
   enum empty = false; 
   @property int front() const { 
      return opIndex(0); 
   }
   void popFront() { 
      ++first; 
   }
   @property SquaresRange save() const { 
      return new SquaresRange(first); 
   }
   int opIndex(size_t index) const { 
      /* This function operates at constant time */ 
      immutable integerValue = first + cast(int)index; 
      return integerValue * integerValue; 
   } 
}
  
bool are_lastTwoDigitsSame(int value) { 
   /* Must have at least two digits */ 
   if (value < 10) { 
      return false; 
   } 
   
   /* Last two digits must be divisible by 11 */ 
   immutable lastTwoDigits = value % 100; 
   return (lastTwoDigits % 11) == 0; 
} 
 
void main() { 
   auto squares = new SquaresRange(); 
   
   writeln(squares[5]);
   
   writeln(squares[10]); 
   
   squares.popFrontN(5); 
   writeln(squares[0]); 
   
   writeln(squares.take(50).filter!are_lastTwoDigitsSame); 
}

Ketika kode di atas dikompilasi dan dijalankan, itu menghasilkan hasil sebagai berikut -

25 
100 
25 
[100, 144, 400, 900, 1444, 1600, 2500]

Hingga RandomAccessRange

opIndex () dan panjang juga diperlukan jika dibandingkan dengan rentang dua arah. Ini dijelaskan dengan bantuan contoh rinci yang menggunakan deret Fibonacci dan contoh Rentang Kuadrat yang digunakan sebelumnya. Contoh ini bekerja dengan baik pada kompilator D normal tetapi tidak bekerja pada kompilator online.

Contoh

import std.array; 
import std.stdio; 
import std.string; 
import std.range; 
import std.algorithm; 

struct FibonacciSeries { 
   int first = 0; 
   int second = 1; 
   enum empty = false;   //  infinite range  
   
   @property int front() const { 
      return first;
   }
   void popFront() { 
      int third = first + second; 
      first = second; 
      second = third; 
   }
   @property FibonacciSeries save() const { 
      return this; 
   } 
}
  
void report(T)(const dchar[] title, const ref T range) { 
   writefln("%40s: %s", title, range.take(5)); 
}
  
class SquaresRange { 
   int first;  
   this(int first = 0) { 
      this.first = first; 
   } 
   enum empty = false; 
   @property int front() const { 
      return opIndex(0); 
   }
   void popFront() { 
      ++first; 
   }
   @property SquaresRange save() const { 
      return new SquaresRange(first); 
   } 
   int opIndex(size_t index) const { 
      /* This function operates at constant time */ 
      immutable integerValue = first + cast(int)index; 
      return integerValue * integerValue; 
   } 
}
  
bool are_lastTwoDigitsSame(int value) { 
   /* Must have at least two digits */ 
   if (value < 10) { 
      return false; 
   }
   
   /* Last two digits must be divisible by 11 */ 
   immutable lastTwoDigits = value % 100; 
   return (lastTwoDigits % 11) == 0; 
}
  
struct Together { 
   const(int)[][] slices;  
   this(const(int)[][] slices ...) { 
      this.slices = slices.dup;  
      clearFront(); 
      clearBack(); 
   }
   private void clearFront() { 
      while (!slices.empty && slices.front.empty) { 
         slices.popFront(); 
      } 
   } 
   private void clearBack() { 
      while (!slices.empty && slices.back.empty) { 
         slices.popBack(); 
      } 
   }
   @property bool empty() const { 
      return slices.empty; 
   } 
   @property int front() const { 
      return slices.front.front; 
   }
   void popFront() { 
      slices.front.popFront(); 
      clearFront(); 
   }
   @property Together save() const { 
      return Together(slices.dup); 
   } 
   @property int back() const { 
      return slices.back.back; 
   } 
   void popBack() { 
      slices.back.popBack(); 
      clearBack(); 
   }
   @property size_t length() const { 
      return reduce!((a, b) => a + b.length)(size_t.init, slices); 
   }
   int opIndex(size_t index) const { 
      /* Save the index for the error message */ 
      immutable originalIndex = index;  

      foreach (slice; slices) { 
         if (slice.length > index) { 
            return slice[index];  
         } else { 
            index -= slice.length; 
         } 
      } 
      throw new Exception( 
         format("Invalid index: %s (length: %s)", originalIndex, this.length));
   } 
}
void main() { 
   auto range = Together(FibonacciSeries().take(10).array, [ 777, 888 ],
      (new SquaresRange()).take(5).array); 
   writeln(range.save); 
}

Ketika kode di atas dikompilasi dan dijalankan, itu menghasilkan hasil sebagai berikut -

[0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 777, 888, 0, 1, 4, 9, 16]

OutputRange

OutputRange mewakili keluaran elemen yang dialirkan, mirip dengan mengirim karakter ke stdout. OutputRange membutuhkan dukungan untuk operasi put (range, element). put () adalah fungsi yang didefinisikan dalam modul std.range. Ini menentukan kemampuan jangkauan dan elemen pada waktu kompilasi dan menggunakan metode yang paling tepat untuk digunakan untuk mengeluarkan elemen. Contoh sederhana ditunjukkan di bawah ini.

import std.algorithm; 
import std.stdio; 
 
struct MultiFile { 
   string delimiter;
   File[] files;
   
   this(string delimiter, string[] fileNames ...) { 
      this.delimiter = delimiter; 

      /* stdout is always included */ 
      this.files ~= stdout; 

      /* A File object for each file name */ 
      foreach (fileName; fileNames) { 
         this.files ~= File(fileName, "w"); 
      } 
   }
   void put(T)(T element) { 
      foreach (file; files) { 
         file.write(element, delimiter); 
      } 
   }
}
void main() { 
   auto output = MultiFile("\n", "output_0", "output_1"); 
   copy([ 1, 2, 3], output);  
   copy([ "red", "blue", "green" ], output); 
}

Ketika kode di atas dikompilasi dan dijalankan, itu menghasilkan hasil sebagai berikut -

[1, 2, 3] 
["red", "blue", "green"]