Conditional map function in Swift - ios

I'm taking an array of ([(String?, String)]) and want to drop the last 3 or 5 elements of the non-optional String, depending on the String.
If I know I'm dropping 5 I use
let strippedName = (data.map{ ($0.1).dropLast(5) } ).map{ String($0) }
however, as I said this is a conditional thing depending on the string within the array.
When I try
let strippedName = (data.map{
if ($0.1 == "a") {
return $0.1.first!
} else {
return $0.1.last!
}
} ).map{ String($0) }
(which is obviously not quite the finished article for my needs).
The example will crash on some inputs, that is irrelevant. I need to have an if statement in the map above (the detail of the if statement is not relevant). An alternative is any way to have a conditional map function in Swift (as is the question title).
As above, my requirement is "I'm taking an array of ([(String?, String)]) and want to drop the last 3 or 5 elements of the non-optional String, depending on the String."
I get an error on the last String() cast - Ambiguous use of init.
How can I take my array and use an if statement within my first map?

Another way to solve it is to use reduce
let strippedName = data.reduce(into: []) { if $1.1 == "a" {$0.append($1.1)}}
Update
Trying to solve this as OP wants by using an if in the mapping. For my example here I use compactMap rather than map, this way anything that doesn't satisfy the if condition will be excluded from the array.
Since the return type of the closure is define to be String I don't need to do a second mapping
let strippedName = data.compactMap { t -> String? in
if t.1 == "a" {
return t.1
}
return nil
}

Swift could not infer the complex closure return type, hence it is showing you the error "Ambiguous use of init()"
Specifying the return type explicitly solves the issue.
let data: [(String?, String)] = [("a","bBCDEA"), ("b","a"), (nil,"CBCDEB"), ("d","aBCDEF"), (nil,"a"), ("f","FBCDEC")]
var strippedName = (data.map { tuple -> String.Element in
if (tuple.1 == "a") {
return tuple.1.first!
} else {
return tuple.1.last!
}
}).map{ String($0) }
print(strippedName) // ["A", "a", "B", "F", "a", "C"]
strippedName = (data.map{ ($0.1).dropLast(5) } ).map{ String($0) }
print(strippedName) // ["b", "", "C", "a", "", "F"]

I think the problem is with anonimous closure and type inference, however, to get what you're trying in your second chunk of code, you can use filter instead of conditionals. With this you won't get error:
let strippedName = data.filter { $0.1 == "a" }.map { $0.1 }
and you can add dropLast to the end.

Related

How to use firstIndex in Switft to find all results

