Yineleyici
Yineleyici terimi , yazılım geliştirme alanından gelir ve bir kümenin öğelerinin yinelenebileceği bir işaretçiyi tanımlar (örneğin bir liste). Terim, matematiksel yineleme yönteminden türetilmiştir . Yineleyici, özellikle veritabanı alanında genellikle imleç olarak adlandırılır.
açıklama
Yineleyici, bir program içinde yazılım geliştiricisi tarafından bir kümenin öğelerine, diğer bir deyişle bir listeye erişmek için kullanılabilen özel bir işaretleyicidir. Yineleyiciler, "Listede başka bir öğe varsa, onu kullanılabilir hale getirin" temel ilkesi üzerinde çalışır.
Basitleştirilmiş terimlerle, bu, bir kelime listesi olan bir metni okumakla karşılaştırılabilir: "Bir sonraki kelime varsa, onu okuyun. Başka kelime kalmadığında metin biter. ”Yineleme adı verilen her erişim adımında, metnin tam olarak bir kelimesi işlenmeye hazırdır.
Programlama uygulamasında kullanılan yineleyicilerin çoğu okuma erişiminin ötesinde, o anda okunan bir öğeyi listeden kaldıran veya listeye yeni bir öğe ekleyen mekanizmalar sağlar, tıpkı bir metni düzenlerken sözcüklerin eklenebilmesi veya silinmesi gibi.
Dış yineleyiciler ve yineleyici tasarım modeli
Harici bir yineleyici, iki temel işlevi olan bir tür işaretçi olarak görülebilir: bir nesneler kümesindeki belirli bir öğeye ( öğe erişimi olarak adlandırılır ) başvurmak ve kendini değiştirerek kümedeki sonraki öğeye işaret etmek ( öğe geçişi olarak adlandırılır). ). Kullanılan programlama diline ve uygulamaya bağlı olarak, yineleyiciler ek işlevlere ve farklı davranışlara sahip olabilir.
Yineleyicinin temel amacı, kullanıcının bir kümedeki herhangi bir öğeye erişmesine izin verirken bunları kümenin veri yapısından izole etmesini sağlamaktır. Bu, kullanıcıya basit bir sekans veya liste gibi davranırken kalabalığın öğeleri mümkün olan her şekilde yönetmesini sağlar. Bir yineleyici sınıfı, kapsayıcı sınıfı, yani kümesi ile yakın koordinasyon içinde tasarlanır. Genellikle konteyner sınıfı, yineleyiciler oluşturmak için kullanılan işlevleri sağlar. Bir döngüdeki sayaç (döngü sayacı olarak da adlandırılır) bazen döngü yineleyicisi olarak adlandırılır. Böyle bir sayacın , öğe erişim işlevselliğini değil, yalnızca öğe geçiş işlevini eşleştirdiği unutulmamalıdır .
Örtülü yineleyiciler
Perl , Python , C # , Ruby gibi çeşitli nesne yönelimli dillerin yanı sıra daha yeni Java ve Delphi sürümleri, açık bir yineleyici nesnesi kullanmadan öğeler arasında yinelemenin içsel bir yolunu sağlar. Bununla birlikte, bu da mevcut olabilir, ancak böyle olması gerekiyorsa ilgili programlama dilinin kodunda mevcut değildir.
Örtük yineleyiciler, aşağıdaki Python örneğinde gösterildiği gibi, kendilerini genellikle foreach komutu veya eşdeğerleri aracılığıyla gösterir:
for value in iterable:
print(value)
Küme / liste döngü iterablekullanılarak çalıştırılır for; her döngü geçişinde, değişken valuegeçerli öğeyi içerir iterable.
Aşağıdaki Ruby örneğinin gösterdiği gibi, bazen yineleyiciler doğrudan veri toplama nesnesinden de üretilir:
iterable.each do |value|
puts value
end
Kümenin each/ listenin yöntemini çağırmak, döngünün eleman eleman boyunca ilerlediği iterablebir yineleyici sağlar do. Döngü gövdesi, geçerli öğeyi içeren puts valuedeğişkenle her öğe için yürütülür value.
Bu yineleme stiline dahili yineleme de denir çünkü kodu yinelenecek nesnenin bağlamında tamamen yürütülür. Bu, yinelemenin tüm yönlerini kontrol eder, ilgili kullanıcı veya programcı, anonim bir alt yordam kullanarak yalnızca bireysel yineleme adımları için işlem sağlar .
Python'a benzer şekilde liste uzantılarını veya benzer yapıları destekleyen diller , sonuç listesinin oluşturulması sırasında örtük yineleyicileri de kullanır:
names = [person.name for person in roster if person.male]
for ... in ...burada miktar / listenin üstündeki roster"mevcut eleman değişkeni" ile "döngü " person. Her eleman için bir koşulun (eleman için) geçerli olup olmadığı kontrol edilir, yani if person.malemiktar filtrelenir. Kalan öğeler person.namesonuç nameslistesine kopyalanır - bir isim listesi.
Bazen örtük, gizli doğa sadece kısmen mevcuttur. C ++ programlama dili , işlev şablonları aracılığıyla for_each işlevselliğini sağlar, bu örtük yinelemeye izin verir.
Endekslemenin tersi
Yineleyici, bir dizin veya anahtarın tersidir :
- İlişkili elemana, veri yapısının kendisi bilinmeden bir yineleyici aracılığıyla doğrudan erişilebilir. Bir indeks ile her zaman bir indekse ve bir veri yapısına ihtiyacınız vardır.
- Bir yineleyici yalnızca tam olarak bir veri yapısı için geçerlidir. Bir indeks diğer veri yapılarına aktarılabilir.
- Yineleyiciler serileştirilemez . Bunu yapmak için önce bir dizine dönüştürülmeleri gerekir.
Bir kabın, öğelerini yinelerken kendisini değiştirebilme becerisinin, modern, nesne yönelimli programlama dillerinde önemli olduğu kanıtlanmıştır. Tek tek nesneler arasındaki karşılıklı ilişkiler ve bunların işlemlerinin etkileri artık bu dillerde net değildir. Yineleyiciler bu sorunu çözmek için kullanılır.
Jeneratörler
Oluşturucu , her çağrıldığında bir dizinin bir (veya daha fazla) öğesini döndüren özel bir koroutin biçimidir . Bu sekans belirli bir liste olabilir, bu durumda jeneratör büyük ölçüde bir yineleyiciye karşılık gelir. Bir üretici aynı zamanda sadece (sonraki) elemanları çağrıldıklarında üretebilir - bu durumda yineleyici için gerekli olduğu gibi mevcut bir listeye ihtiyaç duymaz .
Çoğu yineleyici, üreticiler tarafından doğal ve sezgisel olarak uygulanabilir. Üreteçler, işlev çağrıları arasında yerel durumlarını korudukları için, ikili ağaç geçişleri gibi karmaşık durum bilgisi olan yineleyicileri uygulamak için idealdirler .
Listeden okumak yerine öğeler oluşturan bir oluşturucu örneği :
( Fibonacci dizisi ; Python komutunu kullanarak ilgili değerin "dönüşü" yield)
# Ein Generator für die Fibonacci-Folge
def fibonacci(limit_anzahl_elemente):
a, b = 0, 1
for _ in range(limit_anzahl_elemente):
a, b = b, a + b
yield a
# Die ersten Zahlen der Folge werden berechnet und ausgegeben
for number in fibonacci(100):
print(number)
Farklı programlama dillerinde yineleyiciler
C # ve diğer .NET dilleri
.NET çerçevesindeki yineleyiciler numaralandırıcılar olarak adlandırılır ve arabirim tarafından temsil edilir IEnumerator. kümenin bir sonraki öğesine giden ve sona ulaşıldığını gösteren IEnumeratoradı verilen bir işlevin MoveNext()yanı sıra Current, geçerli öğenin değerini almak için çağrılan bir özellik sağlar . Ayrıca, Reset()başa dönmek için isteğe bağlı bir işlev sunulur. Numaralandırıcı, başlangıcı işaret eden başlatma değeri olarak özel bir değer döndürür. Bu nedenle, başlatmadan sonra MoveNext()yürütmek gerekir .
Numaralandırıcılar tipik olarak arabirimi uygulayan GetEnumerator()bir nesneyle ilişkili bir işlev tarafından döndürülür IEnumerable. C #'daki foreach komutu, IEnumerablearayüzü uygulayan bir nesneden gelmese bile, bu tür herhangi bir işlev üzerinde çalışır . Aşağıdaki örnek, C # 2.0'da yineleyicilerin basit bir kullanımını gösterir:
// explizite Version
IEnumerator<MyType> iter = list.GetEnumerator();
while (iter.MoveNext())
Console.WriteLine(iter.Current);
// implizite Version
foreach (MyType item in list)
Console.WriteLine(item);
C # 2.0 ayrıca üreteçleri de destekler: olarak IEnumerable(veya aynı zamanda IEnumerator) dönen ancak komutu yield returnkullanan bir işlev , derleyici tarafından otomatik olarak uygun arabirimi uygulayan yeni bir sınıfa dönüştürülür.
C ++
C ++ programlama dili, büyük ölçekte yineleyiciler kullanır ve C ++ standart kitaplığı aracılığıyla ileri yineleyiciler , çift yönlü yineleyiciler ve rastgele erişim yineleyiciler gibi çeşitli türlerde yineleyiciler sağlar . Standart konteyner sınıflarının her birinin yineleyici türleri vardır. Standart yineleyicilerin sözdizimi , C'nin işaretçi aritmetiğine dayanıyordu . Operatörler *ve ->elemanları referans olarak kullanıldı. Gibi diğer operatörler ++, öğeler arasında gezinmek için kullanılır.
Yineleyiciler genellikle çiftler halinde kullanılır. Bir yineleyici geçerli yinelemeyi temsil ederken, diğeri yinelemenin sonunu temsil eder. Yineleyiciler, standart işlevler begin()ve end(). Yineleyici begin(), ilk öğeye işaret eder, yineleyici ise end()herhangi bir öğeye başvurmayan özel bir değere işaret eder. Son elemandan sonra bir yineleyici yerleştirilirse, özel değerini döndürür end(). Aşağıdaki örnek, C ++ 'da bir yineleyicinin tipik kullanımını gösterir:
ContainerType c; // Ein beliebiger Standard-Containertyp, wie std::list<sometype>
for (ContainerType::const_iterator constIt = c.begin(); constIt != c.end(); ++constIt) {
std::cout << *constIt << '\n';
}
Biraz farklı davranışa sahip birçok farklı yineleyici türü vardır. Her tür yineleyici, her tür kapsayıcıyı desteklemez. Bununla birlikte, programcıların şablondan bir sınıf türeterek kendi yineleyici türlerini tanımlamaları mümkündür std::iterator. Yineleyici güvenliği, farklı türler için ayrı ayrı tanımlanır. Kapalı yineleme C kısmen kullanılabilir ++ ve işlevler ile sağlanır std::for_each(), std::copy()ve std::accumulate(). Ancak yineleyiciler, onları başlatmak için her zaman açık bir nesneye ihtiyaç duyar, genellikle begin()ve tarafından döndürülen nesneler end(). Bu yapıldıktan sonra, yineleme, yineleyici nesnesi kullanılmadan örtük olarak yapılır. Aşağıdaki örnek for_each'in kullanımını göstermektedir:
// Ein beliebiger Standard-Containertyp jedes ItemType Elements
ContainerType<ItemType> c;
// Funktion, die Zugriff auf jedes Element besitzt
void processItem(const ItemType& i) {
std::cout << i << '\n';
}
// Eine for-each-Iterationsschleife
std::for_each(c.begin(), c.end(), processItem);
Aynı şey std::copyve kullanılarak da elde edilebilir std::ostream_iterator:
std::copy(C.begin(), C.end(), std::ostream_iterator<ItemType>(std::cout, "\n"));
Bu tekniğin bir sınırlaması, gövdenin sıralı olarak ilan edilmesine izin vermemesidir. Ek olarak, bu, başka bir yerde bildirilmesi ve bir parametre olarak iletilmesi gereken bir işlev işaretçisi gerektirir. Bu, Boost gibi kitaplıkların kullanılması ve ilgili infix sözdizimine sahip işlev nesneleri oluşturmak için kullanılan Lambda'nın kullanılmasıyla kısmen telafi edilebilir . Bu işlevsellik yalnızca dış kitaplıklar aracılığıyla sağlandığından, geçici çözümler olarak da bilinen çeşitli geçici çözümler kullanılmalıdır.
Java
Java JDK 1.2'de sunulan java.util.Iterator arabirimi, konteyner sınıflarının yinelenmesine olanak tanır. Her Iteratoradlandırılan fonksiyonları sağlar next(), hasNext()hem de adı verilen isteğe bağlı bir fonksiyon remove(). Yineleyiciler genellikle iterator(), karşılık gelen konteyner sınıfı tarafından kullanıma sunulan adı verilen bir işlev tarafından oluşturulur. Bir yineleyici, başlangıcı işaret eden başlatma değeri olarak özel bir değer döndürür. Bu nedenle next(), ilk öğeyi döndürecek olan başlatmadan sonra yürütmek gerekir . Fonksiyon hasNext(), son elemanın halihazırda iade edilip edilmediğini bulmak için kullanılır. Aşağıdaki örnek, Java'da yineleyicilerin basit bir kullanımını gösterir:
Iterator iter = list.iterator();
while (iter.hasNext())
System.out.println(iter.next());
Onu destekleyen koleksiyonlar için, isteğe bağlı özellik remove()erişilen son öğeyi kaldırır . Bu tür diğer değişikliklerin çoğu güvenli değildir. Ek olarak, java.util. İleri ve geri yinelemeye izin veren ve aynı zamanda geçerli öğenin dizinini döndüren ve öğeyi belirli bir konuma ekleyebilen benzer bir arabirim sağlayan Listyineleyici adı verilen bir yineleyici ListIterator.
İle J2SE 5.0, arabirim olan Iterableforeach anlamında döngüsü için bir genişletilmiş temsil ettiği, kişiye. Iterablefonksiyonunu tanımlar iterator()olduğunu Iteratordöndürür seni. Genişletilmiş for döngüsü kullanılarak, önceki örnek şu şekilde yazılabilir:
for (MyType obj: list)
System.out.print(obj);
MATLAB
MATLAB hem harici hem de dahili yineleyicileri destekler. Kullanıcının bir sonraki öğeyi sağlamakla yükümlü olduğu harici bir yineleme durumunda, aşağıdaki örnekte gösterildiği gibi birkaç öğe tanımlanabilir ve ardından bir for döngüsü ile çalıştırılabilir:
% Definition eines an integer arrays
myArray = [1, 3, 5, 7, 11, 13];
for n = myArray
% ... etwas mit n machen...
disp(n) %Integerausgabe zur Kommandozeile
end
Dahili bir yineleme durumunda, kullanıcı bir dizideki her öğeye erişmek için yineleyiciye bir işlem iletebilir. Birçok yerel işleç ve MATLAB işlevi, örtük bir dönüş değeri olarak karşılık gelen bir çıktı dizisini almak için aşırı yüklenir. Ayrıca, işlevler arrayfunve cellfunyerel ve sözde hücre dizileri aracılığıyla kullanıcı tanımlı işlemler için kullanılabilir .
function simpleFun
% Definition eines an integer arrays
myArray = [1, 3, 5, 7, 11, 13];
% Benutzerdefinierte Operation für jedes Element durchführen
myNewArray = arrayfun(@(a)myCustomFun(a), myArray);
% Arrayausgabe zur Kommandozeile
myNewArray
function outScalar = myCustomFun(inScalar)
% Mit 2 multiplizieren
outScalar = 2 * inScalar;
Alternatif olarak, yineleyici tasarım modelinin özel, nesneye yönelik bir uygulamasını sağlayarak dizinin depolama mekanizmalarını programlamadan soyutlamak istenebilir. Harici yinelemeyi destekleyen böyle bir uygulama, MATLAB Merkezi Dosya Değişimi öğesinde sunulur. Bu tasarım deseni, MATLAB sürüm 7.6 (R2008a) ile sunulan yeni sınıf tanımı sözdizimine göre yazılmıştır. Ayrıca, her bir veri tipini heterojen bir şekilde saklamak için Liste Özet Veri Tipinin tek boyutlu bir hücre dizisi uygulaması dahil edilmiştir. Bu içeren bir liste işlemek için işlevsellik sağlar , ve bir de süre döngü.
hasNext()next()reset()
PHP
PHP4 foreachile Perl ve diğer birçok programlama diline benzer şekilde yapılandırılmış bir yapı tanıtıldı. Bu yapı, diziler üzerinde yinelemenin basit bir yolunu sağlar. foreachKomut sadece PHP4'te diziler ile çalışır ve farklı bir veri türü veya başlatılmamış değişken üzerinde kullanmaya çalışırsanız bir hata verir. PHP5'te foreachtüm genel üyelerin üzerinde yineleme komutuna izin verilir. Aşağıdaki örnek, iki farklı gösterimi gösterir; ikincisi, ilk gösterimin kullanışlı bir uzantısıdır:
- Örnek A.
foreach (array_expression as $value)
echo "$value\n"
- Örnek B.
foreach (array_expression as $key => $value)
echo "($key)$value\n";
Örnek A'da, dizi_ifadesi ile temsil edilen bir dizi üzerinde yinelenir. Her döngü geçişinde, dizi öğesinin değeri $valueatanır ve dizinin dahili göstericisi bir ileri itilir. Bu, sonraki dizi öğesinin bir sonraki döngü geçişinde döndürüldüğü anlamına gelir. Örnek B, örnek A ile aynı işlevselliğe sahiptir. Ek olarak, öğenin dizini, her döngüye girdiğinde değişkene atanır $key.
PHP5'te yineleyici arayüzü önceden tanımlanmıştır, nesneler yinelemeyi işlemek için değiştirilebilir.
class MyIterator implements Iterator {
private $var = array();
public function __construct($array) {
if (is_array($array)) {
$this->var = $array;
}
}
public function rewind() {
echo "rewinding\n";
reset($this->var);
}
public function current() {
$var = current($this->var);
echo "current: $var\n";
return $var;
}
public function key() {
$var = key($this->var);
echo "key: $var\n";
return $var;
}
public function next() {
$var = next($this->var);
echo "next: $var\n";
return $var;
}
public function valid() {
$var = $this->current() !== false;
echo "valid: {$var}\n";
return $var;
}
}
Bu işlevlerin tümü tam bir foreach($obj as $key=>$value)sırayla kullanılır. Yineleme yöntemleri aşağıdaki sırayla çalışır:
1. rewind()
2. while valid()
{
2.1 current() in $value
2.3 key() in $key
2.4 next()
}
piton
Python'daki yineleyiciler, dilin temel bir bölümünü temsil eder, ancak genellikle örtük olarak kullanılırlar ve bu nedenle dil komutlarında görünmez bir şekilde gizlenirler. Bu tür komutlar örn. B. for(foreach) sözde liste anlayışlarında ve oluşturucu ifadelerde. Python'daki tüm sıralı temel türlerin yanı sıra standart kitaplığın birçok sınıfı yinelemeleri destekler. Aşağıdaki örnek, bir dizi üzerinde tipik bir yinelemeyi gösterir:
for value in sequence:
print(value)
Bir ilişkilendirilebilir dizi biçimi olan Python Sözlükleri , sözde sözlük anahtarları döndürüldüğünde doğrudan kendi üzerinde yinelemesine izin verir . Ayrıca , aşağıdaki örneğe göre anahtar ve değer için değerleri döndürdüğü bir sözlüğün öğeler işlevi üzerinde yinelenebilir:
for key in dictionary:
value = dictionary[key]
print(key, value)
for key, value in dictionary.items():
print(key, value)
Python'daki yineleyiciler de açıkça tanımlanabilir ve kullanılabilir. Her yinelenebilir dizi türü veya her yinelenebilir sınıf için, yerleşik iter()işlev bir yineleyici nesnesi oluşturmak için kullanılabilir. Yineleyici nesnesi next(), veya işlevleriyle bir __next__()sonraki öğeye gitmek için kullanılabilir . Setin sonuna ulaşılırsa, bir StopIterationhata ortaya çıkar. Aşağıdaki örnek, açık yineleyicilerin eşdeğer bir uygulamasını gösterir:
it = iter(sequence)
while True:
try:
value = it.next()
except StopIteration:
break
print(value)
Her kullanıcı tanımlı sınıf, _iter__()bir yineleyici nesnesi oluşturan bir işlev tanımlanmışsa , standart yinelemeyi destekleyebilir , yineleyicinin daha sonra bir __next__()sonraki öğeyi döndüren bir işlevi tanımlaması gerekir . Python üreteçleri bu yineleme protokolünü uygular.
Yakut
Ruby'deki yineleyicilerin uygulanması, diğer programlama dillerinin çoğundan farklıdır: Tüm yinelemeler, sözde geri arama kapanışlarından kapsayıcı yöntemlerine geçirme fikrini izler. Bu şekilde Ruby yalnızca yineleyicilerin temel işlevlerini uygulamakla kalmaz, aynı zamanda aşağıdakiler gibi birçok yineleyici tasarım modelini de eşler: B. sözde fonksiyon haritalama , filtreler ve sözde indirgeme .
Ruby ayrıca yineleme için her temel işlev için alternatif bir sözdizimi destekler:
(0...42).each do |n|
puts n
end
… ve …
for n in 0...42
puts n
end
hatta daha kısa
42.times do |n|
puts n
end
Ayrıca bakınız
İnternet linkleri
- Joshua Gatcomb: Yineleyicileri Anlamak ve Kullanmak . (İngilizce)
- Genel Yineleme ve Optimizasyonu İçin Bir Teknik . (PDF; İngilizce; 216 kB)
- STL yineleyiciler . (İngilizce)
- Yineleyiciler nedir? - Referans açıklaması. (İngilizce)
- Arayüz
IteratorJava API - .NET arayüzü içinde MSDN
- C ++ Yineleyici Kitaplığını Artırın (İngilizce)
- PHP: Nesne yinelemesi (İngilizce)
Bireysel kanıt
-
↑
std::for_each() -
↑
std::copy() -
↑
std::accumulate() -
↑
std::ostream_iterator -
↑
java.util.IteratorJava API Spesifikasyonu -
↑
next()Java API Spesifikasyonu -
↑
hasNext()Java API Spesifikasyonu -
↑
remove()Java API Spesifikasyonu -
↑
java.util.ListJava API Spesifikasyonu -
↑
java.util.ListIteratorJava API Spesifikasyonu -
↑
IterableJava API Spesifikasyonu -
↑
iterator()Java API Spesifikasyonu - ↑ Tasarım Deseni: Yineleyici (Davranış)