I have function returning the optional tuple
(Range<String.Index>?, Range<String.Index>?).
Then, I need to add this tuple to the array of tuples which I declares as
var arrayOftuples = [(Range<String.Index>, Range<String.Index>)]()
I am adding the tuple to the array like this
arrayOftuples += [mytuple]
It gives me note that the operator += cannot be applied to the operands
[(Range<String.Index>, Range<String.Index>)]
and
[(Range<String.Index>?, Range<String.Index>?)]
When I make the declaration of the array with optional
var arrayOftuples = [(Range<String.Index>?, Range<String.Index>?)]()
there is no more complains. But, at the end, I need to use the startIndex and endIndex from the tuples from the array, and when I try to get it like this
let myrange = arrayOftuples.first!.0.startIndex..< arrayOftuples.first!.0.endIndex
I have the complain that value of type
Range<String.Index>?
has no member startIndex.
As I can understand, if I want to get startIndex and endIndex from the tuples, I need to use the array without optionals,
var arrayOftuples = [(Range<String.Index>, Range<String.Index>)]()
but then I need somehow to add from optional tuples only that which are not (nil, nil). When adding the tuple like this
arrayOftuples += [mytuple!]
it is not accepting this. If I use the condition like this
if mytuple != (nil, nil)
{
arrayOftuples += [mytuple]
}
it is also not working. Complain is that operator != cannot be applied. How to solve the problem?
The functions returns optionals probably with a reason. You need to check if those optionals are not nil first, then unwrap them and insert them into the array. After that you shouldn't have any issues.
You can unwrap them like this
if let t1 = touple.0, t2 = touple.1 {
let unwraped = (t1, t2)
}
Related
I have an array with millions of tuple elements like:
var arr: ArrayBuffer[(String, String)] = ArrayBuffer[(String, String)]()
arr += (("Hamburg", "Street1"))
arr += (("Hamburg", "Street2"))
arr += (("Hamburg", "Street1")) // duplicate - remove
arr += (("Berlin", "StreetA"))
arr += (("Berlin", "StreetZ"))
arr += (("Berlin", "StreetZ")) // duplicate - remove
arr += (("Berlin", "StreetA")) // duplicate - remove
I would now like to have those duplicates within that array removed, where City AND Street are equal.
Something like:
arr.distinctBy(_._1&_._2) // doesn't work just for illustration
Is there a simple solution to it, how this can be done to get an output like:
(("Hamburg", "Street1"))
(("Hamburg", "Street2"))
(("Berlin", "StreetA"))
(("Berlin", "StreetZ"))
Since equals and hashCode are overridden for tuples you can use distinct which is effectively is distinctBy(identity):
val result = arr.distinct
Calling arr.toSet on your array will do what you require:
arr.toSet
res34: Set[(String, String)] = Set(
("Hamburg", "Street1"),
("Hamburg", "Street2"),
("Berlin", "StreetA"),
("Berlin", "StreetZ")
)
Tuples are case classes, so are provided with equals and hashCode methods to support comparisons.
If your use case is to ensure a collection contains no duplicates, you should generally use a set. This allows other readers of your code to infer that there are no duplicates in the collection.
I have a following code, which copies an array of Rider objects, and appends a new Rider object if it exists.
let riders:[Rider] = getRiders()
let newRider:Rider? = mayGetNewRider()
var ridersPlus = riders
if let rider = newRider {
ridersPlus.append(rider)
}
I am looking for a better (simpler and easier to read) way to write this logic, which also allows me to define ridersPlus as "let" variable.
I am looking for something like below (which is invalid, because I made up the ??? syntax, which produces an empty array of newRider is nil).
let riders:[Rider] = getRiders()
let newRider:Rider? = mayGetNewRider()
let ridersPlus = riders + [newRider???]
How about
let ridersPlus = riders + [newRider].compactMap {$0}
(Note that before Swift 4, compactMap would be called flatMap. You didn't say what Swift version you are using.)
You do it with map and the nil coalescing operator ??:
let ridersPlus = riders + (newRider.map {[$0]} ?? [])
map when called on an Optional value evaluates the given closure when the Optional instance is not nil, passing the unwrapped value as a parameter. If the Optional is nil, the result of the map is nil. Combining that with the nil coalescing operator, the resulting Optional array can be unwrapped or replaced with [] and then added to the riders array.
I have an Array of Image links -
let alamofireSource = [AlamofireSource(urlString: Img1!)!, AlamofireSource(urlString: Img2!)!,
AlamofireSource(urlString: Img3!)!, AlamofireSource(urlString: Img4!)!]
slideshow.setImageInputs(alamofireSource)
some posts have only one image or two or three, and so on. so, sometimes image 2 (for example) is nil, In that case, I don't want it to be added to the array, is that possible?
You can try ( Swift 4 )
let arr = [img1,img2].compactMap{$0}.map{AlamofireSource(urlString:$0)!}
or
let arr = alamofireSource.compactMap{$0}
for Swift 3
let arr = alamofireSource.flatMap{$0}
so, sometimes image 2 (for example) is nil, In that case, I don't want
it to be added to the array, is that possible?
Yes it is. Although I would go with Sh_Khan's suggestion to use the compactMap method to achieve it, but it would be useless for your current case:
Based on your code snippet, I'd assume that alamofireSource of type [AlamofireSource], but not [AlamofireSource?] and that's because you are forcibly unwrap its elements (by adding ! to each of its elements). So far alamofireSource doesn't contain nils (actually it could be more danger than just a declaration, your app might crash!)
So first of all, I would recommend to remove the ! from alamofireSource:
let alamofireSource = [AlamofireSource(urlString: Img1!),
AlamofireSource(urlString: Img2!),
AlamofireSource(urlString: Img3!),
AlamofireSource(urlString: Img4!)]
which means let it be as [AlamofireSource?], therefore you would gain the benefit of using compactMap(_:):
Returns an array containing the non-nil results of calling the given
transformation with each element of this sequence.
As:
let alamofireSourceWihoutNils = alamofireSource.compactMap { $0 }
Assuming you put your Optional url strings into an array, say urlStrings (of type [String?]), you can construct alamofireSource according to (Swift 4):
let alamofireSource = urlStrings.compactMap { $0.map(AlamofireSource.init) }
Which make use of the map(_:) operator of Optional and compactMap(_:) to unwrap the two-level optionality.
Details
Your example contains two levels of optionality:
The optional ImgX arguments of type String? - henceforth referred to and named as img1, ..., img4, as CapitalFirstLetter names are reserved for e.g. types, not type instances.
The failable initilizer init?(urlString: String, placeholder: UIImage? = nil) of AlamofireSource.
First of all, lets gather the optional image links (imgX) into an array
let urlStrings = [url1, url2, url3, url4] // [String?]
Swift 4
You can combine the map(_:) operator of Optional with compactMap(_:) to safely unwrap and make use of the .some entires of urlStrings, thereafter collect the successful invocations of the failable initializer of AlamofireSource:
let alamofireSource = urlStrings.compactMap { $0.map(AlamofireSource.init) }
// or, use a named closure argument
let alamofireSource = urlStrings.compactMap { str in str.map(AlamofireSource.init) }
Swift 3
If using Swift 3, replace the compactMap(_:) invocation above with flatMap(_:):
let alamofireSource = urlStrings.flatMap { $0.map(AlamofireSource.init) }
// or, use a named closure argument
let alamofireSource = urlStrings.flatMap { str in str.map(AlamofireSource.init) }
So in a swift playground file, I am trying to execute the following closure:
var list = [5, 4, 3]
var Arraymultiplier = {(list:Array) -> Array in
for value in list {
value*2
return list
}
}
Arraymultiplier(list)
When I do this though, I get an error saying that the generic type Array must be referenced in <..> brackets, but when I put the brackets, I get another error.
What's the right way to declare the array type as an input and a return?
Array is a generic type, meaning that it expects to see the actual type of the members of the array to be specified within < > immediately following Array:
var arrayMultiplier = {(list: Array<Int>) -> Array<Int> in
// do whatever you want here
}
Or, in the case of arrays, there is a convenient syntax that uses the [ ] characters and omits the need for Array reference at all:
var arrayMultiplier = {(list: [Int]) -> [Int] in
// do whatever you want here
}
I'm not sure what the original code sample was trying to do, but it looks like you might have been trying to build a new array with each item multiplied by 2. If so, then you might do something like:
let inputList = [5, 4, 3]
let arrayMultiplier = { (list: [Int]) -> [Int] in
var results = [Int]() // instantiate a new blank array of `Int`
for value in list { // iterate through array passed to us
results.append(value * 2) // multiply each `value` by `2` and add it to the `results`
}
return results // return results
}
let outputList = arrayMultiplier(inputList)
Or, obviously, you could efficiently achieve similar behavior using the map function:
let outputList = inputList.map { $0 * 2 }
for example:
let myArray:[] = []
or
let myArray = []
The first one is not possible (it will complain about expected element type) If you don't know the element type you can use AnyObject but if you know the type of it you have to put it there (Int,Double,String, AnyObject, etc...).
var myArrayOfDoubles:[Double] = []
The second one (when omitting the type) is OK ONLY if you initialize it with some values but If you try it with an empty array you won't be able to append anything (at least using Playground) saying that NSArray does not have a member named append.
var myArrayOfInts = [1,2,3,4,5] // [Int]
var myArrayOfAnyObject:[AnyObject] = [] // [AnyObject]
And finally last but not least you have to define it as var because if you define it using let it will stay empty forever :)
Yes, you can, it can be Any or Anyobject...
example:
var noTypeArray = [Any]()
If you want to fill the array eventually it may be var, no let, there's no point otherwise.
No. If you don't know what will go in use this:
var myArray = [Any]()
Apple has introduced a Type-GeStaPo and you must type anything that's not up the tree at count three.
To add to this use
myArray.append("this")
myArray.append(1)
myArray.append(myObject)