I am trying to split a string into an array of letters, but keep some of the letters together. (I'm trying to break them into sound groups for pronunciation, for example).
So, for example, all the "sh' combinations would be one value in the array instead of two.
It is easy to find an 's' in an array that I know has an "sh" in it, using firstIndex. But how do I get more than just the first, or last, index of the array?
The Swift documentation includes this example:
let students = ["Kofi", "Abena", "Peter", "Kweku", "Akosua"]
if let i = students.firstIndex(where: { $0.hasPrefix("A") }) {
print("\(students[i]) starts with 'A'!")
}
// Prints "Abena starts with 'A'!"
How do I get both Abena and Akosua (and others, if there were more?)
Here is my code that accomplishes some of what I want (please excuse the rather lame error catching)
let message = "she sells seashells"
var letterArray = message.map { String($0)}
var error = false
while error == false {
if message.contains("sh") {
guard let locate1 = letterArray.firstIndex(of: "s") else{
error = true
break }
let locate2 = locate1 + 1
//since it keeps finding an s it doesn't know how to move on to rest of string and we get an infinite loop
if letterArray[locate2] == "h"{
letterArray.insert("sh", at: locate1)
letterArray.remove (at: locate1 + 1)
letterArray.remove (at: locate2)}}
else { error = true }}
print (message, letterArray)
Instead of first use filter you will get both Abena and Akosua (and others, if there were more?)
extension Array where Element: Equatable {
func allIndexes(of element: Element) -> [Int] {
return self.enumerated().filter({ element == $0.element }).map({ $0.offset })
}
}
You can then call
letterArray.allIndexes(of: "s") // [0, 4, 8, 10, 13, 18]
You can filter the collection indices:
let students = ["Kofi", "Abena", "Peter", "Kweku", "Akosua"]
let indices = students.indices.filter({students[$0].hasPrefix("A")})
print(indices) // "[1, 4]\n"
You can also create your own indices method that takes a predicate:
extension Collection {
func indices(where predicate: #escaping (Element) throws -> Bool) rethrows -> [Index] {
try indices.filter { try predicate(self[$0]) }
}
}
Usage:
let indices = students.indices { $0.hasPrefix("A") }
print(indices) // "[1, 4]\n"
or indices(of:) where the collection elements are Equatable:
extension Collection where Element: Equatable {
func indices(of element: Element) -> [Index] {
indices.filter { self[$0] == element }
}
}
usage:
let message = "she sells seashells"
let indices = message.indices(of: "s")
print(indices)
Note: If you need to find all ranges of a substring in a string you can check this post.
Have fun!
["Kofi", "Abena", "Peter", "Kweku", "Akosua"].forEach {
if $0.hasPrefix("A") {
print("\($0) starts with 'A'!")
}
}
If you really want to use the firstIndex method, here's a recursive(!) implementation just for fun :D
extension Collection where Element: Equatable {
/// Returns the indices of an element from the specified index to the end of the collection.
func indices(of element: Element, fromIndex: Index? = nil) -> [Index] {
let subsequence = suffix(from: fromIndex ?? startIndex)
if let elementIndex = subsequence.firstIndex(of: element) {
return [elementIndex] + indices(of: element, fromIndex: index(elementIndex, offsetBy: 1))
}
return []
}
}
Recursions
Given n instances of element in the collection, the function will be called n+1 times (including the first call).
Complexity
Looking at complexity, suffix(from:) is O(1), and firstIndex(of:) is O(n). Assuming that firstIndex terminates once it encounters the first match, any recursions simply pick up where we left off. Therefore, indices(of:fromIndex:) is O(n), just as good as using filter. Sadly, this function is not tail recursive... although we can change that by keeping a running total.
Performance
[Maybe I'll do this another time.]
Disclaimer
Recursion is fun and all, but you should probably use Leo Dabus' solution.

How to sort an array both numerically and alphabetically in Swift

Say I have an array:
var array = ["5C", "4D", "2H", "13S", "4C", "5H"]
How would I be able to sort this array so that the new array would have the last character sorted alphabetically, then the previous numerical values sorted numerically such as:
["4C", "5C", "4D", "2H", "5H", "13S"]
I am relatively new to coding in general and have a very basic grasp of syntax. Other searches have shown me how to sort numerically using the .sorted function and .ascendingOrder, but I couldn't find a solution that could sort both alphabetically and numerically.
EDIT:
My answer shows how to use sorted() to sort an array of strings into "numeric" order. It is not quite what the OP asked.
To the OP: You should accept vadian's answer. His was the first correct answer.
However, I spend some time in my answer explaining Swift closure syntax, so I am going to leave the answer.
You can use the array method sorted(), which takes a closure that compares pairs of objects and returns true if the first item should come first.
Then you can use the NSString method compare(options:) to do a "numeric" string comparison, where sequences of digits are treated as numbers inside the string.
Here is a working code snippet that will sort your array:
var array = ["5C", "4D", "2H", "13S", "4C", "5H"]
let sorted = array.sorted (by: { (first: String, second: String) -> Bool in
return first.compare(second, options: .numeric) == .orderedAscending
})
The function sorted() is a "higher order function`, or a function that takes another function as a parameter. For an array of strings, that function takes 2 strings, and returns a Bool. It actually takes a closure rather than a function, where a closure is an "anonymous function" (a function with no name.)
Adapting vadian's code that gives the CORRECT answer to my snippet, it would look like this:
var array = ["5C", "4D", "2H", "13S", "4C", "5H"]
let sorted = array.sorted (by: { (first: String, second: String) -> Bool in
if first.suffix(1) == second.suffix(1) {
return first.dropLast.compare(second, options: .numeric) == .orderedAscending
} else {
return first.suffix(1) < second.suffix(1)
}
})
You can rewrite the above with several shortcuts:
With a "trailing closure" you skip the () that contains the closure as a parameter and just provide the closure in braces after the function name.
You can skip the declaration of the parameters and return type of the closure, and skip the return statement:
let sorted = array.sorted { $0.compare($1, options: .numeric) == .orderedAscending }
For more complex code like vadian's that gives the correct answer, I suggest not using positional parameters like that. Using local variables like first and second make the code easier to read.
I suggest studying the chapter on Closures in Apple's Swift iBooks carefully until you understand the various ways that closures can be expressed and their different shortcut syntaxes. It's confusing at first, and using closures is fundamental to using Swift.
You have to write your own comparator which is pretty handy in Swift.
If the last character is the same sort the string without the last character numerically otherwise sort by the last character
let array = ["5C", "4D", "2H", "13S", "4C", "5H"]
let sortedArray = array.sorted { (str1, str2) -> Bool in
if str1.suffix(1) == str2.suffix(1) {
return str1.dropLast().localizedStandardCompare(str2.dropLast()) == .orderedAscending
} else {
return str1.suffix(1) < str2.suffix(1)
}
}
// ["4C", "5C", "4D", "2H", "5H", "13S"]
Welcome to StackOverflow!
What do these numbers represent? I would create a struct to model that "thing" (I'll call it Thing for now), and function that can parse a String into a Thing, like so:
struct Thing: Equatable { // FIXME: Name me something descriptive
let number: Int // FIXME: Name me something descriptive
let letter: Character // FIXME: Name me something descriptive
static func parse(from string: String) -> Thing? {
let numberSegment = string.prefix(while: { $0.isNumber })
guard !numberSegment.isEmpty,
let number = Int(numberSegment) else { return nil }
let letterSegement = string.drop(while: { $0.isNumber })
guard letterSegement.count == 1,
let letter = letterSegement.first else { return nil }
return Thing(number: number, letter: letter)
}
}
Then, you can just conform to Comparable, defining how you want things to be sorted, by defining the comparison operator <:
extension Thing: Comparable {
static func < (lhs: Thing, rhs: Thing) -> Bool {
return (lhs.letter, lhs.number) < (rhs.letter, rhs.number)
}
}
From there, it's just a matter of parsing all your strings into Things, and sorting them:
let array = ["5C", "4D", "2H", "13S", "4C", "5H"]
let things = array.map { Thing.parse(from: $0)! }
print("Before sorting:")
things.forEach { print("\t\($0)") }
let sortedThings = things.sorted()
print("\nAfter sorting:")
sortedThings.forEach { print("\t\($0)") }
Output:
Before sorting:
Thing(number: 5, letter: "C")
Thing(number: 4, letter: "D")
Thing(number: 2, letter: "H")
Thing(number: 13, letter: "S")
Thing(number: 4, letter: "C")
Thing(number: 5, letter: "H")
After sorting:
Thing(number: 4, letter: "C")
Thing(number: 5, letter: "C")
Thing(number: 4, letter: "D")
Thing(number: 2, letter: "H")
Thing(number: 5, letter: "H")
Thing(number: 13, letter: "S")
Welcome to StackOverflow!
this is my solution hope it works for you, I just organize first the numbers and next comparate with the alphabeth to create a new array:
var array = ["5C", "4D", "2H", "13S", "4C", "5H"]
array = array.sorted { $0.numbersValues < $1.numbersValues }
let str = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
var newArrray: [String] = []
for letter in str {
for value in array {
if value.lettersValues.hasPrefix(String(letter)) {
newArrray.append(value)
}
}
}
Don't forget include this helpers methods in your project
extension String {
var lettersValues: String {
return self.components(separatedBy: CharacterSet.decimalDigits).joined()
}
var numbersValues: String {
return self.filter { "0"..."9" ~= $0 }
}
}

Array return optional value? [duplicate]

If I have an array in Swift, and try to access an index that is out of bounds, there is an unsurprising runtime error:
var str = ["Apple", "Banana", "Coconut"]
str[0] // "Apple"
str[3] // EXC_BAD_INSTRUCTION
However, I would have thought with all the optional chaining and safety that Swift brings, it would be trivial to do something like:
let theIndex = 3
if let nonexistent = str[theIndex] { // Bounds check + Lookup
print(nonexistent)
...do other things with nonexistent...
}
Instead of:
let theIndex = 3
if (theIndex < str.count) { // Bounds check
let nonexistent = str[theIndex] // Lookup
print(nonexistent)
...do other things with nonexistent...
}
But this is not the case - I have to use the ol' if statement to check and ensure the index is less than str.count.
I tried adding my own subscript() implementation, but I'm not sure how to pass the call to the original implementation, or to access the items (index-based) without using subscript notation:
extension Array {
subscript(var index: Int) -> AnyObject? {
if index >= self.count {
NSLog("Womp!")
return nil
}
return ... // What?
}
}
Alex's answer has good advice and solution for the question, however, I've happened to stumble on a nicer way of implementing this functionality:
extension Collection {
/// Returns the element at the specified index if it is within bounds, otherwise nil.
subscript (safe index: Index) -> Element? {
return indices.contains(index) ? self[index] : nil
}
}
Example
let array = [1, 2, 3]
for index in -20...20 {
if let item = array[safe: index] {
print(item)
}
}
If you really want this behavior, it smells like you want a Dictionary instead of an Array. Dictionaries return nil when accessing missing keys, which makes sense because it's much harder to know if a key is present in a dictionary since those keys can be anything, where in an array the key must in a range of: 0 to count. And it's incredibly common to iterate over this range, where you can be absolutely sure have a real value on each iteration of a loop.
I think the reason it doesn't work this way is a design choice made by the Swift developers. Take your example:
var fruits: [String] = ["Apple", "Banana", "Coconut"]
var str: String = "I ate a \( fruits[0] )"
If you already know the index exists, as you do in most cases where you use an array, this code is great. However, if accessing a subscript could possibly return nil then you have changed the return type of Array's subscript method to be an optional. This changes your code to:
var fruits: [String] = ["Apple", "Banana", "Coconut"]
var str: String = "I ate a \( fruits[0]! )"
// ^ Added
Which means you would need to unwrap an optional every time you iterated through an array, or did anything else with a known index, just because rarely you might access an out of bounds index. The Swift designers opted for less unwrapping of optionals, at the expense of a runtime exception when accessing out of bounds indexes. And a crash is preferable to a logic error caused by a nil you didn't expect in your data somewhere.
And I agree with them. So you won't be changing the default Array implementation because you would break all the code that expects a non-optional values from arrays.
Instead, you could subclass Array, and override subscript to return an optional. Or, more practically, you could extend Array with a non-subscript method that does this.
extension Array {
// Safely lookup an index that might be out of bounds,
// returning nil if it does not exist
func get(index: Int) -> T? {
if 0 <= index && index < count {
return self[index]
} else {
return nil
}
}
}
var fruits: [String] = ["Apple", "Banana", "Coconut"]
if let fruit = fruits.get(1) {
print("I ate a \( fruit )")
// I ate a Banana
}
if let fruit = fruits.get(3) {
print("I ate a \( fruit )")
// never runs, get returned nil
}
Swift 3 Update
func get(index: Int) ->T? needs to be replaced by func get(index: Int) ->Element?
To build on Nikita Kukushkin's answer, sometimes you need to safely assign to array indexes as well as read from them, i.e.
myArray[safe: badIndex] = newValue
So here is an update to Nikita's answer (Swift 3.2) that also allows safely writing to mutable array indexes, by adding the safe: parameter name.
extension Collection {
/// Returns the element at the specified index if it is within bounds, otherwise nil.
subscript(safe index: Index) -> Element? {
return indices.contains(index) ? self[index] : nil
}
}
extension MutableCollection {
subscript(safe index: Index) -> Element? {
get {
return indices.contains(index) ? self[index] : nil
}
set(newValue) {
if let newValue = newValue, indices.contains(index) {
self[index] = newValue
}
}
}
}
extension Array {
subscript (safe index: Index) -> Element? {
0 <= index && index < count ? self[index] : nil
}
}
O(1) performance
type safe
correctly deals with Optionals for [MyType?] (returns MyType??, that can be unwrapped on both levels)
does not lead to problems for Sets
concise code
Here are some tests I ran for you:
let itms: [Int?] = [0, nil]
let a = itms[safe: 0] // 0 : Int??
a ?? 5 // 0 : Int?
let b = itms[safe: 1] // nil : Int??
b ?? 5 // nil : Int? (`b` contains a value and that value is `nil`)
let c = itms[safe: 2] // nil : Int??
c ?? 5 // 5 : Int?
Swift 4
An extension for those who prefer a more traditional syntax:
extension Array {
func item(at index: Int) -> Element? {
return indices.contains(index) ? self[index] : nil
}
}
Valid in Swift 2
Even though this has been answered plenty of times already, I'd like to present an answer more in line in where the fashion of Swift programming is going, which in Crusty's words¹ is: "Think protocols first"
• What do we want to do?
- Get an Element of an Array given an Index only when it's safe, and nil otherwise
• What should this functionality base it's implementation on?
- Array subscripting
• Where does it get this feature from?
- Its definition of struct Array in the Swift module has it
• Nothing more generic/abstract?
- It adopts protocol CollectionType which ensures it as well
• Nothing more generic/abstract?
- It adopts protocol Indexable as well...
• Yup, sounds like the best we can do. Can we then extend it to have this feature we want?
- But we have very limited types (no Int) and properties (no count) to work with now!
• It will be enough. Swift's stdlib is done pretty well ;)
extension Indexable {
public subscript(safe safeIndex: Index) -> _Element? {
return safeIndex.distanceTo(endIndex) > 0 ? self[safeIndex] : nil
}
}
¹: not true, but it gives the idea
Because arrays may store nil values, it does not make sense to return a nil if an array[index] call is out of bounds.
Because we do not know how a user would like to handle out of bounds problems, it does not make sense to use custom operators.
In contrast, use traditional control flow for unwrapping objects and ensure type safety.
if let index = array.checkIndexForSafety(index:Int)
let item = array[safeIndex: index]
if let index = array.checkIndexForSafety(index:Int)
array[safeIndex: safeIndex] = myObject
extension Array {
#warn_unused_result public func checkIndexForSafety(index: Int) -> SafeIndex? {
if indices.contains(index) {
// wrap index number in object, so can ensure type safety
return SafeIndex(indexNumber: index)
} else {
return nil
}
}
subscript(index:SafeIndex) -> Element {
get {
return self[index.indexNumber]
}
set {
self[index.indexNumber] = newValue
}
}
// second version of same subscript, but with different method signature, allowing user to highlight using safe index
subscript(safeIndex index:SafeIndex) -> Element {
get {
return self[index.indexNumber]
}
set {
self[index.indexNumber] = newValue
}
}
}
public class SafeIndex {
var indexNumber:Int
init(indexNumber:Int){
self.indexNumber = indexNumber
}
}
I realize this is an old question. I'm using Swift5.1 at this point, the OP was for Swift 1 or 2?
I needed something like this today, but I didn't want to add a full scale extension for just the one place and wanted something more functional (more thread safe?). I also didn't need to protect against negative indices, just those that might be past the end of an array:
let fruit = ["Apple", "Banana", "Coconut"]
let a = fruit.dropFirst(2).first // -> "Coconut"
let b = fruit.dropFirst(0).first // -> "Apple"
let c = fruit.dropFirst(10).first // -> nil
For those arguing about Sequences with nil's, what do you do about the first and last properties that return nil for empty collections?
I liked this because I could just grab at existing stuff and use it to get the result I wanted. I also know that dropFirst(n) is not a whole collection copy, just a slice. And then the already existent behavior of first takes over for me.
I found safe array get, set, insert, remove very useful. I prefer to log and ignore the errors as all else soon gets hard to manage. Full code bellow
/**
Safe array get, set, insert and delete.
All action that would cause an error are ignored.
*/
extension Array {
/**
Removes element at index.
Action that would cause an error are ignored.
*/
mutating func remove(safeAt index: Index) {
guard index >= 0 && index < count else {
print("Index out of bounds while deleting item at index \(index) in \(self). This action is ignored.")
return
}
remove(at: index)
}
/**
Inserts element at index.
Action that would cause an error are ignored.
*/
mutating func insert(_ element: Element, safeAt index: Index) {
guard index >= 0 && index <= count else {
print("Index out of bounds while inserting item at index \(index) in \(self). This action is ignored")
return
}
insert(element, at: index)
}
/**
Safe get set subscript.
Action that would cause an error are ignored.
*/
subscript (safe index: Index) -> Element? {
get {
return indices.contains(index) ? self[index] : nil
}
set {
remove(safeAt: index)
if let element = newValue {
insert(element, safeAt: index)
}
}
}
}
Tests
import XCTest
class SafeArrayTest: XCTestCase {
func testRemove_Successful() {
var array = [1, 2, 3]
array.remove(safeAt: 1)
XCTAssert(array == [1, 3])
}
func testRemove_Failure() {
var array = [1, 2, 3]
array.remove(safeAt: 3)
XCTAssert(array == [1, 2, 3])
}
func testInsert_Successful() {
var array = [1, 2, 3]
array.insert(4, safeAt: 1)
XCTAssert(array == [1, 4, 2, 3])
}
func testInsert_Successful_AtEnd() {
var array = [1, 2, 3]
array.insert(4, safeAt: 3)
XCTAssert(array == [1, 2, 3, 4])
}
func testInsert_Failure() {
var array = [1, 2, 3]
array.insert(4, safeAt: 5)
XCTAssert(array == [1, 2, 3])
}
func testGet_Successful() {
var array = [1, 2, 3]
let element = array[safe: 1]
XCTAssert(element == 2)
}
func testGet_Failure() {
var array = [1, 2, 3]
let element = array[safe: 4]
XCTAssert(element == nil)
}
func testSet_Successful() {
var array = [1, 2, 3]
array[safe: 1] = 4
XCTAssert(array == [1, 4, 3])
}
func testSet_Successful_AtEnd() {
var array = [1, 2, 3]
array[safe: 3] = 4
XCTAssert(array == [1, 2, 3, 4])
}
func testSet_Failure() {
var array = [1, 2, 3]
array[safe: 4] = 4
XCTAssert(array == [1, 2, 3])
}
}
Swift 5.x
An extension on RandomAccessCollection means that this can also work for ArraySlice from a single implementation. We use startIndex and endIndex as array slices use the indexes from the underlying parent Array.
public extension RandomAccessCollection {
/// Returns the element at the specified index if it is within bounds, otherwise nil.
/// - complexity: O(1)
subscript (safe index: Index) -> Element? {
guard index >= startIndex, index < endIndex else {
return nil
}
return self[index]
}
}
extension Array {
subscript (safe index: UInt) -> Element? {
return Int(index) < count ? self[Int(index)] : nil
}
}
Using Above mention extension return nil if anytime index goes out of bound.
let fruits = ["apple","banana"]
print("result-\(fruits[safe : 2])")
result - nil
I have padded the array with nils in my use case:
let components = [1, 2]
var nilComponents = components.map { $0 as Int? }
nilComponents += [nil, nil, nil]
switch (nilComponents[0], nilComponents[1], nilComponents[2]) {
case (_, _, .Some(5)):
// process last component with 5
default:
break
}
Also check the subscript extension with safe: label by Erica Sadun / Mike Ash: http://ericasadun.com/2015/06/01/swift-safe-array-indexing-my-favorite-thing-of-the-new-week/
The "Commonly Rejected Changes" for Swift list contains a mention of changing Array subscript access to return an optional rather than crashing:
Make Array<T> subscript access return T? or T! instead of T: The current array behavior is intentional, as it accurately reflects the fact that out-of-bounds array access is a logic error. Changing the current behavior would slow Array accesses to an unacceptable degree. This topic has come up multiple times before but is very unlikely to be accepted.
https://github.com/apple/swift-evolution/blob/master/commonly_proposed.md#strings-characters-and-collection-types
So the basic subscript access will not be changing to return an optional.
However, the Swift team/community does seem open to adding a new optional-returning access pattern to Arrays, either via a function or subscript.
This has been proposed and discussed on the Swift Evolution forum here:
https://forums.swift.org/t/add-accessor-with-bounds-check-to-array/16871
Notably, Chris Lattner gave the idea a "+1":
Agreed, the most frequently suggested spelling for this is: yourArray[safe: idx], which seems great to me. I am very +1 for adding this.
https://forums.swift.org/t/add-accessor-with-bounds-check-to-array/16871/13
So this may be possible out of the box in some future version of Swift. I'd encourage anyone who wants it to contribute to that Swift Evolution thread.
Not sure why no one, has put up an extension that also has a setter to automatically grow the array
extension Array where Element: ExpressibleByNilLiteral {
public subscript(safe index: Int) -> Element? {
get {
guard index >= 0, index < endIndex else {
return nil
}
return self[index]
}
set(newValue) {
if index >= endIndex {
self.append(contentsOf: Array(repeating: nil, count: index - endIndex + 1))
}
self[index] = newValue ?? nil
}
}
}
Usage is easy and works as of Swift 5.1
var arr:[String?] = ["A","B","C"]
print(arr) // Output: [Optional("A"), Optional("B"), Optional("C")]
arr[safe:10] = "Z"
print(arr) // [Optional("A"), Optional("B"), Optional("C"), nil, nil, nil, nil, nil, nil, nil, Optional("Z")]
Note: You should understand the performance cost (both in time/space) when growing an array in swift - but for small problems sometimes you just need to get Swift to stop Swifting itself in the foot
To propagate why operations fail, errors are better than optionals.
public extension Collection {
/// Ensure an index is valid before accessing an element of the collection.
/// - Returns: The same as the unlabeled subscript, if an error is not thrown.
/// - Throws: `AnyCollection<Element>.IndexingError`
/// if `indices` does not contain `index`.
subscript(validating index: Index) -> Element {
get throws {
guard indices.contains(index)
else { throw AnyCollection<Element>.IndexingError() }
return self[index]
}
}
}
public extension AnyCollection {
/// Thrown when `[validating:]` is called with an invalid index.
struct IndexingError: Error { }
}
XCTAssertThrowsError(try ["🐾", "🥝"][validating: 2])
let collection = Array(1...10)
XCTAssertEqual(try collection[validating: 0], 1)
XCTAssertThrowsError(try collection[validating: collection.endIndex]) {
XCTAssert($0 is AnyCollection<Int>.IndexingError)
}
I think this is not a good idea. It seems preferable to build solid code that does not result in trying to apply out-of-bounds indexes.
Please consider that having such an error fail silently (as suggested by your code above) by returning nil is prone to producing even more complex, more intractable errors.
You could do your override in a similar fashion you used and just write the subscripts in your own way. Only drawback is that existing code will not be compatible. I think to find a hook to override the generic x[i] (also without a text preprocessor as in C) will be challenging.
The closest I can think of is
// compile error:
if theIndex < str.count && let existing = str[theIndex]
EDIT: This actually works. One-liner!!
func ifInBounds(array: [AnyObject], idx: Int) -> AnyObject? {
return idx < array.count ? array[idx] : nil
}
if let x: AnyObject = ifInBounds(swiftarray, 3) {
println(x)
}
else {
println("Out of bounds")
}
I have made a simple extension for array
extension Array where Iterator.Element : AnyObject {
func iof (_ i : Int ) -> Iterator.Element? {
if self.count > i {
return self[i] as Iterator.Element
}
else {
return nil
}
}
}
it works perfectly as designed
Example
if let firstElemntToLoad = roots.iof(0)?.children?.iof(0)?.cNode,
You can try
if index >= 0 && index < array.count {
print(array[index])
}
To be honest I faced this issue too. And from performance point of view a Swift array should be able to throw.
let x = try a[y]
This would be nice and understandable.
When you only need to get values from an array and you don't mind a small performance penalty (i.e. if your collection isn't huge), there is a Dictionary-based alternative that doesn't involve (a too generic, for my taste) collection extension:
// Assuming you have a collection named array:
let safeArray = Dictionary(uniqueKeysWithValues: zip(0..., array))
let value = safeArray[index] ?? defaultValue;
2022
infinite index access and safe idx access(returns nil in case no such idex):
public extension Collection {
subscript (safe index: Index) -> Element? {
return indices.contains(index) ? self[index] : nil
}
subscript (infinityIdx idx: Index) -> Element where Index == Int {
return self[ abs(idx) % self.count ]
}
}
but be careful, it will throw an exception in case of array/collection is empty
usage
(0...10)[safe: 11] // nil
(0...10)[infinityIdx: 11] // 0
(0...10)[infinityIdx: 12] // 1
(0...10)[infinityIdx: 21] // 0
(0...10)[infinityIdx: 22] // 1
Swift 5 Usage
extension WKNavigationType {
var name : String {
get {
let names = ["linkAct","formSubm","backForw","reload","formRelo"]
return names.indices.contains(self.rawValue) ? names[self.rawValue] : "other"
}
}
}
ended up with but really wanted to do generally like
[<collection>][<index>] ?? <default>
but as the collection is contextual I guess it's proper.

Swift: array of objects search

I want to search in array of objects in swift
but I didn't know how :(
I tried
filteredArrayUsingPredicate
but still don't work ,It's giving me an error msg
-- Update --
the error message is
swift:42:9: 'Array<search_options>' does not have a member named 'filteredArrayUsingPredicate'
-- Update --
class search_options {
let id:String
let option:String
init(){}
init(id:String ,option:String){
self.id = id
self.option = option
}
}
I only want to search in option variable
And when I tried to used
func searchBarSearchButtonClicked( searchBar: UISearchBar!)
{
let filteredArray = filter(search_options_array) { $0 == "test" }
println(searchBar.text)
}
I got this message
swift:40:58: 'search_options' is not a subtype of 'String'
Find index of specific object:
if let index = find(myArray, objectIAmLookingFor) {
// found! do something
}
Filter array:
let filteredArray = filter(myArray) { $0 == objectIAmLookingFor }
Finally after long search I did't ! ,
I was looking to find a way to do a dynamic search like if array of String contains
"hello","lo","yes"
and I want to get all the strings that contains for example "lo"
I want to get "hello" and "lo"
so the best way I found is regular expression search
so I do a For Loop throw all options in Array and compare every single object variable to the pattern ,and save it in new array on objects
for var i = 0; i < search_options_array.count; i++ {
let myRegex = "searched_text"
if let match = search_options_array[i].option.rangeOfString(myRegex, options: .RegularExpressionSearch){
filtered_options_array.append(search_options(id:search_options_array[i].id,option:search_options_array[i].option) )
}
}
The best part here you can use all benefits of regular expression and have a copy of yours old array so if you need it.
Thanks every one for helping.
Because filter accepts as a predicate a function which maps each element of the given Array to a Bool value (to determine which value should be filtered out), in your case it may be this way;
let a = [
search_options(id: "a", option: "X"),
search_options(id: "b", option: "Y"),
search_options(id: "c", option: "X")
]
let b = filter(a) { (e: search_options) in e.option == "X" }
// ==> [search_options(id: "a", option: "X"), search_options(id: "c", option: "X")]
The correct answer is
func searchBarSearchButtonClicked( searchBar: UISearchBar!)
{
let filteredArray = filter(search_options_array) { $0.option == "test" }
println(searchBar.text)
}
or
func searchBarSearchButtonClicked( searchBar: UISearchBar!)
{
let filteredArray = filter(search_options_array) { $0.id == "test" }
println(searchBar.text)
}
You must retrieve property of searched object by which you perform searching

Converting Character in an array to an Integer

I can't seem to figure out how to do this even though I've searched through documentation.
I'm trying to figure out how to convert a character at an index in an array to an integer.
For example, say I have a character array named "container", I can't figure out how to do:
var number:Integer = container[3]
Thanks for the help!
Swift doesn't make it easy to convert between primitive and typed representations of things. Here's an extension that should help in the meantime:
extension Character {
func utf8Value() -> UInt8 {
for s in String(self).utf8 {
return s
}
return 0
}
func utf16Value() -> UInt16 {
for s in String(self).utf16 {
return s
}
return 0
}
func unicodeValue() -> UInt32 {
for s in String(self).unicodeScalars {
return s.value
}
return 0
}
}
This allows you to get pretty close to what you want:
let container : Array<Character> = [ "a", "b", "c", "d" ]
/// can't call anything here, subscripting's also broken
let number = container[2]
number.unicodeValue() /// Prints "100"
For any engineers that come across this question, see rdar://17494834
I am not sure that it is effective or not but at least it worked. I converted Character to String then to Int.
String(yourCharacterInArray).toInt()
You may try this:
var container = "$0123456789"
var number:Int = Array(container.utf8).map { Int($0) }[3]
It's totally ugly, but it does the job. Also it is a bit computational expensive (O(n) each time one access a character in a string). Still this can be a trick to get back a way to build the CStrings:
typealias CString = Array<CChar>
func toCString(string: String) -> CString {
return Array(string.utf8).map { CChar($0) } + [0]
}
var cString = toCString("$ 0123456789")
println("The 2nd character in cString has value \(cString[1])") // It outputs 32
or without implementing a function:
var container = "$ 0123456789"
var containerAsCString = Array(container.utf8).map { CChar($0) } + [0]
println("The 2nd character in container has value \(containerAsCString[1])") // It outputs 32
Why not just for loop the array and convert everything to Int?
https://developer.apple.com/Library/mac/documentation/General/Reference/SwiftStandardLibraryReference/index.html
Why not just convert the character to String, get the unicodeScalars for it and extract the .value on the scalar?
something like:
var chr: [Character] = ["C", "B", "A"]
for a in String(chr[1]).unicodeScalars {
println(a.value)}
For me worked something like:
"\(container[3])".toInt()

Resources