Elegant way to get the first n elements of a SequenceType - swift

Is there an elegant way (think one-liner) to get the first n elements of a SequenceType in Swift?
I could of course write a for-loop that terminates after n elements but that's a little bulky.
Note also that the solution should be able to deal with infinite sequences.

Isn't it exactly what mySequence.prefix(numberOfElements) does?

In Swift 2, you can create this as an extension:
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
}
}
In Swift 1, it would have to written as a function:
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
}
Note that in either case, SequenceType does not specify what happens if you call generate() more than once. It could return the same values (as in an Array). It could return different values (as in an audio data stream). It could return nothing at all. So the caller of take() may need some special knowledge about its impact on the sequence.

SequenceType only supports generate(). Perhaps a more 'Swiftly' approach would be to define a Generator that given a start and end index and a 'base' generator would skip over the first elements, start returning some, and then stop after end index. Like this:
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
}
}
This is only an example. One could define an convenience init() that takes a SequenceType and produces the base generator. In action:
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
See Swift's EnumerateGenerator for an example.
Note: it might be the Stride nexus of Swift functionality does what you want already.

Why not
var seq = NominalSequence().generate()
var a = (0..<10).map({_ in seq.next()!})
?
Two lines, but funtional-ish.

Related

How to solve a problem with using the method of branches and borders?

All words of the ternary language consist of only 3 letters: a, b, and c and all have a strictly specified length N. Words that do not contain two identical subsequences of letters in a row are considered correct. For example, abcacb is the correct word, and ababc is not the correct one, since the ab subsequences go there.
I tried to solve the problem with a complete enumeration of all possible combinations and a function that looked for a repeating sequence. However, this turned out to be the wrong decision. The problem needs to be solved somehow using the branch and bound method. I have absolutely no idea how this problem can be solved by this method. I would be very happy if someone provides examples or explains to me. I have already spent six days to solve this problem and am very tired.
My wrong solution:
import Foundation
func findRepetition(_ p: String) -> [String:Int] {
var repDict: [String:Int] = [:]
var p = p
while p.count != 0 {
for i in 0...p.count-1 {
repDict[String(Array(p)[0..<i]), default: 0] += 1
}
p = String(p.dropFirst())
}
return repDict
}
var correctWords = [String]()
var wrongWords = [String]()
func getRepeats(_ p: String) -> Bool {
let p = p
var a = findRepetition(p)
for i in a {
var substring = String(Array(repeating: i.key, count: 2).joined())
if p.contains(substring) {
wrongWords.append(p)
return false
}
}
correctWords.append(p)
return true
}
var counter = 0
func allLexicographicRecur (_ string: [String.Element], _ data: [String], _ last: Int, _ index: Int){
var length = string.count-1
var data = data
for i in 0...length {
data[index] = String(string[i])
if index == last {
if getRepeats(data.joined()) {
counter += 1
}
}else{
allLexicographicRecur(string, data, last, index+1)
}
}
}
func threeLanguage(_ l: Int) {
var alphabet = "abc"
var data = Array(repeating: "", count: l)
allLexicographicRecur(alphabet.sorted(), data, l-1, 0)
print("The specified word length: \(l), the number of correct words: \(counter)\n")
print("Correct words:\n\(correctWords)\n")
print("Wrong words:\n\(wrongWords)")
}
threeLanguage(3)
Example:
abca is the right word.
abab is wrong (ab).
aaaa is also wrong (a).
abcabc is also incorrect (abc).
If I correctly understood your problem, you need to separate you input string to parts N-length and check parts by your rules. Smth like this
let constant: Int = 3
extension String {
private func components(withLength length: Int) -> [String] {
return stride(from: 0, to: count, by: length).map {
let start = index(startIndex, offsetBy: $0)
let end = index(start, offsetBy: length, limitedBy: endIndex) ?? endIndex
return String(self[start ..< end])
}
}
var numberOfValidWords: Int {
var numberOfIncorrectWords = 0
let length = count - constant
let array = components(withLength: constant)
for component in array {
let computedLength = replacingOccurrences(of: component, with: "").count
if computedLength != length {
print("as is lengths are not equal, this part is met in string several times")
numberOfIncorrectWords += 1
continue
}
}
return array.count - numberOfIncorrectWords
}
}
Hope it will be helpful

Adopting CollectionType (Collection) in Swift

