I need to do something simple as converting an [AnyObject?] to [AnyObject]. So the optionals in the array should be unwrapped, and if nil kicked out of the array. Is there an easy way to do this in Swift?
You can do it in 2 steps:
filter the array to include all values that are not nil
map the resulting array by transforming each optional into a non optional
Code:
let arrayOfOptionals: [AnyObject?] = [1, 2, nil, 3, nil, 4]
let arrayOfNonOptionals: [AnyObject?] = arrayOfOptionals.filter( { $0 != nil} )
let finalArray: [AnyObject] = arrayOfNonOptionals.map( { $0! } )
Of course you can combine filter and map into a single statement:
let finalArray = arrayOfOptionals.filter( { $0 != nil} ).map( { $0! } )
The shortest answer is
let hetro1 : [AnyObject?] = ["a", nil, 2, 3.4, nil];
var hetro2 : [AnyObject] = [];
for val in hetro1{
if((val) != nil){
hetro2.append(val!)
}
}
println("hetro1 \(hetro1)")
println("hetro2 \(hetro2)")
Related
So I have this method to get an array of random ints between 1-9, a random number of times between 1 and 7.
let n = arc4random_uniform(7) + 1
var arr: [UInt32] = []
for _ in 0 ... n {
var temp = arc4random_uniform(9) + 1
while arr.contains(temp) {
temp = arc4random_uniform(9) + 1
}
print(temp)
arr.append(temp)
}
print(arr)
So that gets me an array like [1,4,2] or [5,7,3,4,6]. And I have a method to turn another array of strings into a enumerated dictionary.
var someArray: [String] = ["War", "Peanuts", "Cats", "Dogs", "Nova", "Bears", "Pigs", "Packers", "Mango", "Turkey"]
extension Collection {
var indexedDictionary: [Int: Element] {
return enumerated().reduce(into: [:]) { $0[$1.offset] = $1.element }
}
}
let dict1 = someArray.indexedDictionary
print(dict1)
giving me the indexed dictionary
[1:"War", 2:"Peanuts",..etc]
MY question is using the Ints of the random array how do I create a new dictionary that only includes those keys and their values?
So for example if arr = [3,1,5]
how do I get a new dictionary of
[3:"dogs", 1:"Peanuts",5:"Bears"].
This should do it:
let finalDict = dict1.filter { arr.contains($0.key) }
Update:
You can even go a step further and skip the whole strings to array mapping. So remove
extension Collection {
var indexedDictionary: [Int: Element] {
return enumerated().reduce(into: [:]) { $0[$1.offset] = $1.element }
}
}
let dict1 = someArray.indexedDictionary
print(dict1)
and just use this:
Swift 4:
let finalArray = someArray.enumerated().flatMap { arr.contains($0.offset) ? $0.element : nil }
Swift 4.1:
let finalArray = someArray.enumerated().compactMap { arr.contains($0.offset) ? $0.element : nil }
Update 2:
If you need a dictionary and not an array in the end use this:
Swift 4:
let finalDict = someArray.enumerated().flatMap { randomInts.contains($0.offset) ? ($0.offset, $0.element) : nil }.reduce(into: [:]) { $0[$1.0] = $1.1 }
Swift 4.1:
let finalDict = someArray.enumerated().compactMap { randomInts.contains($0.offset) ? ($0.offset, $0.element) : nil }.reduce(into: [:]) { $0[$1.0] = $1.1 }
Assume we have an array of optionals defined:
var arrayOfOptionals: [String?] = ["Seems", "like", "an", nil, "of", "optionals"]
I can force unwrap it in a short way: var arrayForCrash = arrayOfOptionals.map { $0! }
But that will make app to crash, is there any other short way(without explicitly unwrapping) how I can unwrap an array of optional?
This solution will get you a new array with all values unwrapped and all nil's filtered away.
Swift 4.1:
let arrayOfOptionals: [String?] = ["Seems", "like", "an", nil, "of", "optionals"]
let arrayWithNoOptionals = arrayOfOptionals.compactMap { $0 }
Swift 2.0:
let arrayOfOptionals: [String?] = ["Seems", "like", "an", nil, "of", "optionals"]
let arrayWithNoOptionals = arrayOfOptionals.flatMap { $0 }
Swift 1.0:
let arrayOfOptionals: [String?] = ["Seems", "like", "an", nil, "of", "optionals"]
let arrayWithNoOptionals = arrayOfOptionals.filter { $0 != nil }.map { $0! }
Since it is an array of optionals, it is possible some of the entries are nil. Instead of force unwrapping with !, use the nil coalescing operator to turns nils into empty strings.
let arrayOfOptionals: [String?] = ["This", "array", nil, "has", "some", "nils", nil]
let array:[String] = arrayOfOptionals.map{ $0 ?? "" }
// array is now ["This", "array", "", "has", "some", "nils", ""]
Although you can use flatMap { $0 } to remove nils, flatMap is actually a much more powerful function, and has an overloaded version which does something completely different (e.g. flatten [[Int]] to [Int]). If you're not careful, you may accidentally invoke the wrong function.
I would recommend using an extension on SequenceType to remove nils. If you use removeNils(), you'll be able to essentially do the following:
[1, nil, 2].removeNils() == [1, 2]
It works by making Optional conform to an OptionalType protocol which allows extending SequenceTypes that contain Optional values.
For more information see the original answer I posted.
I took #Cenny's answer and decided to make an operator out of it:
prefix operator <!> {}
prefix func <!> <T>(array: [T?]) -> [T] {
return array.filter{ $0 != nil }.map{ $0! }
}
I'm using it to parse an array of JSON objects and filter the ones that failed:
static func parse(j: JSONArray) -> [Agency]? {
return <!>j.map { self.parse($0) }
}
Update for Swift 2+:
Use flatMap operator and it'll only return non-nil objects
Swift 4
Easy to read and safe approach to filter nils of any sequence
protocol OptionalProtocol {
associatedtype Wrapped
var optional: Wrapped? { get }
}
extension Optional: OptionalProtocol {
var optional: Wrapped? {
return self
}
}
extension Sequence where Element: OptionalProtocol {
var removingOptionals: [Element.Wrapped] {
return self.compactMap { $0.optional }
}
}
Usage
let array: [Int?] = [1, 2, nil, 3, 4, nil]
print(array.removingOptionals) // prints [1, 2, 3, 4], has type [Int]
The more interesting, how to unwrap an optional array of optional values. It is important to deal when we are working with JSON, because JSON can potentially contain null value for an array of something.
Example:
{ "list": null }
// or
{ "list": [null, "hello"] }
To fill a Swift struct we may have a model:
struct MyStruct: Codable {
var list: [String?]?
}
And to avoid working with String?? as a first item we could:
var myStruct = try! JSONDecoder.init().decode(MyStruct.self, from: json.data(using: .utf8)!)
let firstItem: String? = s1.list?.compactMap { $0 }.first
With compactMap { $0 } we can avoid
let i2: String?? = s1.list?.first
compactMap { $0 } is an equivalent of filter { $0 != nil }. map { $0! }
How about:
import Foundation
var test: [String!] = ["this","is","a",nil,"test"]
for string in test {
if string != nil {
print(string)
}
}
Output is thisisatest.
In your case use [String!], if I understood you correctly.
Is there a faster/more concise way to get multiple indexes from an array besides looping, and appending? Maybe a one-liner functional variant of the following?
let names: [String] = ["John", "Mary", "Hugo", "Bill", "Andrea"]
let indexesToGet = [0, 1, 3]
var result: [String] = []
for i in 0..<indexesToGet.count {
result.append(names[indexesToGet[i]])
}
return result
//returns ["John", "Mary", "Bill"]
You can try like this.
let result = indexesToGet.map { names[$0] }
To prevents from indexOutOfBounds crash you can use flatMap.
let result = indexesToGet.flatMap { (names.count > $0) ? names[$0] : nil}
From Swift 4.1 use compactMap instead of flatMap.
let result = indexesToGet.compactMap { (names.count > $0) ? names[$0] : nil}
In Swift2, how can you do indexOf on arrays that contain optionals? The following example won't compile:
var strings: [String?] = ["hello", nil, "world"]
let index = strings.indexOf("world")
with the compiler complaining
"Cannot invoke indexOf with an argument list of type '(String)'"
A naive approach without indexOf would be:
let index: Int = {
for var i = 0; i < strings.count; i++ {
let s: String? = strings[i]
if s == "world" {
return i
}
}
return -1
}()
Isn't there any way to use the built-in indexOf function?
The same example however works for arrays with non-optionals:
var strings: [String] = ["hello", "world"]
let index = str.indexOf("world")
Or even simpler:
let strings: [String?] = ["hello", nil, "world"]
strings.indexOf{ $0 == "world" }
This works because == is defined for optionals as well
You can use an expression in "trailing closure" for indexOf:
var arr: [String?] = ["hello", nil, "world"]
let i = arr.indexOf() { $0 != nil && $0 == "world" }
Is there a cleaner way to get the last two items of an array in Swift? In general, I try to avoid this approach since it's so easy to be off-by-one with the indexes. (Using Swift 1.2 for this example.)
// Swift -- slices are kind of a hassle?
let oneArray = ["uno"]
let twoArray = ["uno", "dos"]
let threeArray = ["uno", "dos", "tres"]
func getLastTwo(array: [String]) -> [String] {
if array.count <= 1 {
return array
} else {
let slice: ArraySlice<String> = array[array.endIndex-2..<array.endIndex]
var lastTwo: Array<String> = Array(slice)
return lastTwo
}
}
getLastTwo(oneArray) // ["uno"]
getLastTwo(twoArray) // ["uno", "dos"]
getLastTwo(threeArray) // ["dos", "tres"]
I was hoping for something closer to Python's convenience.
## Python -- very convenient slices
myList = ["uno", "dos", "tres"]
print myList[-2:] # ["dos", "tres"]
With Swift 5, according to your needs, you may choose one of the following patterns in order to get a new array from the last two elements of an array.
#1. Using Array's suffix(_:)
With Swift, objects that conform to Collection protocol have a suffix(_:) method. Array's suffix(_:) has the following declaration:
func suffix(_ maxLength: Int) -> ArraySlice<Element>
Returns a subsequence, up to the given maximum length, containing the final elements of the collection.
Usage:
let array = [1, 2, 3, 4]
let arraySlice = array.suffix(2)
let newArray = Array(arraySlice)
print(newArray) // prints: [3, 4]
#2. Using Array's subscript(_:)
As an alternative to suffix(_:) method, you may use Array's subscript(_:) subscript:
let array = [1, 2, 3, 4]
let range = array.index(array.endIndex, offsetBy: -2) ..< array.endIndex
//let range = array.index(array.endIndex, offsetBy: -2)... // also works
let arraySlice = array[range]
let newArray = Array(arraySlice)
print(newArray) // prints: [3, 4]
myList[-2:]
Yes, I have an enhancement request filed asking for negative index notation, and I suggest you file one too.
However, you shouldn't make this harder on yourself than you have to. The built-in global suffix function does exactly what you're after:
let oneArray = ["uno"]
let twoArray = ["uno", "dos"]
let threeArray = ["uno", "dos", "tres"]
let arr1 = suffix(oneArray,2) // ["uno"]
let arr2 = suffix(twoArray,2) // ["uno", "dos"]
let arr3 = suffix(threeArray,2) // ["dos", "tres"]
The result is a slice, but you can coerce it to an Array if you need to.
in swift 5 you can use suffix for get objects from the last and use prefix for get objects from the first, here is an example:
let exampleArray = ["first text", "second text", "third text"]
let arr1 = exampleArray.suffix(2) // ["second text", "third text"]
let arr2 = exampleArray.prefix(2) // ["first text", "second text"]
The result is a slice, but you can coerce it to an Array if you need to.
In Swift 2, you can extend CollectionType. Here's an example (borrowing from Rob Napier's answer):
extension CollectionType {
func last(count:Int) -> [Self.Generator.Element] {
let selfCount = self.count as! Int
if selfCount <= count - 1 {
return Array(self)
} else {
return Array(self.reverse()[0...count - 1].reverse())
}
}
}
You can use it on any CollectionType. Here's Array:
let array = ["uno", "dos", "tres"]
print(array.last(2)) // [dos, tres]
Here's CharacterView:
let string = "looking"
print(string.characters.last(4)) // [k, i, n, g]
(Note that my example returns an Array in all cases, not the original collection type.)
More generic answer ...
let a1 = [1,2,3,4,5]
let a2 = ["1","2","3","4","5"]
func getLast<T>(array: [T], count: Int) -> [T] {
if count >= array.count {
return array
}
let first = array.count - count
return Array(array[first..<first+count])
}
getLast(a1, count: 2) // [4, 5]
getLast(a2, count: 3) // ["3", "4", "5"]
the last two items of an array in Swift
EDIT: first checks that myArray.count >= 2
let myArray2:Array? = myArray.count >= 2 ? [myArray[myArray.count-2], myArray[myArray.count-1]] : nil
Here it is wrapped in a function which takes the array and either returns an array containing the last two or else returns nil if the passed array does not contain at least two items.
func getLastTwo(myArray:[String]) -> [String]? {
return myArray.count >= 2 ? [myArray[myArray.count-2], myArray[myArray.count-1]] : nil
}
I doubt it's going to make you that much happier, but the math is certainly simpler:
func getLastTwo(array: [String]) -> [String] {
if array.count <= 1 {
return array
} else {
return array.reverse()[0...1].reverse()
}
}
Note that reverse() is lazy, so this isn't particularly expensive.
let items = [0, 2, 5, 3, 7, 6, 9, 10]
let count = items.count
let last2 = items[count - 2 ..< count] // [9, 10]
Swift4 solution:
let oneArray = ["uno"]
let twoArray = ["uno", "dos"]
let threeArray = ["uno", "dos", "tres"]
let arr1 = threeArray.suffix(from: threeArray.count-2) // ["dos", "tres"]
Other examples to clarify the functionality of Swift's built in function func suffix(from start: Int) -> ArraySlice<Element> are...
let arr2 = oneArray.suffix(from: 0) // ["uno"]
let arr3 = twoArray.suffix(from: 0) // ["uno", "dos"]
let arr4 = twoArray.suffix(from: 1) // ["dos"]
let arr5 = threeArray.suffix(from: 1) // ["dos", "tres"]
let arr6 = threeArray.suffix(from: 2) // ["tres"]