将单个整数值视为Swift中的范围

时间:2017-08-10 17:53:21

标签: swift casting integer range nsrange

我需要验证字符串的长度。字符数的允许值为:

  • 6 - 9个字符
  • 12个字符
  • 15个字符

具有不同字符数的所有字符串都无效。因此,我想创建一个Swift函数,它接受许多范围并计算字符串:

extension String {

    func evaluateLength(validCharacterCounts: Range<Int>...) -> Bool {
        // Implementation
    }

}

现在我可以为单个Int范围调用该函数:

"Live long and prosper".evaluateLength(validCharacterCounts: 6..<10)

和多个Int范围:

"Live long and prosper".evaluateLength(validCharacterCounts: 6..<10, 15..<20)

但我不能用单个孤立的整数值调用该函数:

"Live long and prosper".evaluateLength(validCharacterCounts: 6..<10, 12, 15)

因为1215的输入为Int而不是Range<Int>

  

Swift编译错误:无法转换类型&#39; Int&#39;预期参数类型&#39;范围&#39;

有没有办法在Swift中将单个整数视为Range,比如将其自动投放到Range<Int>

(毕竟5相当于5..<6,所以在数学上说5也是一个范围。)

2 个答案:

答案 0 :(得分:0)

我想出了3个解决方案,但我不会像方法接受IntRange<Int>那样令人满意,但我们走了吗?

1 - 你有类型安全但必须使用一些解决方法:

extension String {
    func evaluateLength(validCharacterCounts: [Range<Int>]? = nil) -> Bool {
        if let validCharCounts = validCharacterCounts {
            for validCharCount in validCharCounts {
                if validCharCount.contains(characters.count) {
                    return true
                }
            }
        }

        return false
    }
}

extension Int {
    var asRange: Range<Int> {
        return self..<self+1 as Range<Int>
    }
}

"Hello, playground".evaluateLength(validCharacterCounts: [17.asRange, 1, 25, 1..<45]) // true

2 - 您没有类型安全:

extension String {
    func evaluateLength(validCharacterCounts: [Any]? = nil) -> Bool {
        if let validCharCounts = validCharacterCounts {
            for validCharCount in validCharCounts {
                if let range = validCharCount as? Range<Int> {
                    if range.contains(characters.count) {
                        return true
                    }
                } else if let range = validCharCount as? CountableRange<Int> {
                    if range.contains(characters.count) {
                        return true
                    }
                } else if let range = validCharCount as? CountableClosedRange<Int> {
                    if range.contains(characters.count) {
                        return true
                    }
                } else if let int = validCharCount as? Int {
                    if int.asRange.contains(characters.count) {
                        return true
                    }
                } else {
                    fatalError("Unexpected type: \(type(of: validCharCount))")
                }
            }
        }

        return false
    }
}

extension Int {
    var asRange: Range<Int> {
        return self..<self+1 as Range<Int>
    }
}

"Hello, playground".evaluateLength(validCharacterCounts: [12, 1, 4, 6, 14...18]) // true

3 - 迄今为止最好的,但仍然不是完美的解决方案:

extension String {
    func evaluateLength(validCharacterCounts: [Int]? = nil) -> Bool {
        guard let validCharCounts = validCharacterCounts else {
            return false
        }

        return validCharCounts.contains(characters.count)

    }
}

"Hello, playground".evaluateLength(validCharacterCounts: [12, 1, 4, 6] + Array(14...18)) // true

答案 1 :(得分:0)

我就是这样做的。我只是创建一个带有相关初始化程序的Set扩展,而不是处理范围语义。

extension Set where Element == Int {
    init(with elements: [Int] = [], and ranges: Range<Int>...) {
        var allElements = [elements]
        ranges.forEach {
            allElements.append(Array($0.lowerBound..<$0.upperBound))
        }
        self.init(allElements.joined())
    }
}

let newSet = Set(with: [1, 3, 328], and: 6..<10, 15..<20)
newSet.contains(3)  //true
newSet.contains(4)  //false
newSet.contains(16) //true

这允许您只传递单个值,仅传递范围或两者。唯一需要注意的是将它们分开的命名参数。

Set语义也意味着你可以根据需要创建静态常量,并且也应该明显更快。