D Programlama - Aralıklar
Aralıklar, öğe erişiminin bir soyutlamasıdır. Bu soyutlama, çok sayıda kap türü üzerinde çok sayıda algoritmanın kullanılmasını sağlar. Aralıklar, kapsayıcıların nasıl uygulandığının aksine, kapsayıcı öğelerine nasıl erişildiğini vurgular. Aralıklar, bir türün belirli üye işlev kümelerini tanımlayıp tanımlamadığına dayanan çok basit bir kavramdır.
Aralıklar, D'nin dilimlerinin ayrılmaz bir parçasıdır ve en güçlü RandomAccessRange aralığının uygulamalarıdır ve Phobos'ta birçok aralık özelliği vardır. Çoğu Phobos algoritması geçici aralık nesneleri döndürür. Örneğin, filter () aşağıdaki kodda 10'dan büyük olan öğeleri seçer, aslında bir dizi değil, bir aralık nesnesi döndürür.
Sayı aralıkları
Sayı aralıkları oldukça yaygın olarak kullanılmaktadır ve bu sayı aralıkları int tipindedir. Sayı aralıkları için birkaç örnek aşağıda gösterilmiştir -
// Example 1
foreach (value; 3..7)
// Example 2
int[] slice = array[5..10];
Phobos Serileri
Yapılar ve sınıf arayüzleriyle ilgili aralıklar, phobos aralıklarıdır. Phobos, D dil derleyicisi ile birlikte gelen resmi çalışma zamanı ve standart kitaplıktır.
Aşağıdakileri içeren çeşitli aralık türleri vardır:
- InputRange
- ForwardRange
- BidirectionalRange
- RandomAccessRange
- OutputRange
Giriş aralığı
En basit aralık, giriş aralığıdır. Diğer seriler, temel aldıkları serinin üstüne daha fazla gereksinim getirir. InputRange'in gerektirdiği üç işlev vardır -
empty- Aralığın boş olup olmadığını belirtir; aralığın boş olduğu kabul edildiğinde true döndürmelidir; aksi takdirde false.
front - Aralığın başındaki elemana erişim sağlar.
popFront() - İlk elemanı kaldırarak menzili baştan kısaltır.
Misal
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);
}
Yukarıdaki kod derlendiğinde ve yürütüldüğünde, aşağıdaki sonucu verir -
[Raj(1), John(2), Ram(3)]
3
Raj(1)
false
[John(2), Ram(3)]
ForwardRange
ForwardRange, ayrıca InputRange'in diğer üç işlevinden kaydetme üye işlevi bölümünü gerektirir ve kaydetme işlevi çağrıldığında aralığın bir kopyasını döndürür.
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);
}
Yukarıdaki kod derlendiğinde ve yürütüldüğünde, aşağıdaki sonucu verir -
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]
Çift Yönlü Aralık
BidirectionalRange ayrıca ForwardRange üye işlevleri üzerinde iki üye işlevi sağlar. Ön tarafa benzeyen arka işlev, aralığın son öğesine erişim sağlar. PopBack işlevi popFront işlevine benzer ve aralıktaki son öğeyi kaldırır.
Misal
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]));
}
Yukarıdaki kod derlendiğinde ve yürütüldüğünde, aşağıdaki sonucu verir -
[3, 2, 1]
Sonsuz RandomAccessRange
opIndex (), ForwardRange ile karşılaştırıldığında ek olarak gereklidir. Ayrıca, derleme zamanında yanlış olarak bilinecek boş bir işlevin değeri. Aşağıda kareler aralığı ile basit bir örnek açıklanmıştır.
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);
}
Yukarıdaki kod derlendiğinde ve yürütüldüğünde, aşağıdaki sonucu verir -
25
100
25
[100, 144, 400, 900, 1444, 1600, 2500]
Sonlu RandomAccessRange
opIndex () ve uzunluk, çift yönlü aralık ile karşılaştırıldığında ek olarak gereklidir. Bu, daha önce kullanılan Fibonacci serisi ve Squares Range örneğini kullanan detaylı örnek yardımıyla açıklanmıştır. Bu örnek normal D derleyicisinde iyi çalışır ancak çevrimiçi derleyicide çalışmaz.
Misal
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);
}
Yukarıdaki kod derlendiğinde ve yürütüldüğünde, aşağıdaki sonucu verir -
[0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 777, 888, 0, 1, 4, 9, 16]
Çıktı aralığı
OutputRange, karakterleri stdout'a göndermeye benzer şekilde akışlı öğe çıktısını temsil eder. OutputRange, put (aralık, öğe) işlemi için destek gerektirir. put (), std.range modülünde tanımlanan bir işlevdir. Derleme zamanında aralığın ve elemanın yeteneklerini belirler ve elemanların çıktısını almak için en uygun yöntemi kullanır. Aşağıda basit bir örnek gösterilmektedir.
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);
}
Yukarıdaki kod derlendiğinde ve yürütüldüğünde, aşağıdaki sonucu verir -
[1, 2, 3]
["red", "blue", "green"]