'Int' is not convertible to 'Range<Int> - arrays

I have an array of PFObjects and I've created a new array: restaurantNames to store all their names. Now I'm trying to print the names on UIPageView, but I get the error:
'Int' is not convertible to 'Range<Int>'
Code:
private func getItemController(itemIndex: Int) -> PageItemController? {
let restaurantNames = finalRestaurantArray.map { $0.objectForKey("Name") }
if itemIndex < finalRestaurantArray.count {
let pageItemController = self.storyboard!.instantiateViewControllerWithIdentifier("ItemController") as PageItemController
pageItemController.itemIndex = itemIndex
pageItemController.restaurantName = restaurantNames[itemIndex]
//pageItemController.imageName = finalRestaurantArray[itemIndex]
return pageItemController
}
return nil
}
The actual PFObject array looks like this (restaurantNames contains the array of just names):
[<Restaurant: 0x7feb9252cfc0, objectId: LA74J92QDA, localId: (null)> {
Name = "Restaurant 1";
City = "New York";
Closed = 1;
Country = "United States";
FoodType = Japanese;
}, <Restaurant: 0x7feb926afa00, objectId: 0aKFrpKN46, localId: (null)> {
Name = "Restaurant 2";
City = "San Francisco";
Closed = 1;
Country = "United States";
FoodType = Italian;
}]
Pastebin: http://pastebin.com/U63TFMRV

This line is confusing to the compiler:
let restaurantNames = finalRestaurantArray.map { $0.objectForKey("Name") }
This creates an [AnyObject?] which is a notoriously difficult for the compiler to deal with, and the errors you get are often confusing (because of various promotions and overloads).
Step 1 is that you should avoid AnyObject whenever possible. So finalRestaurantArray should be an array of the actual objects rather than [AnyObject], or even dictionaries. Then your map would return a [String] like I believe you want it to.
You can hack this into place like this:
// Avoid this
let restaurantNames = finalRestaurantArray.map { $0.objectForKey("Name") as String }
And if anything goes wrong, it'll crash. Don't do that. Get your data out of AnyObject as fast as you can (and get it out of Dictionary as fast as you can, too), and turn it into real model objects that can guarantee they'll return a value.

Related

Using returned value (array of Strings) in another Swift file

Apologize for a complete newbie question. This was the original array of Strings I wrote:
let fruit = ["apple1.jpg", "apple2.jpg", "apple3.jpg", ..... "apple10.jpg"]
First, I made a function in a separate Swift file (attached to the project) to replace above array, as the array's content might be changed based on several input factors later:
class Fruits {
let fruit = "apple"
func fruitName() -> [String] {
let arrayA = (1...10).map({ "\(fruit)\($0).jpg" })
return arrayA
}
}
}
This is everything written on Fruits.swift file. And then, back to original file, I wanted to replace the original let fruit = ["", "", ...] to something like let fruit = Fruits.fruitName() - by loading the returned arrayA. But it was a bit confusing to understand how to use returned String Array values in a different file, inside of a different Class bracket. I tried something like let fruits = Fruits(), let fruit = fruits.fruitName(), etc but it doesn't seem to successfully replace the original array code. I still need to create the constant let fruit = part. Is there any way to load the returned value in a separate file? Much appreciated. <3
If you want a property of a class to be directly accessible from anywhere in your code, you can make it static:
class Fruits {
static let fruit = "apple"
static func fruitName() -> [String] {
let arrayA = (1...10).map({ "\(fruit)\($0).jpg" })
return arrayA
}
}
// usage:
let fruits = Fruits.fruitName()
Depending on your specific situation, you could even not have a class and have a global function that takes the fruit as a parameter:
func fruitNames(fruit: String) -> [String] {
let arrayA = (1...10).map({ "\(fruit)\($0).jpg" })
return arrayA
}
// usage:
let fruits = fruitNames(fruit: "apple")

How to map an array of integers as keys to dictionary values

