Iterators: Difference between revisions
Puppydrum64 (talk | contribs) |
Thundergnat (talk | contribs) m (syntax highlighting fixup automation) |
||
Line 20: | Line 20: | ||
Also, I'm making the assumption that the "Print the first, fourth, and fifth elements of each container" were intended to be one-indexed (i.e print the strings at offsets zero, three, and four) |
Also, I'm making the assumption that the "Print the first, fourth, and fifth elements of each container" were intended to be one-indexed (i.e print the strings at offsets zero, three, and four) |
||
< |
<syntaxhighlight lang="68000devpac">main: |
||
PrintAll: |
PrintAll: |
||
Line 117: | Line 117: | ||
Purple: |
Purple: |
||
dc.b "Purple",0 |
dc.b "Purple",0 |
||
even</ |
even</syntaxhighlight> |
||
=={{header|BASIC256}}== |
=={{header|BASIC256}}== |
||
{{trans|FreeBASIC}} |
{{trans|FreeBASIC}} |
||
< |
<syntaxhighlight lang="freebasic">arraybase 1 |
||
dim list$ = {{"Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday"}, {"Red","Orange","Yellow","Green","Blue","Purple"}} |
dim list$ = {{"Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday"}, {"Red","Orange","Yellow","Green","Blue","Purple"}} |
||
dim ind = {1,4,5} |
dim ind = {1,4,5} |
||
Line 153: | Line 153: | ||
print |
print |
||
end |
end |
||
</syntaxhighlight> |
|||
</lang> |
|||
<pre>Igual que la entrada de FreeBASIC.</pre> |
<pre>Igual que la entrada de FreeBASIC.</pre> |
||
=={{header|C++}}== |
=={{header|C++}}== |
||
< |
<syntaxhighlight lang="cpp">#include <iostream> |
||
#include <list> |
#include <list> |
||
#include <string> |
#include <string> |
||
Line 206: | Line 206: | ||
FirstFourthFifth(colors.rbegin()); |
FirstFourthFifth(colors.rbegin()); |
||
} |
} |
||
</syntaxhighlight> |
|||
</lang> |
|||
{{out}} |
{{out}} |
||
<pre>All elements: |
<pre>All elements: |
||
Line 223: | Line 223: | ||
=={{header|F_Sharp|F#}}== |
=={{header|F_Sharp|F#}}== |
||
< |
<syntaxhighlight lang="fsharp"> |
||
//Iterators. Nigel Galloway: Januuary 30th., 2022 |
//Iterators. Nigel Galloway: Januuary 30th., 2022 |
||
let N,G=[|"Sunday"; "Monday"; "Tuesday"; "Wednesday"; "Thursday"; "Friday"; "Saturday"|],["Red"; "Orange"; "Yellow"; "Green"; "Blue"; "Purple"] |
let N,G=[|"Sunday"; "Monday"; "Tuesday"; "Wednesday"; "Thursday"; "Friday"; "Saturday"|],["Red"; "Orange"; "Yellow"; "Green"; "Blue"; "Purple"] |
||
Line 238: | Line 238: | ||
let X=(N|>Array.rev|>Seq.ofArray).GetEnumerator() in printfn $"{next X} {(advance X 3; next X)} {next X}" |
let X=(N|>Array.rev|>Seq.ofArray).GetEnumerator() in printfn $"{next X} {(advance X 3; next X)} {next X}" |
||
let X=(G|>List.rev|>Seq.ofList).GetEnumerator() in printfn $"{next X} {(advance X 3; next X)} {next X}" |
let X=(G|>List.rev|>Seq.ofList).GetEnumerator() in printfn $"{next X} {(advance X 3; next X)} {next X}" |
||
</syntaxhighlight> |
|||
</lang> |
|||
{{out}} |
{{out}} |
||
<pre> |
<pre> |
||
Line 253: | Line 253: | ||
=={{header|FreeBASIC}}== |
=={{header|FreeBASIC}}== |
||
< |
<syntaxhighlight lang="freebasic">Dim As Integer n, m |
||
Dim As String list(1 To 2, 1 To 7) = {_ |
Dim As String list(1 To 2, 1 To 7) = {_ |
||
{"Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday"}, _ |
{"Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday"}, _ |
||
Line 283: | Line 283: | ||
Print list(2, Ubound(list,2)-ind(m)); " "; |
Print list(2, Ubound(list,2)-ind(m)); " "; |
||
Next m |
Next m |
||
Sleep</ |
Sleep</syntaxhighlight> |
||
{{out}} |
{{out}} |
||
<pre> |
<pre> |
||
Line 295: | Line 295: | ||
Still, one approach here might be: |
Still, one approach here might be: |
||
< |
<syntaxhighlight lang="j">dow=: ;:'monday tuesday wednesday thursday friday saturday sunday' |
||
col=: (,<)/;:'red orange yellow green blue purple'</ |
col=: (,<)/;:'red orange yellow green blue purple'</syntaxhighlight> |
||
This gives us: |
This gives us: |
||
<syntaxhighlight lang="j"> |
|||
<lang J> |
|||
dow |
dow |
||
┌──────┬───────┬─────────┬────────┬──────┬────────┬──────┐ |
┌──────┬───────┬─────────┬────────┬──────┬────────┬──────┐ |
||
Line 318: | Line 318: | ||
│ ││ │└──────┴───────────────────────┘││ |
│ ││ │└──────┴───────────────────────┘││ |
||
│ │└──────┴────────────────────────────────┘│ |
│ │└──────┴────────────────────────────────┘│ |
||
└───┴─────────────────────────────────────────┘</ |
└───┴─────────────────────────────────────────┘</syntaxhighlight> |
||
Here, the implementation's array indexing would see the linked list representation as a two element array. To index arbitrary elements from the linked list, we might map back from the linked list representation to a flat array representation, perhaps using <S:0 (which is a no-op on our array of days of week). |
Here, the implementation's array indexing would see the linked list representation as a two element array. To index arbitrary elements from the linked list, we might map back from the linked list representation to a flat array representation, perhaps using <S:0 (which is a no-op on our array of days of week). |
||
< |
<syntaxhighlight lang="j"> echo ;:inv <S:0 dow |
||
monday tuesday wednesday thursday friday saturday sunday |
monday tuesday wednesday thursday friday saturday sunday |
||
echo ;:inv <S:0 col |
echo ;:inv <S:0 col |
||
Line 335: | Line 335: | ||
sunday friday thursday |
sunday friday thursday |
||
echo ;:inv _1 _3 _4 {<S:0 col |
echo ;:inv _1 _3 _4 {<S:0 col |
||
purple green yellow</ |
purple green yellow</syntaxhighlight> |
||
The downside of this approach is that the programmer must understand the data (to know to map all relevant list structures to the desired form). For example, we might instead say that a linked list is not merely an unbalanced binary tree, but must always have its data elements in the left node. That would give us this implementation for col: |
The downside of this approach is that the programmer must understand the data (to know to map all relevant list structures to the desired form). For example, we might instead say that a linked list is not merely an unbalanced binary tree, but must always have its data elements in the left node. That would give us this implementation for col: |
||
<syntaxhighlight lang="j"> |
|||
<lang J> |
|||
col=: '' ]F..(,<) ;:'red orange yellow green blue purple' |
col=: '' ]F..(,<) ;:'red orange yellow green blue purple' |
||
</syntaxhighlight> |
|||
</lang> |
|||
< |
<syntaxhighlight lang="j"> col |
||
┌──────┬───────────────────────────────────────┐ |
┌──────┬───────────────────────────────────────┐ |
||
│purple│┌────┬────────────────────────────────┐│ |
│purple│┌────┬────────────────────────────────┐│ |
||
Line 356: | Line 356: | ||
│ ││ │└─────┴────────────────────────┘││ |
│ ││ │└─────┴────────────────────────┘││ |
||
│ │└────┴────────────────────────────────┘│ |
│ │└────┴────────────────────────────────┘│ |
||
└──────┴───────────────────────────────────────┘</ |
└──────┴───────────────────────────────────────┘</syntaxhighlight> |
||
This creates an issue that a single element nested list looks very much like a flat array. To prevent that from being a problem, we include an empty element at the end of our flat array: |
This creates an issue that a single element nested list looks very much like a flat array. To prevent that from being a problem, we include an empty element at the end of our flat array: |
||
<syntaxhighlight lang="j"> |
|||
<lang J> |
|||
dow=: a:,~;:'monday tuesday wednesday thursday friday saturday sunday' |
dow=: a:,~;:'monday tuesday wednesday thursday friday saturday sunday' |
||
</syntaxhighlight> |
|||
</lang> |
|||
< |
<syntaxhighlight lang="j"> dow |
||
┌──────┬───────┬─────────┬────────┬──────┬────────┬──────┬┐ |
┌──────┬───────┬─────────┬────────┬──────┬────────┬──────┬┐ |
||
│monday│tuesday│wednesday│thursday│friday│saturday│sunday││ |
│monday│tuesday│wednesday│thursday│friday│saturday│sunday││ |
||
└──────┴───────┴─────────┴────────┴──────┴────────┴──────┴┘</ |
└──────┴───────┴─────────┴────────┴──────┴────────┴──────┴┘</syntaxhighlight> |
||
Now everything is the same as before, except that we need to explicitly ignore the empty trailing element: |
Now everything is the same as before, except that we need to explicitly ignore the empty trailing element: |
||
< |
<syntaxhighlight lang="j"> echo ;:inv _2 _4 _5 {<S:0 dow |
||
sunday friday thursday |
sunday friday thursday |
||
echo ;:inv _2 _4 _5 {<S:0 col |
echo ;:inv _2 _4 _5 {<S:0 col |
||
red yellow green</ |
red yellow green</syntaxhighlight> |
||
That said, we now also have the opportunity to implement a different kind of normalization routine, which takes advantage of the difference in representation (if we had a need for that...). |
That said, we now also have the opportunity to implement a different kind of normalization routine, which takes advantage of the difference in representation (if we had a need for that...). |
||
Line 384: | Line 384: | ||
For example: |
For example: |
||
< |
<syntaxhighlight lang="j">nextItem=: {{ (x+1) -.#y }} |
||
nextLink=: {{ (1;x) #~ (L.y) > #x }} |
nextLink=: {{ (1;x) #~ (L.y) > #x }} |
||
Line 399: | Line 399: | ||
more=: {{'`next val more'=. ops['ops list position'=. y |
more=: {{'`next val more'=. ops['ops list position'=. y |
||
more position |
more position |
||
}}</ |
}}</syntaxhighlight> |
||
With this approach, one of the task examples could look like this: |
With this approach, one of the task examples could look like this: |
||
<syntaxhighlight lang="j"> |
|||
<lang J> |
|||
printAll=: {{ |
printAll=: {{ |
||
while. more y do. |
while. more y do. |
||
Line 431: | Line 431: | ||
monday |
monday |
||
value iterate^:3 DOW |
value iterate^:3 DOW |
||
thursday</ |
thursday</syntaxhighlight> etc. |
||
(Except that this approach does not support negative indexing, so indexing from the end of a list would, for the general case, require either extending the system with explicit support for a length operation or iterating once over the list to determine the list length.) |
(Except that this approach does not support negative indexing, so indexing from the end of a list would, for the general case, require either extending the system with explicit support for a length operation or iterating once over the list to determine the list length.) |
||
Line 443: | Line 443: | ||
extensive set of functions which act on lists and vectors. Julia's Iterators can implement |
extensive set of functions which act on lists and vectors. Julia's Iterators can implement |
||
the C++ example: |
the C++ example: |
||
< |
<syntaxhighlight lang="julia">using DataStructures |
||
function PrintContainer(iterator) |
function PrintContainer(iterator) |
||
Line 473: | Line 473: | ||
FirstFourthFifth(reverse(days)) |
FirstFourthFifth(reverse(days)) |
||
FirstFourthFifth(reverse(colors)) |
FirstFourthFifth(reverse(colors)) |
||
</ |
</syntaxhighlight>{{out}} |
||
<pre> |
<pre> |
||
All elements: |
All elements: |
||
Line 492: | Line 492: | ||
five builtin data types it is not an issue for a routine to "know" what it is doing.<br> |
five builtin data types it is not an issue for a routine to "know" what it is doing.<br> |
||
Something along the lines of [[Same_fringe#Phix]] could perhaps also be used to implement custom iterators. |
Something along the lines of [[Same_fringe#Phix]] could perhaps also be used to implement custom iterators. |
||
<!--< |
<!--<syntaxhighlight lang="phix">(phixonline)--> |
||
<span style="color: #008080;">with</span> <span style="color: #008080;">javascript_semantics</span> |
<span style="color: #008080;">with</span> <span style="color: #008080;">javascript_semantics</span> |
||
<span style="color: #008080;">procedure</span> <span style="color: #000000;">print_all</span><span style="color: #0000FF;">(</span><span style="color: #004080;">object</span> <span style="color: #000000;">s</span><span style="color: #0000FF;">)</span> |
<span style="color: #008080;">procedure</span> <span style="color: #000000;">print_all</span><span style="color: #0000FF;">(</span><span style="color: #004080;">object</span> <span style="color: #000000;">s</span><span style="color: #0000FF;">)</span> |
||
Line 522: | Line 522: | ||
<span style="color: #000000;">printFirstFourthFifth</span><span style="color: #0000FF;">(</span><span style="color: #000000;">days</span><span style="color: #0000FF;">,-</span><span style="color: #000000;">1</span><span style="color: #0000FF;">)</span> |
<span style="color: #000000;">printFirstFourthFifth</span><span style="color: #0000FF;">(</span><span style="color: #000000;">days</span><span style="color: #0000FF;">,-</span><span style="color: #000000;">1</span><span style="color: #0000FF;">)</span> |
||
<span style="color: #000000;">printFirstFourthFifth</span><span style="color: #0000FF;">(</span><span style="color: #000000;">colors</span><span style="color: #0000FF;">,-</span><span style="color: #000000;">1</span><span style="color: #0000FF;">)</span> |
<span style="color: #000000;">printFirstFourthFifth</span><span style="color: #0000FF;">(</span><span style="color: #000000;">colors</span><span style="color: #0000FF;">,-</span><span style="color: #000000;">1</span><span style="color: #0000FF;">)</span> |
||
<!--</ |
<!--</syntaxhighlight>--> |
||
Originally I used keys of 1..6 on the colours dictionary, but that looked suspicious. |
Originally I used keys of 1..6 on the colours dictionary, but that looked suspicious. |
||
Note that the keys here are a mix of int/flt/string/seq, but still carefully "in order". |
Note that the keys here are a mix of int/flt/string/seq, but still carefully "in order". |
||
Line 545: | Line 545: | ||
We can create our own iterators by implementing the ''iterator protocol''. The iterator protocol requires us to implement an <code>__iter__</code> method and a <code>__next__</code> method, as demonstrated by the <code>MyIterable</code> and <code>MyIterator</code> classes below. |
We can create our own iterators by implementing the ''iterator protocol''. The iterator protocol requires us to implement an <code>__iter__</code> method and a <code>__next__</code> method, as demonstrated by the <code>MyIterable</code> and <code>MyIterator</code> classes below. |
||
< |
<syntaxhighlight lang="python">"""Iterables and iterators. Requires Python >= 3.6 for type hints.""" |
||
from collections import deque |
from collections import deque |
||
from typing import Iterable |
from typing import Iterable |
||
Line 666: | Line 666: | ||
if __name__ == "__main__": |
if __name__ == "__main__": |
||
main() |
main() |
||
</syntaxhighlight> |
|||
</lang> |
|||
{{out}} |
{{out}} |
||
Line 695: | Line 695: | ||
The following example iterates though a hash of Positional Iterable objects and demonstrates both using explicit iterators, and object slice operations on each; then has a semi contrived example of where directly using iterators may be actually useful in Raku; collating unique ascending values from several infinite sequence generators. |
The following example iterates though a hash of Positional Iterable objects and demonstrates both using explicit iterators, and object slice operations on each; then has a semi contrived example of where directly using iterators may be actually useful in Raku; collating unique ascending values from several infinite sequence generators. |
||
<lang |
<syntaxhighlight lang="raku" line>my %positional-iterable-types = |
||
array => [<Sunday Monday Tuesday Wednesday Thursday Friday Saturday>], |
array => [<Sunday Monday Tuesday Wednesday Thursday Friday Saturday>], |
||
list => <Red Orange Yellow Green Blue Purple>, |
list => <Red Orange Yellow Green Blue Purple>, |
||
Line 733: | Line 733: | ||
} |
} |
||
say @seq[^25];</ |
say @seq[^25];</syntaxhighlight> |
||
{{out}} |
{{out}} |
||
<pre>Note: here we are iterating over the %positional-iterable-types hash, but |
<pre>Note: here we are iterating over the %positional-iterable-types hash, but |
||
Line 765: | Line 765: | ||
=={{header|Ring}}== |
=={{header|Ring}}== |
||
{{incorrect|Ring|The task is specifically about ''iterators'', not [[wp:Iterator#Contrasting_with_indexing|counting loops with indexing]].}} |
{{incorrect|Ring|The task is specifically about ''iterators'', not [[wp:Iterator#Contrasting_with_indexing|counting loops with indexing]].}} |
||
< |
<syntaxhighlight lang="ring"> |
||
list = [["Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday"], |
list = [["Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday"], |
||
["Red","Orange","Yellow","Green","Blue","Purple"]] |
["Red","Orange","Yellow","Green","Blue","Purple"]] |
||
Line 800: | Line 800: | ||
see "done..." +nl |
see "done..." +nl |
||
</syntaxhighlight> |
|||
</lang> |
|||
{{out}} |
{{out}} |
||
<pre> |
<pre> |
||
Line 826: | Line 826: | ||
The iterator protocol methods are not usually called directly as Wren's 'for' statement (and the Sequence methods) call them automatically under the hood. However, in the spirit of this task, they are called directly. |
The iterator protocol methods are not usually called directly as Wren's 'for' statement (and the Sequence methods) call them automatically under the hood. However, in the spirit of this task, they are called directly. |
||
< |
<syntaxhighlight lang="ecmascript">import "./llist" for DLinkedList |
||
// Use iterators to print all elements of the sequence. |
// Use iterators to print all elements of the sequence. |
||
Line 862: | Line 862: | ||
System.print("\nReverse first, fourth, and fifth elements:") |
System.print("\nReverse first, fourth, and fifth elements:") |
||
printFirstFourthFifth.call(days[-1..0]) |
printFirstFourthFifth.call(days[-1..0]) |
||
printFirstFourthFifth.call(colors.reversed)</ |
printFirstFourthFifth.call(colors.reversed)</syntaxhighlight> |
||
{{out}} |
{{out}} |
||
Line 885: | Line 885: | ||
as XPL0 can come to meeting the requirements of the task. |
as XPL0 can come to meeting the requirements of the task. |
||
<syntaxhighlight lang="xpl0"> |
|||
<lang XPL0> |
|||
\\ Use iterators to print all of the elements of any container that supports |
\\ Use iterators to print all of the elements of any container that supports |
||
\\ iterators. It print elements starting at 'start' up to, but not |
\\ iterators. It print elements starting at 'start' up to, but not |
||
Line 928: | Line 928: | ||
FirstFourthFifth(@Days(7-1), -1); |
FirstFourthFifth(@Days(7-1), -1); |
||
FirstFourthFifth(@Colors(6-1), -1); |
FirstFourthFifth(@Colors(6-1), -1); |
||
]</ |
]</syntaxhighlight> |
||
{{out}} |
{{out}} |
Revision as of 16:46, 27 August 2022
Iterators are a design pattern that can be used to access elements of a container without depending on the implementation or type of the container.
- Task
- Create an array like container to hold the days of the week and a linked-list like container to hold colors.
- Print all of the elements of each container.
- Print the first, fourth, and fifth elements of each container.
- Print the last, fourth to last, and fifth to last of each container.
If you language supports iterators, use them. Otherwise show how access to elements can be
separated from the containers that hold them.
68000 Assembly
The easiest way to do this is with a table of pointers, as they're always 4 bytes regardless of the size of the data they point to.
Also, I'm making the assumption that the "Print the first, fourth, and fifth elements of each container" were intended to be one-indexed (i.e print the strings at offsets zero, three, and four)
main:
PrintAll:
MOVE.W #7-1,D7
MOVEQ #0,D1
.loop:
LEA Days_Of_The_Week,A0
LEA Colors,A1
MOVE.W D1,D2
LSL.W #2,D2
MOVEA.L (A0,D2),A3
JSR PrintString ;unimplemented hardware-dependent printing routine
MOVEA.L (A1,D2),A3
JSR PrintString
ADDQ.W #1,D1
DBRA D7,.loop
Part2:
LEA Days_Of_The_Week,A0
LEA Colors,A1
MOVEA.L (A0),A3
JSR PrintString
MOVEA.L (12,A0),A3
JSR PrintString
MOVEA.L (16,A0),A3
JSR PrintString
MOVEA.L (A1),A3
JSR PrintString
MOVEA.L (12,A1),A3
JSR PrintString
MOVEA.L (16,A1),A3
JSR PrintString
Part3:
LEA Days_Of_The_Week,A0
LEA Colors,A1
MOVEA.L (24,A0),A3
JSR PrintString
MOVEA.L (12,A0),A3
JSR PrintString
MOVEA.L (8,A0),A3
JSR PrintString
MOVEA.L (20,A1),A3
JSR PrintString
MOVEA.L (8,A1),A3
JSR PrintString
MOVEA.L (4,A1),A3
JSR PrintString
JMP * ;HALT THE CPU
Days_Of_The_Week:
DC.L Sunday,Monday,Tuesday,Wednesday,Thursday,Friday,Saturday
; 0 4 8 12 16 20 24
Sunday:
DC.B "Sunday",0
EVEN ;conditionally aligns to a 2-byte boundary if the data isn't aligned already
Monday:
DC.B "Monday",0
EVEN
Tuesday:
DC.B "Tuesday",0
EVEN
Wednesday:
DC.B "Wednesday",0
EVEN
Thursday:
DC.B "Thursday",0
EVEN
Friday:
DC.B "Friday",0
EVEN
Saturday:
DC.B "Saturday",0
EVEN
Colors:
DC.L Red,Orange,Yellow,Green,Blue,Purple
Red:
DC.B "Red",0
even
Orange:
DC.B "Orange",0
even
Yellow:
DC.B "Yellow",0
even
Green:
dc.b "Green",0
even
Blue:
dc.b "Blue",0
even
Purple:
dc.b "Purple",0
even
BASIC256
arraybase 1
dim list$ = {{"Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday"}, {"Red","Orange","Yellow","Green","Blue","Purple"}}
dim ind = {1,4,5}
print "All elements:"
for n = 1 to list$[?,]
for m = 1 to list$[,?]
print list$[n, m]; " ";
next m
print
next n
print
print "First, fourth, and fifth elements:"
for n = 1 to list$[?,]
for m = 1 to ind[?]
print list$[n, ind[m]]; " ";
next m
print
next n
print
print "Reverse first, fourth, and fifth elements:"
for m = 1 to ind[?]
print list$[1, list$[,?]+1-ind[m]]; " ";
next m
print
for m = 1 to ind[?]
print list$[2, list$[,?]-ind[m]]; " ";
next m
print
end
Igual que la entrada de FreeBASIC.
C++
#include <iostream>
#include <list>
#include <string>
#include <vector>
using namespace std;
// Use iterators to print all of the elements of any container that supports
// iterators. It print elements starting at 'start' up to, but not
// including, 'sentinel'.
void PrintContainer(forward_iterator auto start, forward_iterator auto sentinel)
{
for(auto it = start; it != sentinel; ++it)
{
cout << *it << " ";
}
cout << "\n";
}
// Use an iterator to print the first, fourth, and fifth elements
void FirstFourthFifth(input_iterator auto it)
{
cout << *it;
advance(it, 3);
cout << ", " << *it;
advance(it, 1);
cout << ", " << *it;
cout << "\n";
}
int main()
{
// Create two differnt kinds of containers of strings
vector<string> days{"Sunday", "Monday", "Tuesday", "Wednesday",
"Thursday", "Friday", "Saturday"};
list<string> colors{"Red", "Orange", "Yellow", "Green", "Blue", "Purple"};
cout << "All elements:\n";
PrintContainer(days.begin(), days.end());
PrintContainer(colors.begin(), colors.end());
cout << "\nFirst, fourth, and fifth elements:\n";
FirstFourthFifth(days.begin());
FirstFourthFifth(colors.begin());
cout << "\nReverse first, fourth, and fifth elements:\n";
FirstFourthFifth(days.rbegin());
FirstFourthFifth(colors.rbegin());
}
- Output:
All elements: Sunday Monday Tuesday Wednesday Thursday Friday Saturday Red Orange Yellow Green Blue Purple First, fourth, and fifth elements: Sunday, Wednesday, Thursday Red, Green, Blue Reverse first, fourth, and fifth elements: Saturday, Wednesday, Tuesday Purple, Yellow, Orange
F#
//Iterators. Nigel Galloway: Januuary 30th., 2022
let N,G=[|"Sunday"; "Monday"; "Tuesday"; "Wednesday"; "Thursday"; "Friday"; "Saturday"|],["Red"; "Orange"; "Yellow"; "Green"; "Blue"; "Purple"]
N|>Array.iter(printf "%s "); printfn ""
N|>Seq.iter(printf "%s "); printfn ""
G|>List.iter(printf "%s "); printfn ""
G|>Seq.iter(printf "%s "); printfn ""
let rec advance(n:System.Collections.IEnumerator)=function 0->() |g->n.MoveNext(); advance n (g-1)
let next(n:System.Collections.IEnumerator)=n.MoveNext(); n.Current
let X=(N|>Seq.ofArray).GetEnumerator() in printfn $"{next X} {(advance X 2; next X)} {next X}"
let X=(G|>Seq.ofList).GetEnumerator() in printfn $"{next X} {(advance X 2; next X)} {next X}"
let X=(N|>Array.rev|>Seq.ofArray).GetEnumerator() in printfn $"{next X} {(advance X 3; next X)} {next X}"
let X=(G|>List.rev|>Seq.ofList).GetEnumerator() in printfn $"{next X} {(advance X 3; next X)} {next X}"
- Output:
Sunday Monday Tuesday Wednesday Thursday Friday Saturday Sunday Monday Tuesday Wednesday Thursday Friday Saturday Red Orange Yellow Green Blue Purple Red Orange Yellow Green Blue Purple Sunday Wednesday Thursday Red Green Blue Saturday Tuesday Monday Purple Orange Red
FreeBASIC
Dim As Integer n, m
Dim As String list(1 To 2, 1 To 7) = {_
{"Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday"}, _
{"Red","Orange","Yellow","Green","Blue","Purple"}}
Dim As Integer ind(1 To 3) = {1,4,5}
Print "All elements:"
For n = 1 To Ubound(list)
For m = 1 To Ubound(list, 2)
Print list(n, m); " ";
Next m
Print
Next n
Print !"\nFirst, fourth, and fifth elements:"
For n = 1 To Ubound(list)
For m = 1 To Ubound(ind)
Print list(n, ind(m)); " ";
Next m
Print
Next n
Print !"\nReverse first, fourth, and fifth elements:"
For m = 1 To Ubound(ind)
Print list(1, Ubound(list,2)+1-ind(m)); " ";
Next m
Print
For m = 1 To Ubound(ind)
Print list(2, Ubound(list,2)-ind(m)); " ";
Next m
Sleep
- Output:
Same as C++ input, Julia, Phix or Wren.
J
J's operations are designed to be applied to the data structure as a whole, and this explicitly includes mapping between representations. Also, in J, all data is array-like, and type is data. And this necessarily includes linked lists (though we can introduce arbitrarily complex mechanisms to obfuscate a linked list structure).
Still, one approach here might be:
dow=: ;:'monday tuesday wednesday thursday friday saturday sunday'
col=: (,<)/;:'red orange yellow green blue purple'
This gives us:
dow
┌──────┬───────┬─────────┬────────┬──────┬────────┬──────┐
│monday│tuesday│wednesday│thursday│friday│saturday│sunday│
└──────┴───────┴─────────┴────────┴──────┴────────┴──────┘
col
┌───┬─────────────────────────────────────────┐
│red│┌──────┬────────────────────────────────┐│
│ ││orange│┌──────┬───────────────────────┐││
│ ││ ││yellow│┌─────┬───────────────┐│││
│ ││ ││ ││green│┌────┬────────┐││││
│ ││ ││ ││ ││blue│┌──────┐│││││
│ ││ ││ ││ ││ ││purple││││││
│ ││ ││ ││ ││ │└──────┘│││││
│ ││ ││ ││ │└────┴────────┘││││
│ ││ ││ │└─────┴───────────────┘│││
│ ││ │└──────┴───────────────────────┘││
│ │└──────┴────────────────────────────────┘│
└───┴─────────────────────────────────────────┘
Here, the implementation's array indexing would see the linked list representation as a two element array. To index arbitrary elements from the linked list, we might map back from the linked list representation to a flat array representation, perhaps using <S:0 (which is a no-op on our array of days of week).
echo ;:inv <S:0 dow
monday tuesday wednesday thursday friday saturday sunday
echo ;:inv <S:0 col
red orange yellow green blue purple
echo ;:inv 0 3 4 {<S:0 dow
monday thursday friday
echo ;:inv 0 3 4 {<S:0 col
red green blue
echo ;:inv _1 _3 _4 {<S:0 dow
sunday friday thursday
echo ;:inv _1 _3 _4 {<S:0 col
purple green yellow
The downside of this approach is that the programmer must understand the data (to know to map all relevant list structures to the desired form). For example, we might instead say that a linked list is not merely an unbalanced binary tree, but must always have its data elements in the left node. That would give us this implementation for col:
col=: '' ]F..(,<) ;:'red orange yellow green blue purple'
col
┌──────┬───────────────────────────────────────┐
│purple│┌────┬────────────────────────────────┐│
│ ││blue│┌─────┬────────────────────────┐││
│ ││ ││green│┌──────┬───────────────┐│││
│ ││ ││ ││yellow│┌──────┬──────┐││││
│ ││ ││ ││ ││orange│┌───┬┐│││││
│ ││ ││ ││ ││ ││red│││││││
│ ││ ││ ││ ││ │└───┴┘│││││
│ ││ ││ ││ │└──────┴──────┘││││
│ ││ ││ │└──────┴───────────────┘│││
│ ││ │└─────┴────────────────────────┘││
│ │└────┴────────────────────────────────┘│
└──────┴───────────────────────────────────────┘
This creates an issue that a single element nested list looks very much like a flat array. To prevent that from being a problem, we include an empty element at the end of our flat array:
dow=: a:,~;:'monday tuesday wednesday thursday friday saturday sunday'
dow
┌──────┬───────┬─────────┬────────┬──────┬────────┬──────┬┐
│monday│tuesday│wednesday│thursday│friday│saturday│sunday││
└──────┴───────┴─────────┴────────┴──────┴────────┴──────┴┘
Now everything is the same as before, except that we need to explicitly ignore the empty trailing element:
echo ;:inv _2 _4 _5 {<S:0 dow
sunday friday thursday
echo ;:inv _2 _4 _5 {<S:0 col
red yellow green
That said, we now also have the opportunity to implement a different kind of normalization routine, which takes advantage of the difference in representation (if we had a need for that...).
However, given the intrinsic value of comprehension when programming, a requirement for comprehension (and, thus, documentation) is frequently a worthwhile price. (There's also an execution cost issue, which can be especially significant in contexts where comprehension is difficult.)
That said, we could implement other approaches which are more similar to some of the other approaches here. These tend to be bulky and inefficient, but some people like that kind of thing. (Some insist on that kind of thing.)
For example:
nextItem=: {{ (x+1) -.#y }}
nextLink=: {{ (1;x) #~ (L.y) > #x }}
makeIterator=: {{ x;y;0 }}
iterate=: {{'`next val more'=. ops['ops list position'=. y
(}:y),<position next list
}}
value=: {{'`next val more'=. ops['ops list position'=. y
position val list
}}
more=: {{'`next val more'=. ops['ops list position'=. y
more position
}}
With this approach, one of the task examples could look like this:
printAll=: {{
while. more y do.
echo value y
y=. iterate y
end.EMPTY
}}
DOW=: nextItem`{::`# makeIterator ;:'monday tuesday wednesday thursday friday saturday sunday'
COL=: nextLink`{::`# makeIterator (,<)/;:'red orange yellow green blue purple'
printAll DOW
monday
tuesday
wednesday
thursday
friday
saturday
sunday
printAll COL
red
orange
yellow
green
blue
purple
value iterate^:0 DOW
monday
value iterate^:3 DOW
thursday
etc.
(Except that this approach does not support negative indexing, so indexing from the end of a list would, for the general case, require either extending the system with explicit support for a length operation or iterating once over the list to determine the list length.)
Julia
Julia has a iteration interface. Any Julia type which implements the `iterate` function is considered an iterable. In base Julia, this includes any array type or collection, including any subclass of AbstractRange, UnitRange, Tuple, Number, AbstractArray, BitSet, IdDict, Dict, WeakKeyDict, EachLine, AbstractString, Set, Pair, and NamedTuple. In particular, Julia has an extensive set of functions which act on lists and vectors. Julia's Iterators can implement the C++ example:
using DataStructures
function PrintContainer(iterator)
iter = Iterators.Stateful(iterator)
foreach(x -> print(x, ", "), Iterators.take(iter, length(iter) -1))
foreach(println, Iterators.take(iter, 1))
end
function FirstFourthFifth(iterator)
iter = Iterators.Stateful(iterator)
foreach(x -> print(x, ", "), Iterators.take(iter, 1))
popfirst!(iter); popfirst!(iter)
foreach(x -> print(x, ", "), Iterators.take(iter, 1))
foreach(println, Iterators.take(iter, 1))
end
const days = ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"]
const colors = list("Red", "Orange", "Yellow", "Green", "Blue", "Purple") # this is a linked list
println("All elements:")
PrintContainer(days)
PrintContainer(colors)
println("\nFirst, fourth, and fifth elements:")
FirstFourthFifth(days)
FirstFourthFifth(colors)
println("\nReverse first, fourth, and fifth elements:")
FirstFourthFifth(reverse(days))
FirstFourthFifth(reverse(colors))
- Output:
All elements: Sunday, Monday, Tuesday, Wednesday, Thursday, Friday, Saturday Red, Orange, Yellow, Green, Blue, Purple First, fourth, and fifth elements: Sunday, Wednesday, Thursday Red, Green, Blue Reverse first, fourth, and fifth elements: Saturday, Wednesday, Tuesday Purple, Yellow, Orange
Phix
Phix does not have iterators or for that matter design patterns. Since there are only
five builtin data types it is not an issue for a routine to "know" what it is doing.
Something along the lines of Same_fringe#Phix could perhaps also be used to implement custom iterators.
with javascript_semantics procedure print_all(object s) if integer(s) then -- (a dictionary) s = apply(true,getd,{getd_all_keys(s),s}) end if printf(1,"%s\n",join(s)) end procedure procedure printFirstFourthFifth(object s, integer d=+1) if integer(s) then -- (a dictionary) s = apply(true,getd,{getd_all_keys(s),s}) end if printf(1,"%s\n",join(extract(s,sq_mul({1,4,5},d)))) end procedure sequence days = {"Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"} integer colors = new_dict({{2,"Red"}, {2.5,"Orange"}, {3,"Yellow"}, {"a","Green"}, {"b","Blue"}, {{#CD},"Purple"}}) printf(1,"All elements:\n") print_all(days) print_all(colors) printf(1,"\nFirst, fourth, and fifth elements:\n") printFirstFourthFifth(days) printFirstFourthFifth(colors) printf(1,"\nReverse first, fourth, and fifth elements:\n") printFirstFourthFifth(days,-1) printFirstFourthFifth(colors,-1)
Originally I used keys of 1..6 on the colours dictionary, but that looked suspicious. Note that the keys here are a mix of int/flt/string/seq, but still carefully "in order".
- Output:
All elements: Sunday Monday Tuesday Wednesday Thursday Friday Saturday Red Orange Yellow Green Blue Purple First, fourth, and fifth elements: Sunday Wednesday Thursday Red Green Blue Reverse first, fourth, and fifth elements: Saturday Wednesday Tuesday Purple Yellow Orange
Python
Python's built-in containers (list, dict, collections.deque, etc.) are iterable. When an iterable object is used in a for
loop, a new iterator is created automatically. Alternatively, the built-in iter()
function can be used to obtain an iterator for an iterable, allowing us to single step through it's members using next()
. When an iterator has been exhausted, calls to next()
will raise a StopIteration
exception.
We can create our own iterators by implementing the iterator protocol. The iterator protocol requires us to implement an __iter__
method and a __next__
method, as demonstrated by the MyIterable
and MyIterator
classes below.
"""Iterables and iterators. Requires Python >= 3.6 for type hints."""
from collections import deque
from typing import Iterable
from typing import Iterator
from typing import Reversible
# array-like
days = [
"Monday",
"Tuesday",
"Wednesday",
"Thursday",
"Friday",
"Saturday",
"Sunday",
]
# deque is implemented as a doubly linked list
colors = deque(
[
"red",
"yellow",
"pink",
"green",
"purple",
"orange",
"blue",
]
)
class MyIterable:
class MyIterator:
def __init__(self) -> None:
self._day = -1
def __iter__(self):
return self
def __next__(self):
if self._day >= 6:
raise StopIteration
self._day += 1
return days[self._day]
class MyReversedIterator:
def __init__(self) -> None:
self._day = 7
def __iter__(self):
return self
def __next__(self):
if self._day <= 0:
raise StopIteration
self._day -= 1
return days[self._day]
def __iter__(self):
return self.MyIterator()
def __reversed__(self):
return self.MyReversedIterator()
def print_elements(container: Iterable[object]) -> None:
for element in container:
print(element, end=" ")
print("") # for trailing newline
def _drop(it: Iterator[object], n: int) -> None:
"""Helper function to advance the iterator at most `n` times."""
try:
for _ in range(n):
next(it)
except StopIteration:
pass
def print_first_fourth_fifth(container: Iterable[object]) -> None:
# Get an iterator from the iterable
it = iter(container)
print(next(it), end=" ")
_drop(it, 2)
print(next(it), end=" ")
print(next(it))
def print_reversed_first_fourth_fifth(container: Reversible[object]) -> None:
# Reverse iterator
it = reversed(container)
print(next(it), end=" ")
_drop(it, 2)
print(next(it), end=" ")
print(next(it))
def main() -> None:
my_iterable = MyIterable()
print("All elements:")
print_elements(days)
print_elements(colors)
print_elements(my_iterable)
print("\nFirst, fourth, fifth:")
print_first_fourth_fifth(days)
print_first_fourth_fifth(colors)
print_first_fourth_fifth(my_iterable)
print("\nLast, fourth to last, fifth to last:")
print_reversed_first_fourth_fifth(days)
print_reversed_first_fourth_fifth(colors)
print_reversed_first_fourth_fifth(my_iterable)
if __name__ == "__main__":
main()
- Output:
All elements: Monday Tuesday Wednesday Thursday Friday Saturday Sunday red yellow pink green purple orange blue Monday Tuesday Wednesday Thursday Friday Saturday Sunday First, fourth, fifth: Monday Thursday Friday red green purple Monday Thursday Friday Last, fourth to last, fifth to last: Sunday Thursday Wednesday blue green pink Sunday Thursday Wednesday
Raku
Raku has iterators, but is rare for casual users to ever explicitly use them. Operators and functions that are designed to work on Iterable objects generally have the iteration semantics built in; so don't need an iterator to be explicitly called. It is far, far more common to use object slices to do the task example operations.
Rakus iterators are one direction only (not reversible), since they are designed to be able to work with infinite streams. It is difficult to reverse a stream that has no end. If the object / collection is finite, it may be reversed, but that is a separate operation from iteration.
Once an iteration has been reified, it is discarded unless explicitly cached. This allows effortless iteration through multi-gigabyte sized data objects and streams without filling up main memory.
The following example iterates though a hash of Positional Iterable objects and demonstrates both using explicit iterators, and object slice operations on each; then has a semi contrived example of where directly using iterators may be actually useful in Raku; collating unique ascending values from several infinite sequence generators.
my %positional-iterable-types =
array => [<Sunday Monday Tuesday Wednesday Thursday Friday Saturday>],
list => <Red Orange Yellow Green Blue Purple>,
range => 'Rako' .. 'Raky',
sequence => (1.25, 1.5, * × * … * > 50),
;
sub first-fourth-fifth ($iterable) {
my $iterator = $iterable.iterator;
gather {
take $iterator.pull-one;
$iterator.skip-one xx 2;
take $iterator.pull-one;
take $iterator.pull-one;
}
}
say "Note: here we are iterating over the %positional-iterable-types hash, but
the order we get elements out is not the same as the order they were inserted.
Hashes are not guaranteed to be in any specific order, in fact, they are
guaranteed to _not_ be in any specific order.";
for %positional-iterable-types.values {
say "\nType " ~ .^name ~ ', contents: ' ~ $_ ~
"\nUsing iterators : first, fourth and fifth from start: " ~ first-fourth-fifth($_) ~ ', and from end: ' ~ first-fourth-fifth(.reverse) ~
"\nUsing object slices: first, fourth and fifth from start: " ~ .[0, 3, 4] ~ ', and from end: ' ~ .[*-1, *-4, *-5] ~ "\n";
};
say "\nWhere iterators really shine; when you are collating the values from several infinite generators.";
my @i = (1, * × 2 … *).iterator, (1, * × 3 … *).iterator, (1, * × 5 … *).iterator;
my @v = @i[0].pull-one, @i[1].pull-one, @i[2].pull-one;
my @seq = lazy gather loop {
take my $min := @v.min;
for ^@v { @v[$_] = @i[$_].pull-one if @v[$_] == $min };
}
say @seq[^25];
- Output:
Note: here we are iterating over the %positional-iterable-types hash, but the order we get elements out is not the same as the order they were inserted. Hashes are not guaranteed to be in any specific order, in fact, they are guaranteed to _not_ be in any specific order. Type Range, contents: Rako Rakp Rakq Rakr Raks Rakt Raku Rakv Rakw Rakx Raky Using iterators : first, fourth and fifth from start: Rako Rakr Raks, and from end: Raky Rakv Raku Using object slices: first, fourth and fifth from start: Rako Rakr Raks, and from end: Raky Rakv Raku Type Seq, contents: 1.25 1.5 1.875 2.8125 5.273438 14.831543 78.2132149 Using iterators : first, fourth and fifth from start: 1.25 2.8125 5.273438, and from end: 78.2132149 2.8125 1.875 Using object slices: first, fourth and fifth from start: 1.25 2.8125 5.273438, and from end: 78.2132149 2.8125 1.875 Type Array, contents: Sunday Monday Tuesday Wednesday Thursday Friday Saturday Using iterators : first, fourth and fifth from start: Sunday Wednesday Thursday, and from end: Saturday Wednesday Tuesday Using object slices: first, fourth and fifth from start: Sunday Wednesday Thursday, and from end: Saturday Wednesday Tuesday Type List, contents: Red Orange Yellow Green Blue Purple Using iterators : first, fourth and fifth from start: Red Green Blue, and from end: Purple Yellow Orange Using object slices: first, fourth and fifth from start: Red Green Blue, and from end: Purple Yellow Orange Where iterators really shine; when you are collating the values from several infinite generators. (1 2 3 4 5 8 9 16 25 27 32 64 81 125 128 243 256 512 625 729 1024 2048 2187 3125 4096)
Ring
list = [["Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday"],
["Red","Orange","Yellow","Green","Blue","Purple"]]
ind = [1,4,5]
revInd = reverse(ind)
see "working..." +nl
see "All elements:" + nl
for n = 1 to len(list)
for m = 1 to len(list[n])
see list[n][m] + " "
next
see nl
next
see nl + "First, fourth, and fifth elements:" + nl
for n = 1 to len(list)
for m = 1 to len(ind)
see list[n][m] + " "
next
see nl
next
see nl +"Reverse first, fourth, and fifth elements:" + nl
for n = 1 to len(list)
for m = 1 to len(revInd)
see list[n][m] + " "
next
see nl
next
see "done..." +nl
- Output:
All elements: Sunday Monday Tuesday Wednesday Thursday Friday Saturday Red Orange Yellow Green Blue Purple First, fourth, and fifth elements: Sunday Monday Tuesday Red Orange Yellow Reverse first, fourth, and fifth elements: Sunday Monday Tuesday Red Orange Yellow
Wren
In Wren an iterable object is a sequence whose class implements the iterate and iteratorValue methods. These methods enable one to walk through the sequence and look up the value of the each element.
Iterable objects, which include the built-in classes: List, Range and String, generally inherit from the Sequence class which provides a number of useful methods including: map, where and reduce.
Wren has no built-in linked list class but the Wren-llist module provides singly and doubly-linked implementations of them. Nor does it have a built-in way to iterate through a sequence in reverse though it is possible to write one. Here, we simply reverse the sequence first to do this.
The iterator protocol methods are not usually called directly as Wren's 'for' statement (and the Sequence methods) call them automatically under the hood. However, in the spirit of this task, they are called directly.
import "./llist" for DLinkedList
// Use iterators to print all elements of the sequence.
var printAll = Fn.new { |seq|
var iter = null
while (iter = seq.iterate(iter)) System.write("%(seq.iteratorValue(iter)) ")
System.print()
}
// Use iterators to print just the first, fourth and fifth elements of the sequence.
var printFirstFourthFifth = Fn.new { |seq|
var iter = null
iter = seq.iterate(iter)
System.write("%(seq.iteratorValue(iter)) ") // first
for (i in 1..3) iter = seq.iterate(iter)
System.write("%(seq.iteratorValue(iter)) ") // fourth
iter = seq.iterate(iter)
System.print(seq.iteratorValue(iter)) // fifth
}
// built in list (elements stored contiguously)
var days = ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"]
// custom doubly linked list
var colors = DLinkedList.new(["Red", "Orange", "Yellow", "Green", "Blue", "Purple"])
System.print("All elements:")
printAll.call(days)
printAll.call(colors)
System.print("\nFirst, fourth, and fifth elements:")
printFirstFourthFifth.call(days)
printFirstFourthFifth.call(colors)
System.print("\nReverse first, fourth, and fifth elements:")
printFirstFourthFifth.call(days[-1..0])
printFirstFourthFifth.call(colors.reversed)
- Output:
All elements: Sunday Monday Tuesday Wednesday Thursday Friday Saturday Red Orange Yellow Green Blue Purple First, fourth, and fifth elements: Sunday Wednesday Thursday Red Green Blue Reverse first, fourth, and fifth elements: Saturday Wednesday Tuesday Purple Yellow Orange
XPL0
XPL0 doesn't have iterators as intended here. It has no built-in linked lists, thus an array is used instead. This translation is about as close as XPL0 can come to meeting the requirements of the task.
\\ Use iterators to print all of the elements of any container that supports
\\ iterators. It print elements starting at 'start' up to, but not
\\ including, 'sentinel'.
proc PrintContainer(Start, Sentinel);
int Start, Sentinel, It;
[It:= 0;
while Start(It) # Sentinel do
[Text(0, Start(It)); Text(0, " ");
It:= It+1;
];
Text(0, "^m^j");
];
\\ Use an iterator to print the first, fourth, and fifth elements
proc FirstFourthFifth(Start, Dir);
int Start, Dir, It;
[It:= 0;
Text(0, Start(It));
It:= It + 3*Dir;
Text(0, ", "); Text(0, Start(It));
It:= It + 1*Dir;
Text(0, ", "); Text(0, Start(It));
Text(0, "^m^j");
];
\\ Create two different kinds of containers of strings
int Days, Colors;
[Days:= ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday",
"Friday", "Saturday", 0];
Colors:= ["Red", "Orange", "Yellow", "Green", "Blue", "Purple", 0];
Text(0, "All elements:^m^j");
PrintContainer(Days, 0);
PrintContainer(Colors, 0);
Text(0, "^m^jFirst, fourth, and fifth elements:^m^j");
FirstFourthFifth(Days, +1);
FirstFourthFifth(Colors, +1);
Text(0, "^m^jReverse first, fourth, and fifth elements:^m^j");
FirstFourthFifth(@Days(7-1), -1);
FirstFourthFifth(@Colors(6-1), -1);
]
- Output:
All elements: Sunday Monday Tuesday Wednesday Thursday Friday Saturday Red Orange Yellow Green Blue Purple First, fourth, and fifth elements: Sunday, Wednesday, Thursday Red, Green, Blue Reverse first, fourth, and fifth elements: Saturday, Wednesday, Tuesday Purple, Yellow, Orange