I'm writing a graphics library to display data in a graph. Since most of the projects I do tend to have a large learning component in them, I decided to create a generically typed struct to manage my data set DataSet<T: Plottable> (note here that Plottable is also Comparable).
In trying to conform to MutableCollectionType, I've run across an error. I'd like to use the default implementation of sort(), but the compiler is giving the following error when trying to use the sorting function.
Ambiguous reference to member 'sort()'
Here's a code example:
var data = DataSet<Int>(elements: [1,2,3,4])
data.sort() //Ambiguous reference to member 'sort()'
The compiler suggests two candidates, but will not actually display them to me. Note that the compiler error goes away if I explicitly implement sort() on my struct.
But the bigger question remains for me. What am I not seeing that I expect the default implementation to be providing? Or am I running across a bug in Swift 3 (this rarely is the case... usually I have overlooked something).
Here's the balance of the struct:
struct DataSet<T: Plottable>: MutableCollection, BidirectionalCollection {
typealias Element = T
typealias Iterator = DataSetIterator<T>
typealias Index = Int
/**
The list of elements in the data set. Private.
*/
private var elements: [Element] = []
/**
Initalize the data set with an array of data.
*/
init(elements data: [T] = []) {
self.elements = data
}
//MARK: Sequence Protocol
func makeIterator() -> DataSetIterator<T> {
return DataSetIterator(self)
}
//MARK: Collection Protocol
subscript(_ index:DataSet<T>.Index) -> DataSet<T>.Iterator.Element {
set {
elements[index] = newValue
}
get {
return elements[index]
}
}
subscript(_ inRange:Range<DataSet<T>.Index>) -> DataSet<T> {
set {
elements.replaceSubrange(inRange, with: newValue)
}
get {
return DataSet<T>(elements: Array(elements[inRange]))
}
}
//required index for MutableCollection and BidirectionalCollection
var endIndex: Int {
return elements.count
}
var startIndex: Int {
return 0
}
func index(after i: Int) -> Int {
return i+1
}
func index(before i: Int) -> Int {
return i-1
}
mutating func append(_ newElement: T) {
elements.append(newElement)
}
// /**
// Sorts the elements of the DataSet from lowest value to highest value.
// Commented because I'd like to use the default implementation.
// - note: This is equivalent to calling `sort(by: { $0 < $1 })`
// */
// mutating func sort() {
// self.sort(by: { $0 < $1 })
// }
//
// /**
// Sorts the elements of the DataSet by an abritrary block.
// */
// mutating func sort(by areInIncreasingOrder: #noescape (T, T) -> Bool) {
// self.elements = self.elements.sorted(by: areInIncreasingOrder)
// }
/**
Returns a `DataSet<T>` with the elements sorted by a provided block.
This is the default implementation `sort()` modified to return `DataSet<T>` rather than `Array<T>`.
- returns: A sorted `DataSet<T>` by the provided block.
*/
func sorted(by areInIncreasingOrder: #noescape (T, T) -> Bool) -> DataSet<T> {
return DataSet<T>(elements: self.elements.sorted(by: areInIncreasingOrder))
}
func sorted() -> DataSet<T> {
return self.sorted(by: { $0 < $1 })
}
}
Your DataSet is a BidirectionalCollection. The sort() you're trying to use requires a RandomAccessCollection. The most important thing you need to add is an Indicies typealias.
typealias Indices = Array<Element>.Indices
Here's my version of your type:
protocol Plottable: Comparable {}
extension Int: Plottable {}
struct DataSet<Element: Plottable>: MutableCollection, RandomAccessCollection {
private var elements: [Element] = []
typealias Indices = Array<Element>.Indices
init(elements data: [Element] = []) {
self.elements = data
}
var startIndex: Int {
return elements.startIndex
}
var endIndex: Int {
return elements.endIndex
}
func index(after i: Int) -> Int {
return elements.index(after: i)
}
func index(before i: Int) -> Int {
return elements.index(before: i)
}
subscript(position: Int) -> Element {
get {
return elements[position]
}
set {
elements[position] = newValue
}
}
subscript(bounds: Range<Int>) -> DataSet<Element> {
get {
return DataSet(elements: Array(elements[bounds]))
}
set {
elements[bounds] = ArraySlice(newValue.elements)
}
}
}
var data = DataSet(elements: [4,2,3,1])
data.sort()
print(data.elements) // [1,2,3,4]
You don't actually need an Iterator if you don't want one. Swift will give you Sequence automatically if you implement Collection.