If I have the following array and I want to create a string array containing the door prizes by mapping the mysteryDoors array as keys for the dictionary, and get the corresponding values into a new array.
Thus I would get a string array of ["Gift Card", "Car", "Vacation"] how can I do that?
let mysteryDoors = [3,1,2]
let doorPrizes = [
1:"Car", 2: "Vacation", 3: "Gift card"]
You can map() each array element to the corresponding value in
the dictionary. If it is guaranteed that all array elements are
present as keys in the dictionary then you can do:
let mysteryDoors = [3, 1, 2]
let doorPrizes = [ 1:"Car", 2: "Vacation", 3: "Gift card"]
let prizes = mysteryDoors.map { doorPrizes[$0]! }
print(prizes) // ["Gift card", "Car", "Vacation"]
To avoid a runtime crash if a key is not present, use
let prizes = mysteryDoors.flatMap { doorPrizes[$0] }
to ignore unknown keys, or
let prizes = mysteryDoors.map { doorPrizes[$0] ?? "" }
to map unknown keys to a default string.
If you have to use map, then it would look something like the following:
let array = mysteryDoors.map { doorPrizes[$0] }
After re-reading the Apple Doc example code and changing it to what I need. I believe this is it (Almost). Unfortunately it is now in string format with new lines...
let myPrizes = doorPrizes.map { (number) -> String in
var output = ""
output = mysteryDoors[number]!
return output;
}

Swift 3 - Difference between two arrays of dictionary

I have two arrays of dictionaries:
let arrayA = [["name1": "email1"], ["name2": "email2"]]
let arrayB = [["name1": "email1"], ["name3": "email3"]]
I want to compare them and get another two arrays: arrayC should have the elements in arrayA but not in arrayB, and arrayD should have the elements in arrayB but not in arrayA:
let arrayC = [["name2": "email2"]]
let arrayD = [["name3": "email3"]]
How can I do this taking into the consideration large arrays?
Here you go
let arrayA = [["name1": "email1"], ["name2": "email2"]]
let arrayB = [["name1": "email1"], ["name3": "email3"]]
let arrayC = arrayA.filter{
let dict = $0
return !arrayB.contains{ dict == $0 }
}
let arrayD = arrayB.filter{
let dict = $0
return !arrayA.contains{ dict == $0 }
}
I know this answer may be complicating things and that you can use filter but...have you considered using Sets instead of Arrays?
Sets can give you operations for finding elements in setA but not in setB or elements in setA and setB out of the box.
There are a few caveats about sets though. As it says in The Swift Programming Guide
A set stores distinct values of the same type in a collection with no defined ordering. You can use a set instead of an array when the order of items is not important, or when you need to ensure that an item only appears once.
notice from the above:
Distinct: Meaning no duplicates
No definded ordering: Means that you cannot expect your sets to be in order
Also, notice this (also from The Swift Programming Guide):
A type must be hashable in order to be stored in a set—that is, the type must provide a way to compute a hash value for itself.
If you can live with that...then sets are a fine solution I think.
Here is an example...I created a simple Email struct and made that implement Hashable:
struct Email {
let name: String
let email: String
}
extension Email: Hashable {
var hashValue: Int {
return "\(name)\(email)".hashValue
}
static func ==(lhs: Email, rhs: Email) -> Bool {
return lhs.name == rhs.name && lhs.email == rhs.email
}
}
And that can then be used like so:
let arrayA = [Email(name: "name1", email: "email1"), Email(name: "name2", email: "email2")]
let arrayB = [Email(name: "name1", email: "email1"), Email(name: "name3", email: "email3")]
let setA = Set(arrayA)
let setB = Set(arrayB)
let inBothAAndB = setA.intersection(setB) //gives me an Email with "name1", "email1"
let inAButNotB = setA.subtracting(setB) //gives me an Email with "name2", "email2"
let inBButNotA = setB.subtracting(setA) //gives me an Email with "name3", "email3"
So...I don't know if that confuses things for you or makes things harder or maybe impossible (if you're data can contain more than one element with the same name and email for instance) but...I just thought you should consider sets :)
Hope that helps you.

"Extra argument in call" error when using zip() to iterate over multiple arrays

I'm trying to iterate over multiple arrays then place everything into one other array.
This is my class that I'm going to loop into:
class Place {
var names = [String]()
var messages = [String]()
var latidudes = [Double]()
var longitudes = [Double]()
var locations = [CLLocationCoordinate2D]()
}
And this is my function:
private func placesArrayLoop() {
let CoffeeShopNames = ["aCoffee","bCoffee", "cCoffee"]
let messages = ["message0", "message1", "message2"]
let latitudes = [40.232320, 40.232321, 40.232322]
let longitudes = [-95.388069, -95.388068, 95.388067]
for (name, message, latitude, longitude) in zip(CoffeeShopNames, messages, latitudes, longitudes) {
let place = Place()
place.names.append(name)
place.messages.append(message)
place.latitudes.append(latitude)
place.longitudes.append(longitude)
}
}
It is giving me the error, "extra argument in call pointing to latitudes in the zip array line. I'm assuming it's a syntax error new to swift 3, but I've looked around and cant find how to fix it. But the code bellow works...
let strArr1 = ["Some1", "Some2", "Some3"]
let strArr2 = ["Somethingelse1", "Somethingelse2", "Somethingelse3"]
for (e1, e2) in zip(strArr1, strArr2) {
print("\(e1) - \(e2)")
}
So now I'm really confused.
The zip() function only takes two arguments (hence why your second example works).
http://swiftdoc.org/v3.0/func/zip/
You are trying to pass it four arguments.

