Help with Closed Ranges

I was asked to tackle the following challenge in a lesson:

Write a while loop that prints the even numbers from 1 to 1000 (inclusive). While you could just do this with a for loop, try using a while loop.

For example, if we were printing even numbers from 1 to 10, we'd get the following output.

2
4
6
8
10

I came up with the following solution, which resulted in the desired output:

var evenNumberContainer = 0

while evenNumberContainer <= 998 {
evenNumberContainer = evenNumberContainer + 2
print(evenNumberContainer)
}

However, I'm wondering if what was preferred was to use an actual range to accomplish the requested output. How would I go about accomplishing the same thing but using a range, instead? I tried it with a range but inputting the following program:

var numericRange = 1...1000

while numericRange <= 1000 {
    for eachItem in numericRange {
        if eachItem % 2 == 0 {
            print(eachItem)
            }
    }
}

But by doing so, I get the following error message:

Binary operator '<=' cannot be applied to operands of type 'ClosedRange' and 'Int'

Could someone please explain to me as well why I keep getting that error message and what the error message actually means? It seems like ClosedRange is a type in itself? Thank you.

EDIT: I just tried the following code which worked:

var numericRange = 1...1000

while numericRange == 1...998 {
    for eachItem in numericRange {
        if eachItem % 2 == 0 {
            print(eachItem)
            }
    }
}

But it doesn't address my question above as to the error message that I received. Please help! Thank you.

There are many ways you could solve this with a while loop. One way is to transform a for version into an equivalent while version the same way the Swift compiler does. You can find the details of the transformation in the IteratorProtocol documentation, which I quote here:

Whenever you use a for-in loop with an array, set, or any other collection or sequence, you’re using that type’s iterator. Swift uses a sequence’s or collection’s iterator internally to enable the for-in loop language construct.

Using a sequence’s iterator directly gives you access to the same elements in the same order as iterating over that sequence using a for - in loop. For example, you might typically use a for - in loop to print each of the elements in an array.

let animals = ["Antelope", "Butterfly", "Camel", "Dolphin"]
for animal in animals {
    print(animal)
}
// Prints "Antelope"
// Prints "Butterfly"
// Prints "Camel"
// Prints "Dolphin"

Behind the scenes, Swift uses the animals array’s iterator to loop over the contents of the array.

var animalIterator = animals.makeIterator()
while let animal = animalIterator.next() {
    print(animal)
}
// Prints "Antelope"
// Prints "Butterfly"
// Prints "Camel"
// Prints "Dolphin"

The call to animals.makeIterator() returns an instance of the array’s iterator. Next, the while loop calls the iterator’s next() method repeatedly, binding each element that is returned to animal and exiting when the next() method returns nil.

So, for your problem, here's a for version:

for i in 1...1000 {
    if i.isMultiple(of: 2) {
        print(i)
    }
}

I suggest that you try to apply the transformation described above to this for loop. You can see my solution by clicking the triangle below.

My solution
var iterator = (1...1000).makeIterator()
while let i = iterator.next() {
    if i.isMultiple(of: 2) {
        print(i)
    }
}

ClosedRange is a generic type. Consider your declaration of numericRange:

var numericRange = 1...1000

If you option-click numericRange in Xcode, or add print(type(of: numericRange)) to your program, you will see that the type of numericRange is ClosedRange<Int>. There is no definition of the <= operator that takes a ClosedRange<Int> on the left side and an Int on the right side.

1 Like

Thank you, Mayoff this was helpful; I appreciate it.

Better with stride?

let largest = 10        // set this to largest desired result
var iterator = stride(from: 0, through: largest, by: 2).makeIterator()
while let even = iterator.next() {
    print(even)
}