这就是我所拥有的:
class func truncateTailsOfRange(range: Range<Int>, portion: Double) -> Range<Int> {
let start = range.startIndex + Int(portion * Double(range.count))
let end = range.endIndex - Int(portion * Double(range.count))
return Range(start: start, end: end)
}
我想为IntegerType制作这个通用:
class func truncateTailsOfRange<T: IntegerType>(range: Range<T>, portion: Double) -> Range<T> {
let start = range.startIndex + T(portion * Double(range.count))
let end = range.endIndex - T(portion * Double(range.count))
return Range(start: start, end: end)
}
但我得到的错误是:
无法使用类型(
Double
)的参数列表调用类型T.Distance
的初始值设定项
这可能吗?
答案 0 :(得分:0)
首先,您需要CustomDoubleConvertible
协议。这反映了CustomStringConvertible
。您可以将要转换的所有类型扩展为Double
。与description
类似,返回类型的String
表示。
protocol CustomDoubleConvertible {
var doubleValue : Double { get }
}
extension Int : CustomDoubleConvertible {
var doubleValue : Double { return Double(self) }
}
extension Int16 : CustomDoubleConvertible {
var doubleValue : Double { return Double(self) }
}
如果你将该函数作为Range
本身的扩展,你可以利用它的通用性,它是typealiases
。
extension Range where Element.Distance : CustomDoubleConvertible {
现在您可以计算索引的偏移量,如下所示:
let startOffset = Int(portion * self.count.doubleValue)
let endOffset = Int(portion * self.count.doubleValue)
如果您进一步约束Range
以使其Element
必须为BidirectionalIndexType
,则可以使用successor
和predecessor
。
extension Range where Element.Distance : CustomDoubleConvertible, Element : BidirectionalIndexType {
这使您可以通过迭代偏移量并调用successor
和predecessor
来获得完整功能。
extension Range where Element.Distance : CustomDoubleConvertible, Element : BidirectionalIndexType {
func truncateTailsOfRange(portion: Double) -> Range<Element> {
let startOffset = Int(portion * self.count.doubleValue)
let endOffset = Int(portion * self.count.doubleValue)
var start = self.startIndex
var end = self.endIndex
for _ in 0..<startOffset { start = start.successor() }
for _ in 0..<endOffset { end = end.predecessor() }
return Range(start: start, end: end)
}
}
一些测试:
let rangeA = 1...4 // 1..<5
let rangeB = "a"..."g"
rangeA.truncateTailsOfRange(0.3) // 2..<4
rangeB.truncateTailsOfRange(0.3) // has no member ....
let w : Int16 = 3
let z : Int16 = 9
let rangeC = w...z // 3..<10
rangeC.truncateTailsOfRange(0.4) // 5..<8
答案 1 :(得分:0)
这是一项有趣但学术性的练习。
这是一种效率不高但可以适用于所有范围类型的方法:
func truncateTailsOfRange<T>(var range: Range<T>, portion: Double) -> Range<T>
{
let elementCount = Array(range).count
let truncationCount = Int( portion * Double(elementCount) )
let remainingCount = max(0, elementCount - 2 * truncationCount)
for _ in 0..<truncationCount
{ range.startIndex = range.startIndex.successor() }
range.endIndex = range.startIndex
for _ in 0..<remainingCount
{ range.endIndex = range.endIndex.successor() }
return range
}
这是一个更快的一个:
func truncateTailsOfRange2<T>(var range: Range<T>, portion: Double) -> Range<T>
{
if range.isEmpty {return range}
let elements = Array(range)
let truncationCount = Int( portion * Double(elements.count) )
let remainingCount = max(0, elements.count - 2 * truncationCount)
return elements[truncationCount]..<elements[truncationCount+remainingCount]
}