获得SequenceType的前n个元素的优雅方式

时间:2015-05-14 17:15:53

标签: swift

是否有一种优雅的方式(想想单行)来获取Swift中SequenceType的前n个元素?

我当然可以编写一个在n个元素之后终止的for循环,但这有点笨重。

另请注意,解决方案应该能够处理无限序列。

4 个答案:

答案 0 :(得分:13)

这不正是mySequence.prefix(numberOfElements)的作用吗?

答案 1 :(得分:2)

在Swift 2中,您可以将其创建为扩展名:

extension SequenceType {
    func take(n: Int) -> [Generator.Element] {
        var result: [Generator.Element] = []
        var g = self.generate()
        for _ in 1...n {
            if let next = g.next() {
                result.append(next)
            } else {
                break
            }
        }
        return result
    }
}

在Swift 1中,它必须写成函数:

func take<Seq: SequenceType>(n: Int, xs: Seq) -> [Seq.Generator.Element] {
    var result: [Seq.Generator.Element] = []
    var g = xs.generate()
    for _ in 1...n {
        if let next = g.next() {
            result.append(next)
        } else {
            break
        }
    }
    return result
}

请注意,在任何一种情况下,SequenceType都没有指定如果您多次调用generate()会发生什么。它可以返回相同的值(如Array中所示)。它可以返回不同的值(如在音频数据流中)。它根本不会返回任何东西。因此,take()的来电者可能需要一些关于其对序列影响的特殊知识。

答案 2 :(得分:0)

SequenceType仅支持generate()。也许更“快速”的方法是定义一个Generator给定一个开始和结束索引,一个'基础'生成器将跳过第一个元素,开始返回一些,然后在结束索引后停止。像这样:

struct SubscriptGenerator<Base: GeneratorType> : GeneratorType {
  var nowIndex : Int = 0
  let endIndex : Int
  let begIndex : Int
  var generator : Base

  init (generator: Base, startIndex: Int, endIndex: Int) {
    precondition(startIndex < endIndex, "oops")
    self.generator = generator
    self.endIndex  = endIndex
    self.begIndex  = startIndex
  }

  // MARK - GeneratorType

  typealias Element = Base.Element

  mutating func next() -> Element? {
    while (nowIndex < begIndex) { nowIndex++; generator.next () }
    return nowIndex++ < endIndex ? generator.next() : nil
  }
}

这只是一个例子。可以定义一个convenience init()来获取SequenceType并生成基本生成器。在行动:

75> var gen = [10,20,30,40,50].generate()
76> var sg = SubscriptGenerator(generator: gen, startIndex: 1, endIndex:3) 
sg: SubscriptGenerator<IndexingGenerator<[Int]>> = { ... }
 77> sg.next()
$R2: Int? = 20
 78> sg.next()
$R3: Int? = 30
 79> sg.next()
$R4: Int? = nil

有关示例,请参阅Swift的EnumerateGenerator

注意:可能是Swift功能的Stride关系可以做你想要的。

答案 3 :(得分:-1)

为什么不

var seq = NominalSequence().generate()
var a = (0..<10).map({_ in seq.next()!})

两行,但是功能性的。