Advance all elements in a Range in Swift? - swift

If I have a Range, say
let bilbo = ( 1 ... 5 )
And I wanted to advance all elements of it by a number, say 3, is there a way other than
let offset = 3
let baggins = ( bilbo.first! + offset ... bilbo.last! + offset )
Something like
bilbo.advance_by( 3 )
Which I discovered only works for one element in the Range?
I have searched the web and SO and can't find an answer. I'm guessing that there is a Swift-ish way to do this that probably appears in another SO post somewhere that I just don't comprehend how it connects yet. Any help would be appreciated.

let advanceRangeBy : (Range<Int>, Int) -> Range<Int> = { $0.0.first!.advancedBy($0.1) ... $0.0.last!.advancedBy($0.1) }
let bilbo = 1...5
let bagger = advanceRangeBy(bilbo, 3) // 4..<9
You can also make it a generic extension to Range that will work for many (although not all) types of Range:
let bilbo = 1...5
extension Range where Element : BidirectionalIndexType {
func advanceRangeBy(advance: Element.Distance) -> Range<Element> {
return first!.advancedBy(advance) ... last!.advancedBy(advance)
}
}
let baggins = bilbo.advanceRangeBy(3)
For the sake of completeness, I thought I'd add that you can also perform this range advancement/de-advancement operation using a custom binary infix operator
infix operator <> {
associativity left
precedence 140 /* use same precedence as '+', '-' arithmetic */
}
func <> (lhs: Range<Int>, rhs: Int) -> Range<Int>{
var out : Range<Int> = lhs
out.endIndex = lhs.endIndex + rhs
out.startIndex = lhs.startIndex + rhs
return out
}
let bilbo = 1...5
let bagger = bilbo <> 3 // 4..<9
let frodo = bagger <> (-2) // 2..<7

How about a simple extension:
extension Range {
public func advancedBy(n: Element.Distance) -> Range<Element> {
let startIndex = self.startIndex.advancedBy(n)
let endIndex = self.endIndex.advancedBy(n)
return Range(start: startIndex, end: endIndex)
}
}
Update for swift 5:
public extension CountableRange {
func advanced(by n: Bound.Stride) -> Self {
let lowerBound = self.lowerBound.advanced(by: n)
let upperBound = self.upperBound.advanced(by: n)
return .init(uncheckedBounds: (lowerBound, upperBound))
}
static func + (lhs: Self, rhs: Bound.Stride) -> Self {
lhs.advanced(by: rhs)
}
}
Note that CountableRange is just a typealias for Range with conditions:
typealias CountableRange<Bound> = Range<Bound> where Bound : Strideable, Bound.Stride : SignedInteger

Use map:
let bagger = bilbo.map { $0.advancedBy(3) }

Related

How to get list of elements of two sequences using Set.intersection

I'm studying The Swift Programming Language (Swift 4.2)
https://docs.swift.org/swift-book/GuidedTour/GuidedTour.html
Is it possible to write a generic function to return the common elements of any two Sequences using Set.intersection()? I've written the following method (I'm a C# developer just learning, so please excuse bad Swift coding practices), but is it possible to do this without knowing the element type?
func getCommonElements<T: Sequence, U: Sequence>(_ lhs: T, _ rhs: U) -> Array<Any>
where T.Element: Equatable, T.Element == U.Element
{
if let lhsSet = lhs as? Set<String> {
if let rhsSet = rhs as? Set<String> {
return Array(lhsSet.intersection(rhsSet))
}
} else if let lhsSet = lhs as? Set<Double> {
if let rhsSet = rhs as? Set<Double> {
return Array(lhsSet.intersection(rhsSet))
}
} else if let lhsArray = lhs as? Array<String> {
if let rhsArray = rhs as? Array<String> {
let lhsSet = Set<String>(lhsArray)
let rhsSet = Set<String>(rhsArray)
return Array(lhsSet.intersection(rhsSet))
}
}
return [T.Element]()
}
getCommonElements(["FirstName", "MiddleName", "LastName"], ["FirstName", "LastName"])
let elementsSet1 = Set<Double>([1.2, 2.4, 3.6])
let elementsSet2 = Set<Double>([1.2, 3.6])
getCommonElements(elementsSet1, elementsSet2)
Yes, you can even just init a Set from the input anyway. Doesn't matter if it is Set or Array since your input is Sequence and Set can be init from Sequence. where T.Element: Hashable, T.Element == U.Element already guarantee the element types are the same and can be made as Set
func getCommonElements<T: Sequence, U: Sequence>(_ lhs: T, _ rhs: U) -> [T.Element]
where T.Element: Hashable, T.Element == U.Element
{
return Array(Set<T.Element>(lhs).intersection(Set<U.Element>(rhs)))
}
print(getCommonElements(["FirstName", "MiddleName", "LastName"], ["FirstName", "LastName"]))
let elementsSet1 = Set<Double>([1.2, 2.4, 3.6])
let elementsSet2 = Set<Double>([1.2, 3.6])
print(getCommonElements(elementsSet1, elementsSet2))
output:
["FirstName", "LastName"]
[1.2, 3.6]

How to get next case of enum(i.e. write a circulating method) in Swift 4.2