Getting a random element in array by a generic function

func ramElment<X, T: CollectionType >(list: T) -> X {
let len = UInt32(list.count)
let element = arc4random_uniform(len)
return list[element]
}
it pops up:
error: cannot invoke initializer for type UInt32 with an argument list of type '(T.Index.Distance)'
let len = UInt32(list.count)
I have checked the T.Index.Distance is Int type. but why can't i change the type to UInt32?
thanks!
The Index of a CollectionType is
a ForwardIndexType:
public protocol ForwardIndexType : _Incrementable {
// ...
typealias Distance : _SignedIntegerType = Int
// ...
}
This means that the associated type Distance must conform to _SignedIntegerType, and (by default) is Int unless declared (or inferred)
otherwise.
Example: The following is a valid type conforming to ForwardIndexType,
with 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
}
And here is a (for demonstration purposes, otherwise pretty useless)
type conforming to CollectionType with Index == 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)"
}
}
Example:
let coll = MyCollectionType()
for elem in coll {
print(elem)
}
/*
I am element #0
I am element #1
I am element #2
*/
But we can also define a forward index type without declaring
any Distance type, and using the default protocol implementations
for advancedBy() and 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
}
Now MyOtherIndex.Distance == Int because that is the default type
as defined in ForwardIndexType.
So how does this apply to your function?
You cannot assume that
Index.Distance is Int for an arbitrary collection.
You can restrict the function to collection types with
Index.Distance == Int:
func randomElement<T: CollectionType where T.Index.Distance == Int>(list: T)
But you can also utilize that _SignedIntegerType can be converted to and from 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))]
}
Note also that the return type is determined as T.Generator.Element,
and cannot be an arbitrary generic type X.
This function works with arbitrary collections, for example Array, ArraySlice, or 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)
but also with the above custom collection type:
let mc = MyCollectionType()
let r = randomElement(mc)
In the title of your question you talk about Array. But in your code you are declaring the input param as a CollectionType.
If you really want to receive a Generic Array param then this is the code
func randomElement<T>(list: [T]) -> T {
let len = UInt32(list.count)
let random = Int(arc4random_uniform(len))
return list[random]
}
This is the simplest example what you want.
extension CollectionType where Index.Distance == Int {
func randomElement() -> Self.Generator.Element {
let randomIndex = Int(arc4random_uniform(UInt32(count)))
return self[startIndex.advancedBy(randomIndex)]
}
}

Multiple index types in Swift

