通过泛型函数获取数组中的随机元素

时间:2016-02-22 10:35:45

标签: swift

func ramElment<X, T: CollectionType >(list: T) -> X {
    let len = UInt32(list.count)
    let element = arc4random_uniform(len)
    return list[element]
}
它出现了:

错误:无法使用类型为“UInt32)”的参数列表调用类型T.Index.Distance的初始值设定项

let len = UInt32(list.count)

我检查过T.Index.Distance是Int类型。但为什么我不能将类型更改为UInt32

谢谢!

3 个答案:

答案 0 :(得分:3)

Index的{​​{1}}是 CollectionType

ForwardIndexType

这意味着关联的类型public protocol ForwardIndexType : _Incrementable { // ... typealias Distance : _SignedIntegerType = Int // ... } 必须符合Distance,并且(默认情况下)为_SignedIntegerType ,除非声明(或推断) 除此以外。

示例:以下是符合Int的有效类型, 与ForwardIndexType

Distance == Int16

这是一个(用于演示目的,否则相当无用) 类型符合struct MyIndex : ForwardIndexType { var value : Int16 func advancedBy(n: Int16) -> MyIndex { return MyIndex(value: value + n) } func distanceTo(end: MyIndex) -> Int16 { return end.value - value } func successor() -> MyIndex { return MyIndex(value: value + 1) } } func ==(lhs : MyIndex, rhs : MyIndex) -> Bool { return lhs.value == rhs.value } CollectionTypeIndex == MyIndex

Index.Distance == Int16

示例:

struct MyCollectionType : CollectionType {

    var startIndex : MyIndex { return MyIndex(value: 0) }
    var endIndex : MyIndex { return MyIndex(value: 3) }

    subscript(position : MyIndex) -> String {
        return "I am element #\(position.value)"
    }
}

但是我们也可以在不声明的情况下定义前向索引类型 任何let coll = MyCollectionType() for elem in coll { print(elem) } /* I am element #0 I am element #1 I am element #2 */ 类型,并使用默认协议实现 对于DistanceadvancedBy()

distanceTo()

现在struct MyOtherIndex : ForwardIndexType { var value : Int16 func successor() -> MyOtherIndex { return MyOtherIndex(value: value + 1) } } func ==(lhs : MyOtherIndex, rhs : MyOtherIndex) -> Bool { return lhs.value == rhs.value } 因为这是默认类型 如MyOtherIndex.Distance == Int中所定义。

那么这对您的功能有何影响?

你无法想象 对于任意集合,ForwardIndexTypeIndex.Distance

您可以函数限制为集合类型 Int

Index.Distance == Int

但您也可以利用func randomElement<T: CollectionType where T.Index.Distance == Int>(list: T) 可以转换为_SignedIntegerType

IntMax

另请注意,返回类型确定为func randomElement<T: CollectionType>(list: T) -> T.Generator.Element { let len = UInt32(list.count.toIntMax()) let element = IntMax(arc4random_uniform(len)) return list[list.startIndex.advancedBy(T.Index.Distance(element))] } , 并且不能是任意泛型类型T.Generator.Element

此功能适用于任意集合,例如XArrayArraySlice

String.CharacterView

还要使用上面的自定义集合类型:

let array = [1, 1, 2, 3, 5, 8, 13]
let elem1 = randomElement([1, 2, 3])

let slice = array[2 ... 3]
let elem2 = randomElement(slice)

let randomChar = randomElement("abc".characters)

答案 1 :(得分:2)

在问题的标题中,您谈到了Array。但是在您的代码中,您将输入参数声明为CollectionType

如果你真的想收到一个通用数组参数,那么这就是代码

func randomElement<T>(list: [T]) -> T {
    let len = UInt32(list.count)
    let random = Int(arc4random_uniform(len))
    return list[random]
}

enter image description here

答案 2 :(得分:0)

这是你想要的最简单的例子。

extension CollectionType where Index.Distance == Int {
    func randomElement() -> Self.Generator.Element {
        let randomIndex = Int(arc4random_uniform(UInt32(count)))
        return self[startIndex.advancedBy(randomIndex)]
    }
}