Swift 4.2 introduces a new CaseIterable protocol that automatically generates an array property of all cases in an enum.
Now I want to implement a default method for Enum inherits from CaseIterable that can return the next case of a giving case. If this case is the last case, return the first case. Like a circle.
If I write this for specific Enum, it works correctly:
enum Direction: CaseIterable {
case east, south, west, north
func next() -> Direction {
let all = type(of: self).allCases // 1
if self == all.last! {
return all.first!
} else {
let index = all.firstIndex(of: self)!
return all[index + 1]
}
}
}
print(Direction.east.next()) // south
print(Direction.north.next()) // east
But I want to implement this function to many Enum. Copying and pasting code repeatedly are not good (Not to mention this code is totally the same for every Enum).
So I tried this. But something went wrong.
(I suggest you copy following code to playground that you can understand this problem more quickly):
extension CaseIterable {
func next() -> Self {
let all = type(of: self).allCases // 1
if self == all.last { // 2
return all.first!
} else {
let index = all.firstIndex { (ele) -> Bool in
self == ele // 3
}
return all[index + 1]
}
}
}
Three points:
all's type is Self.AllCases, which is a Collection type. But in the method above, it's [Direction].
There's an error at line 2 says Value of type 'Self.AllCases' has no member 'last'
(Even I avoid to use last, the error at line 3 can't be avoided.)
At line 3, the error is Binary operator '==' cannot be applied to two 'Self' operands
And even I use generic constraints, it's the same.
func next<T: CaseIterable>(element: T) -> T {...}
Any solutions? :)
Some problems with your approach are:
The Collection protocol does not define a last property.
In order to compare the elements with == they have to be Equatable.
Collection indices are not necessarily integers, they must be incremented
with index(after:).
This seems to be a working solution (tested with Xcode 10.0 beta 2):
extension CaseIterable where Self: Equatable {
func next() -> Self {
let all = Self.allCases
let idx = all.firstIndex(of: self)!
let next = all.index(after: idx)
return all[next == all.endIndex ? all.startIndex : next]
}
}
Example:
enum Direction: CaseIterable {
case east, south, west, north
}
print(Direction.east.next()) // south
print(Direction.north.next()) // east
Remarks:
Only enumerations without associated values are CaseIterable, and
those are also Equatable (but the compiler does not figure out that
by itself). Therefore Self: Equatable is not a
real restriction.
Self.allCases can be used in Swift 4.2 to access the type property
from an instance method.
The forced unwrapping is safe because we know that the value is
an element of allCases.
Your enum Direction: CaseIterable compiles because the concrete
enum Direction type is Equatable, and its Direction.allCases is an Array – which has integer indices and a last property.
If someone is interested into both previous and next cases, here's an upgrade of the previous answer:
extension CaseIterable where Self: Equatable, AllCases: BidirectionalCollection {
func previous() -> Self {
let all = Self.allCases
let idx = all.index(of: self)!
let previous = all.index(before: idx)
return all[previous < all.startIndex ? all.index(before: all.endIndex) : previous]
}
func next() -> Self {
let all = Self.allCases
let idx = all.index(of: self)!
let next = all.index(after: idx)
return all[next == all.endIndex ? all.startIndex : next]
}
}
Actually you don't need BidirectionalCollection conformance to implement previous case as well.
extension CaseIterable where Self: Equatable {
func previous() -> Self {
let all = Self.allCases
var idx = all.firstIndex(of: self)!
if idx == all.startIndex {
let lastIndex = all.index(all.endIndex, offsetBy: -1)
return all[lastIndex]
} else {
all.formIndex(&idx, offsetBy: -1)
return all[idx]
}
}
func next() -> Self {
let all = Self.allCases
let idx = all.firstIndex(of: self)!
let next = all.index(after: idx)
return all[next == all.endIndex ? all.startIndex : next]
}
}
You can also make a more generic cyclic offset function:
extension CaseIterable where Self: Equatable {
func advanced(by n: Int) -> Self {
let all = Array(Self.allCases)
let idx = (all.firstIndex(of: self)! + n) % all.count
print(idx)
if idx >= 0 {
return all[idx]
} else {
return all[all.count + idx]
}
}
}
2022
We can create extension:
extension Collection {
subscript (infinityIdx idx: Index) -> Element where Index == Int {
return self[ idx % self.count ]
}
}
lets try this ext in action:
enum SomeEnum: CaseIterable {
case v1, v2, v3, v4
}
for i in 0...15 {
print(SomeEnum.allCases[infinityIdx: i] )
}
result:
v1
v2
v3
v4
v1
v2
v3
v4
v1
v2
v3

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)]
}
}

Swift: How to make this function generic

Here is what I have:
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)
}
I would like to make this generic for 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)
}
But the error I get is:
Cannot invoke initializer for type Double with an argument list of type (T.Distance)
Is this possible to do?
First you need a CustomDoubleConvertible protocol. This mirrors CustomStringConvertible. You extend all Types which you want to be convertible to Double. Similar to description which returns a String representation of a Type.
protocol CustomDoubleConvertible {
var doubleValue : Double { get }
}
extension Int : CustomDoubleConvertible {
var doubleValue : Double { return Double(self) }
}
extension Int16 : CustomDoubleConvertible {
var doubleValue : Double { return Double(self) }
}
If you make the function an extension to Range itself you can make use of it's generic nature and it's typealiases.
extension Range where Element.Distance : CustomDoubleConvertible {
Now you can calculate the offsets of the indexes like so :
let startOffset = Int(portion * self.count.doubleValue)
let endOffset = Int(portion * self.count.doubleValue)
If you further constrain Range so that it's Element must be a BidirectionalIndexType you can use successor and predecessor.
extension Range where Element.Distance : CustomDoubleConvertible, Element : BidirectionalIndexType {
This allows you to get the full function by iterating over the offsets and calling successor and 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)
}
}
Some tests :
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
This is an interesting but academic exercise.
Here's a method that is not very efficient but that will work with all range types:
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
}
and here's a much quicker one :
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]
}

Elegant way to get the first n elements of a SequenceType

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.