In Swift (a language I'm still fairly new to), I'm trying to define a class that allows indexing using either an Int or Range<Int>. For example:
var m = Matrix(rows: 10, cols: 10)
var v = m[1, 0..<10]
The two ways I can think of allowing this issue is to either adding an extension to the Range class:
extension Range {
init(_ intValue:Element) {
self.init(start: intValue, end: intValue.successor())
}
}
or to create an enum that allows for either type:
enum IndexType {
case value(Int)
case range(Range<Int>)
init(_ v:Int) {
self = .value(v)
}
init(_ r:Range<Int>) {
self = .range(r)
}
}
However, neither solution works as intended, as I still need to specify the type manually. For example, given the function:
func slice(indices:IndexType...) -> [Double] {
// ...
}
I can't then just do:
slice(1, 3...4, 5)
but instead have to do:
slice(IndexType(1), IndexType(3...4), 5)
Is there a way to accomplish this in Swift? I'm used to c++, which would do type inference automatically, but the same doesn't appear to work with Swift.
One similar question I found was:
Swift Arrays of Multiple Types
However, I really would like to avoid the use of Any as I know the two types it should be.
protocol MatrixIndex {
var Matrix_range: Range<Int> { get }
}
extension Int : MatrixIndex {
var Matrix_range: Range<Int> {
get {
return Range<Int>(start: self, end: self+1)
}
}
}
extension Range : MatrixIndex {
var Matrix_range: Range<Int> {
get {
return Range<Int>(start: self.startIndex as! Int, end: self.endIndex as! Int)
}
}
}
class Matrix {
subscript(row: MatrixIndex, column: MatrixIndex) -> () {
get {
print("getting \(row.Matrix_range) \(column.Matrix_range)")
}
set(newValue) {
print("setting \(row.Matrix_range) \(column.Matrix_range)")
}
}
}

Swift SequenceType not working

I'm trying to implement a SequenceType / GeneratorType example and getting an error that doesn't quite make sense.
Here's the code:
// Here's my GeneratorType - it creates a random-number Generator:
struct RandomNumberGenerator:GeneratorType {
typealias Element = Int
mutating func next() -> Element? {
return Int(arc4random_uniform(100))
}
}
When I call this (in Playgrounds) it works perfectly well:
var randyNum = RandomNumberGenerator()
randyNum.next() // this shows a valid random number in the Gutter
// And calling it from within a println also works:
println("randyNum = \(randyNum.next()!)")
So far so so good.
Next is the SequenceType:
struct RandomNumbersSequence:SequenceType {
typealias Generator = RandomNumberGenerator
var numberOfRandomNumbers:Int
init(maxNum:Int) {
numberOfRandomNumbers = maxNum
}
func generate() -> Generator {
for i in 1...numberOfRandomNumbers {
var randNum = Generator()
randNum.next()
return randNum
}
}
}
That's what's generating an error: 'Type RandomNumberSequence' does not conform to protocol 'SequenceType'. (Xcode is showing this error right on that first line of the declaration struct RandomNumbersSequence:SequenceType statement.)
I actually think the logic of my for loop may be wrong - meaning I won't get the results I actually want - but regardless, in terms of satisfying what the SequenceType Protocol is requiring, I think I got that much right.
So what's causing this error?
This isn’t quite how generators work. Assuming you want to serve up a set number of random numbers, you have the right idea about taking a maximum as a parameter, but you need to store that in the generator, as well, plus some state for where it is up to.
The idea with a generator is that it stores its state, and every time you call next() you return the next element. So if you want to generate a run of up to n numbers, you could do something like the following:
struct RandomNumberGenerator: GeneratorType {
let n: Int
var i = 0
init(count: Int) { self.n = count }
mutating func next() -> Int? {
if i++ < n {
return Int(arc4random_uniform(100))
}
else {
return nil
}
}
}
Note, you don’t need a for loop here. Just each time next() is called, i is incremented, until it reaches the max, then the generator starts returning nil.
The purpose of SequenceType is to serve up fresh generators:
struct RandomNumberSequence: SequenceType {
let n: Int
init(count: Int) { self.n = count }
func generate() -> RandomNumberGenerator {
return RandomNumberGenerator(count: n)
}
}
Given this, you can now use it to generate a sequence of a fixed number of random integers:
let seq = RandomNumberSequence(count: 3)
for x in seq {
// loops 3 times with x being a new random number each time
}
// every time you use seq, you get a new set of 3 numbers
",".join(map(seq,toString)) // prints 3 comma-separated random nums
// but when you create a generator, it gets “used up”
var gen = seq.generate()
println(gen.next()) // prints a random number
println(gen.next()) // prints another random number
println(gen.next()) // prints the third
println(gen.next()) // prints nil
println(gen.next()) // and will keep printing nil
gen = seq.generate()
println(gen.next()) // will print the first of a new set of 3 numbers
Creating these stateful generators is quite a common problem, so the standard library has a helper struct, GeneratorOf, that allows to you skip defining them. It takes a closure that each time it is called should return the next value to generate:
struct RandomNumbersSequence: SequenceType {
let maxNum: Int
init(maxNum: Int) { self.maxNum = maxNum }
func generate() -> GeneratorOf<Int> {
// counter to track how many have been generated
var n = 0
return GeneratorOf {
// the closure “captures” n
if n++ < self.maxNum {
return Int(arc4random_uniform(100))
}
else {
return nil
}
}
}
}
The error message you're seeing:
'Type RandomNumberSequence' does not conform to protocol 'SequenceType'
Always means that your class or struct is missing something that the protocol declares as required.
In this case, we're missing the generate() -> Generator method. "But, it's right there!" you say? Well, it is, but it's not compiling.
func generate() -> Generator {
for i in 1...numberOfRandomNumbers {
var randNum = Generator()
randNum.next()
return randNum
}
}
The problem is, what if you initialize your struct with numberOfRandomNumbers less than or equal to 0? Your loop executes zero times and generate can't return anything.
I'm not sure exactly what logic you're trying to to do in this loop, but we can fix the compilation errors by simply a adding a return statement that will return a Generator:
func generate() -> Generator {
for i in 1...numberOfRandomNumbers {
var randNum = Generator()
randNum.next()
return randNum
}
return Generator()
}
This won't do what you're trying to accomplish. This isn't how generators are supposed to work. But it will fix the generate() -> Generator method and allow your struct to now conform to the protocol.
With Swift 3, you can choose one of the three RandomNumbersSequence implementations in order to solve your problem.
1. Using a struct that conforms to Sequence protocol and a struct that conforms to IteratorProtocol protocol
The following Playground code shows how to implement a RandomNumbersSequence struct that conforms to Sequence and that uses a RandomNumbersIterator struct that conforms to IteratorProtocol protocol:
import Darwin // required for arc4random_uniform
struct RandomNumbersIterator: IteratorProtocol {
let maxNum: Int
var n = 0
init(maxNum: Int) {
self.maxNum = maxNum
}
mutating func next() -> Int? {
n += 1
return n <= self.maxNum ? Int(arc4random_uniform(10)) : nil
}
}
struct RandomNumbersSequence: Sequence {
let maxNum: Int
init(maxNum: Int) {
self.maxNum = maxNum
}
func makeIterator() -> RandomNumbersIterator {
return RandomNumbersIterator(maxNum: maxNum)
}
}
Usage #1:
for value in RandomNumbersSequence(maxNum: 3) {
print(value)
}
/*
may print:
5
7
3
*/
Usage #2:
let randomArray = Array(RandomNumbersSequence(maxNum: 3))
print(randomArray)
/*
may print: [7, 6, 1]
*/
Usage #3:
let randomSequence = RandomNumbersSequence(maxNum: 3)
var randomGenerator = randomSequence.makeIterator()
randomGenerator.next() // may return: 4
randomGenerator.next() // may return: 8
randomGenerator.next() // may return: 3
randomGenerator.next() // will return: nil
2. Using a struct that conforms to Sequence and IteratorProtocol protocols
The following Playground code shows how to implement a RandomNumbersSequence struct that conforms to Sequence and IteratorProtocol protocols:
import Darwin // required for arc4random_uniform
struct RandomNumbersSequence: Sequence, IteratorProtocol {
let maxNum: Int
var n = 0
init(maxNum: Int) {
self.maxNum = maxNum
}
mutating func next() -> Int? {
n += 1
return n <= self.maxNum ? Int(arc4random_uniform(10)) : nil
}
}
Usage #1:
for value in RandomNumbersSequence(maxNum: 3) {
print(value)
}
/*
may print:
5
7
3
*/
Usage #2:
let randomArray = Array(RandomNumbersSequence(maxNum: 3))
print(randomArray)
/*
may print: [7, 6, 1]
*/
Usage #3:
var randomSequence = RandomNumbersSequence(maxNum: 3)
randomSequence.next() // may return: 4
randomSequence.next() // may return: 8
randomSequence.next() // may return: 3
randomSequence.next() // will return: nil
3. Using AnyIterator and a struct that conforms to Sequence
As an alternative to the previous implementation, you can use AnyIterator<T> as the return type of the makeIterator method inside your Sequence protocol conforming struct. The following Playground code shows how to implement it with your RandomNumbersSequence struct:
import Darwin // required for arc4random_uniform
struct RandomNumbersSequence: Sequence {
let maxNum: Int
init(maxNum: Int) {
self.maxNum = maxNum
}
func makeIterator() -> AnyIterator<Int> {
var n = 0
let iterator: AnyIterator<Int> = AnyIterator {
n += 1
return n <= self.maxNum ? Int(arc4random_uniform(10)) : nil
}
return iterator
}
}
Usage #1:
for value in RandomNumbersSequence(maxNum: 3) {
print(value)
}
/*
may print:
5
7
3
*/
Usage #2:
let randomArray = Array(RandomNumbersSequence(maxNum: 3))
print(randomArray)
/*
may print: [7, 6, 1]
*/
Usage #3:
let randomSequence = RandomNumbersSequence(maxNum: 3)
let randomGenerator = randomSequence.makeIterator()
randomGenerator.next() // may return: 4
randomGenerator.next() // may return: 8
randomGenerator.next() // may return: 3
randomGenerator.next() // will return: nil