Swift switch pattern matching with arrays
You could define a custom pattern matching operator~=
which takes an array as the "pattern" and a value:
func ~=<T : Equatable>(array: [T], value: T) -> Bool {
return array.contains(value)
}
let foo = [1, 2, 3]
let bar = [4, 5, 6]
let value = 5
switch value {
case foo:
print("\(value) is in foo")
case bar:
print("\(value) is in bar")
default:
break
}
Similar operators exist already e.g. for intervals:
public func ~=<I : IntervalType>(pattern: I, value: I.Bound) -> Bool
Swift Pattern match on ArrayAny
Unfortunately casting between generic types like Array
is not fully supported (yet). There are also odd situations even if you want to upcast:
let emptyStringArray : [String] = []
emptyStringArray as [Any] // succeeds
let stringArray : [String] = ["Bob", "Roger"]
stringArray as [Any] // error! due to the elements?!
let intArray = [1, 2, 3]
intArray as [Any] // error
let customStructArray : [myStruct] = []
customStructArray as [Any] // '[myStruct]' is not convertible to '[Any]'
There is also no good workaround without using a protocol. If you really want to have this dynamic behavior you could use reflections with the reflect()
function. In Swift 2 they are more powerful, but it is still not a good solution.
Edit:
A solution with a protocol which gets adopted by all Arrays
through an extension (only for your specific case):
protocol ArrayType {
var anyValues: [Any] { get }
}
extension Array: ArrayType {
var anyValues: [Any] {
return self.map { $0 as Any }
}
}
// now the switch gets rewritten as
switch any {
case let array as ArrayType:
let anyArray = array.anyValues
return "Array"
case let array as NSArray:
return "NSArray"
default:
return "Default"
}
Pattern matching in a Swift for loop
You can combine a pattern matching conditional cast with a where
clause like so:
let myStuff: [AnyObject] = [5, "dog", 11, 15, "cat"]
// item will be an Int, and divisible by 5
for case let item as Int in myStuff where item % 5 == 0 {
print(item)
}
// Prints:
// 5
// 15
How to use Pattern matching in a Swift for loop for nested array
Not really pattern matching but without a loop
arr2.compactMap{$0.first{$0 is String}}.forEach{print($0)}
compactMap
is necessary because first
returns an optional. The position of the String
in the array is irrelevant.
Is there a way to compare array with array using switch case in Swift?
You can use cases with where
predicates:
let array = ["A", "B"]
switch array {
case _ where array == ["A", "B"]: print("AB")
case _ where array == ["C", "D"]: print("CD")
default: print("default")
}
If you really wanted, you could define a pattern match operator (~=
) that calls ==
. The switch
statement looks for definitions of the pattern match operator that accept the given pattern and candidate to determine whether a case
is matched:
let array = ["A", "B"]
func ~= <T: Equatable>(pattern: [T], candidate: [T]) -> Bool {
return pattern == candidate
}
switch array {
case ["A", "B"]: print("AB")
case ["C", "D"]: print("CD")
default: print("default")
}
I would advise against this, however, because it's not clear whether such a case is doing a ==
check, contains(_:)
, hasPrefix(_:)
, etc.
Swift - Search for pattern of numbers in an array
I still feel your question not entirely clear. Does the array [2,3,2,3,2]
has 2 repeating subsequences of [2,3,2]
even though they share an element in common?
If you want to avoid the "Can't form Range..." error, use stride
:
// A more convenient way to check if two arrays are equal
func ==(lhs: [Int], rhs: [Int]) -> Bool {
guard lhs.count == rhs.count else { return false }
for (l, r) in zip(lhs, rhs) {
if l != r { return false }
}
return true
}
// If there's no matching pattern, this function will return nil
// instead of an aempty array. Change it if you want to
func hasPattern(array: [Int], length: Int) -> [[Int]]? {
guard array.count >= length * 2 else { return nil }
var result = [[Int]]()
for i in 0..<(array.count - length) {
let subarray1 = array[i..<(i+length)]
for j in stride(from: i+1, to: array.count - length, by: 1) {
let subarray2 = array[j..<(j+length)]
if subarray1 == subarray2 {
result.append(Array(subarray1))
}
}
}
return result.isEmpty ? nil : result
}
if let patterns = hasPattern(array: array5, length: 3) {
print(patterns) // [[39, 78, 324], [78, 324, 43]]
} else {
print("No repeating pattern found")
}
Retrieve array of substring matched with regex in swift
Your fundamental issue, as @jnpdx hinted at in a comment, is that your regexp
string contains control elements from another language. The following should solve your issue:
let regexp = "@\\w*"
You also get bogged down in unnecessary try-catch statements and outdated APIs based on Objective-C and their related type conversions. The following should do:
func matches(for regex: String, in text: String) -> [String] {
var result = [String]()
var startIndex = text.startIndex
let endIndex = text.endIndex
while let range = text.range(of: regex,
options: .regularExpression,
range: startIndex ..< endIndex)
{
result.append(String(text[range]))
startIndex = range.upperBound
}
return result
}
Related Topics
How to Move an Object Towards a Direction Without Stopping
Is There an Object Class in Swift
How to Draw Something on a PDF in Swift
Turn Off Splash Screen When Using Flutterviewcontroller Within Existing Native App
Generic Return Type Based on Class
How to Use a Protocol with a Typealias as a Func Parameter
Hide Placeholder Programatically Using Swift 3X
Error: Missing Return in a Closure Expected to Return 'Uiviewcontroller' (Xcode, Swift, iOS 13)
Wrong Value Returned After Formatting Timestamp
Scanning Ble Peripheral and Connecting to It
How to Find The Top 3 Maximum Values in a Swift Dictionary
Issue with Optional Core Data Relationship Using Nspersistentcloudkitcontainer
Must Call a Designated Initializer of The Superclass 'Day' Error
What Is The Intended Use of Optional Variable/Constant in Swift