Swift: associative array with multiple keys:values

I am not expert in Swift and I have been using it for few months to build Mac Apps. I would like to represent in memory a data structure like that of PHP associative arrays but in Swift. Let's imagine that I have a table of data to load in memory with the following fields/records:
ID Surname Name
1 XXX YYY
2 ZZZ WWW
3 JJJ KKK
What I would like to obtain is an associative array like the one I would be able to obtain in PHP:
$arr[1]["Surname"] = "XXX"
$arr[1]["Name"] = "YYY"
$arr[2]["Surname"] = "ZZZ"
$arr[2]["Name"] = "WWW"
I just cannot find the right data structure in Swift to obtain the same result. I tried with the following piece of code:
class resObject: NSObject {
private var cvs = [Int: [String: String]]()
override init() {
self.cvs[0] = ["Name" : "XXX"]
self.cvs[0] = ["Surname" : "YYY"]
self.cvs[1] = ["Name" : "ZZZ"]
self.cvs[1] = ["Surname" : "WWW"]
for (key, arr) in cvs {
let sur = arr["Surname"]
let nam = arr["Name"]
println("Row \(key) - Surname: \(sur), Name: \(nam)")
}
super.init()
}
}
It looks to me pretty close, but it does not work. What I get in the output is the following (I don't care about the "Optional(s)":
Row 0 - Surname: Optional("XXX"), Name: nil
Row 1 - Surname: Optional("ZZZ"), Name: nil
I tried to make some tests in debug and I noticed that the data that are saved in memory are just that of the last key:value pair used (i.e. if I assign Surname first and Name second I get Surname as nil and Name with the correct value).
Please consider that, as in the example, I don't know the data structure when I declare the variable, so I declare it empty and fill it programmatically later.
I don't know if it is just me not declaring the data structure correctly, or if it is Swift that does not allow to do that. Any help will be greatly appreciated.
Thanks a lot.
Regards,
Alessio
One way is a Dictionary of structs. Consider:
struct Person {
var firstName: String
var lastName: String
}
var peopleByID = [ Int: Person ]()
peopleByID[1] = Person(firstName: "First", lastName: "Last")
peopleByID[27] = Person(firstName: "Another", lastName: "LastName")
var myID = 1 // Try changing this to 2 later
if let p = peopleByID[myID] {
println("Found: \(p.firstName) with ID: \(myID)")
}
else {
println("No one found with ID: \(myID)")
}
You can then update the structure:
peopleByID[1].firstName = "XXX"
peopleByID[27].lastName = "ZZZ"
You can iterate freely:
for p in peopleByID.keys {
println("Key: \(p) value: \(peopleByID[p]!.firstName)")
}
Note that a mere array of [Person] isn't so hot, because the IDs:
-- may not be Ints, but are often Strings
-- even if they remain Ints, an array takes up storage in proportion to the highest numbered index, whereas a Dictionary only takes up storage in proportion to the number of stored objects. Imagine storing just two ID's: 523123, and 2467411.
EDIT
It seems like you don't know the attributes ahead of time that will go into each Person object. That's odd, but you should then do:
struct Person {
var attributes = [String : String]() // A dictionary of String keys and String values
}
var peopleByID = [ Int : Person ]()
// and then:
var p1 = Person()
var p2 = Person()
p1.attributes["Surname"] = "Somename"
p1.attributes["Name"] = "Firstname"
p2.attributes["Address"] = "123 Main St."
peopleByID[1] = p1
peopleByID[2] = p2
if let person1 = peopleByID[1] {
println(person1.attributes["Surname"]!)
for attrKey in person1.attributes.keys {
println("Key: \(attrKey) value: \(person1.attributes[attrKey]!)")
}
}

Resources