Why Is My Swift Loop Failing with Error "Can't Form Range with End < Start"

Swift fatal error: Can't form Range with end start

for in (0...row-1).reverse()

Swift can't read row-1...0

Can't form Range with end start

Your for has two problems:

  1. If slashList.count is 0 (because slashList is empty), it would try to count from 1 to 0 adding 1 (which results in an infinite loop), that's why the compiler gives you the error start > end.
  2. if slashList.count is greater than 0 (slashList is not empty), it would use an index which is out of bounds, because you count from 1 to slashList.count, while the indexes go from 0 to slashList.count - 1

to check all indexes it should be:

for i in 0 ..< slashList.count { 
// your code
}

to ignore the first element (index 0) do:

for i in 1 ..< slashList.count {
// your code
}

for your special case, it would seem better to me to do something like:

for element in slashList {    
if !quotaList.contains(element+1)
{
slashList.removeObject(element)
}
}

You can use removeObject from this answer. If, for some reason, you also need the index, do:

for (index, element) in slashList.enumerate() {
// your code
}

Can't form Range with end start Check range before doing for loop?

If you just want to iterate over a collection, then use the for <element> in <collection> syntax.

for element in arr {
// do something with element
}

If you also need access to the index of the element at each iteration, you can use enumerate(). Because indices are zero based, the index will have the range 0..<arr.count.

for (index, element) in arr.enumerate() {

// do something with index & element

// if you need the position of the element (1st, 2nd 3rd etc), then do index+1
let position = index+1
}

You can always add one to the index at each iteration in order to access the position (to get a range of 1..<arr.count+1).

If none of these solve your problem, then you can use the range 0..<arr.count to iterate over the indices of your array, or as @vacawama says, you could use the range 1..<arr.count+1 to iterate over the positions.

for index in 0..<arr.count {

// do something with index
}

for position in 1..<arr.count+1 {

// do something with position
}

0..<0 cannot crash for an empty array as 0..<0 is just an empty range, and 1..<arr.count+1 cannot crash for an empty array as 1..<1 is also an empty range.

Also see @vacawama's comment below about using stride for safely doing more custom ranges. For example (Swift 2 syntax):

let startIndex = 4
for i in startIndex.stride(to: arr.count, by: 1) {
// i = 4, 5, 6, 7 .. arr.count-1
}

Swift 3 syntax:

for i in stride(from: 4, to: arr.count, by: 1) {
// i = 4, 5, 6, 7 .. arr.count-1
}

This is where startIndex is the number to start the range at, arr.count is the number that the range will stay below, and 1 is the stride length. If your array has less elements than the given starting index, then the loop will never be entered.

Can't form Range with upperBound lowerBound

You should first parse your date strings, which are UTC time, into date objects using DateFormatter or ISO8601DateFormatter and get the month and day representation from the resulting dates:

extension Formatter {
static let monthDay: DateFormatter = {
let dateFormatter = DateFormatter()
dateFormatter.locale = Locale(identifier: "en_US_POSIX")
dateFormatter.dateFormat = "MM.dd"
return dateFormatter
}()
}

extension Formatter {
static let iso8601: DateFormatter = {
let formatter = DateFormatter()
formatter.calendar = Calendar(identifier: .iso8601)
formatter.locale = Locale(identifier: "en_US_POSIX")
formatter.timeZone = TimeZone(secondsFromGMT: 0)
formatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ss.SSSXXXXX"
return formatter
}()
}

Playground testing:

let dealStatus: [String: Any] = ["dateStart": "2019-08-21T14:54:03.285108Z",
"dateEnd" : "2019-09-20T06:15:03.285108Z"]

if let dateStart = dealStatus["dateStart"] as? String,
let dateEnd = dealStatus["dateEnd"] as? String,
let start = Formatter.iso8601.date(from: dateStart),
let end = Formatter.iso8601.date(from: dateEnd) { // ,
// let catTitle = ordersResponseArray[indexPath.row]["title"] as? String {

let startTime = Formatter.monthDay.string(from: start)
let endTime = Formatter.monthDay.string(from: end)
let startEndDates = "(" + startTime + " - " + endTime + ")"
print(startEndDates) // "(08.21 - 09.20)"
// cell.titleAndDatesLabel.text = catTitle + " " + startEndDates
}

A concise way to not execute a loop now that C-Style for loops are going to be removed from Swift 3?

To do this in a way that works for n < 2, you can use the stride method.

let startIndex = 2
let endIndex = n

for i in stride(from: startIndex, through: endIndex, by: 1) {
memo.append(memo[i-1] + memo[i-2])
}

For- in loop dynamic closed range

[10-x] denotes an array (with the single element 10-x). You'll want "normal"
parentheses:

for z in 1 ... (10 - x) { ... }

or just

for z in 1 ... 10 - x { ... }

because ... has a lower precedences than -.

As you noticed, this does not work for x = 10 because ranges with end < start are not allowed in Swift.

To execute a loop n times you better use the range 0 ..< n with the range operator that omits the upper value. This works for n = 0 as well:

for x in 1 ... 10 {
for y in 0 ..< x {
print(" ")
}
for z in 0 ..< 10 - x {
print("*")
}
println()
}


Related Topics



Leave a reply



Submit