If Statement with Array Variables Out of Range Swift - arrays

I'm trying to search a user's contacts but one of my if statements is broken. It checks if the character at a certain index of the input matches the character of the same index of the givenName, familyName, and phoneNumber. My problem is that sometimes the number of characters entered is more than the number of characters in the givenName, familyName, or phoneNumber. This makes my if statement compare the character at a certain index of the input and the character at an index that doesn't exist. For instance, it compares charInput[2] to charGivenName[2] but charGivenName only has values at charGivenName[0] and charGivenName[1]. Since charGivenName[2] doesn't exist, my apps crashes.
Does anyone know how to fix this?
#IBAction func contactTextFieldChanged(_ sender: Any) {
if contactTextField.text != "" {
contactTableView.isHidden = false
let request = CNContactFetchRequest(keysToFetch: keys as! [CNKeyDescriptor])
do {
try contactStore.enumerateContacts(with: request){
(contact, stop) in
self.contacts.append(contact)
for phoneNumber in contact.phoneNumbers {
if phoneNumber.value.stringValue != ""{
let charGivenName = Array(contact.givenName)
let charFamilyName = Array(contact.familyName)
let charNumber = Array(phoneNumber.value.stringValue)
let charInput = Array(self.contactTextField.text!)
var matchBool = false
for inputCount in (0...charInput.count - 1) {
if charNumber[inputCount] == charInput[inputCount] || charGivenName[inputCount] == charInput[inputCount] || charFamilyName[inputCount] == charInput[inputCount]{
matchBool = true
} else {
matchBool = false
break
}
if matchBool == true {
print("\(contact.givenName) \(contact.familyName) \(phoneNumber.value.stringValue)")
}
}
}
}
}
} catch {
print("Error fetching contacts")
}
}
if contactTextField.text == ""{
contactTableView.isHidden = true
}
}

Related

String Duplicate count

I am trying to prints counts of a duplicate from an input string through the use of hash map. I am not sure why solution is not working. I come from a python background
//Write an efficient program to print all the duplicates and their counts in the input string
func letters(inputs: String)->[Character:Int] {
var result = [Character:Int]()
for input in inputs {
if let value = result[input] {
return [input : value]
}
else {
result[input] = (result[input] ?? 0)+1
}
}
return [:]
}
letters(inputs:"geeksforgeeks")
["e": 1]
Try this:
func letters(inputs: String) -> [Character:Int] {
var result = [Character:Int]()
for input in inputs{
if let value = result[input] {
result[input] = value + 1
}
else{
result[input] = 1
}
}
return result
}

Adding string to array

When i am parsing through the string from the url, I append each new line to an array. However I only want to add if the field is not empty. So if the column[5] is an empty string I don't append it to the array. For example I have two lines of strings:
1,2,3,4,5,
1,2,3,4,5,6
I only want to append when there are 6
However I am getting a index out of range error on the if column[5] == "" line
func readDataFromURL(url: String) -> String?{
if let url = URL(string: url)
{
do {
var contents = try String(contentsOf: url)
contents = contents.replacingOccurrences(of: "\r", with: "")
csv(data: contents)
return contents
} catch {
print("File error \(url)")
return nil
}
}
return nil
}
func csv(data: String) -> [[String]] {
var result: [[String]] = []
let rows = data.components(separatedBy: "\n")
for row in rows {
let columns = row.components(separatedBy: ",")
if columns[5] == "" {
continue
} else {
result.append(columns)
}
}
return result
}
Your current code will crash if num of elements is less than 6 , Replace
if columns[5] == "" {
continue
} else {
result.append(columns)
}
with
if columns.count > 5 && columns.last != "" {
result.append(columns)
}

Is There a Better Way To Filter An Array With Multiple Conditions

I am using a dropdown menu help filter an array and then place the data from the array back into a collectionView but, when I attempt to attempt to run the function that should sort and reload the collectionView, the screen goes blank.
I've tried to make set a baseline and then filter the array.
extension RestaurantDetails: menuViewDelegate {
func didChangeMealSize(mealSizeText: String) {
self.mealSize = mealSizeText
print("Usage", self.mealSize)
}
func didChangeDrink(drinkName: String) {
self.drink = drinkName
print("drink", self.drink)
}
func didChangeProductType(productType: String) {
self.productFilter = productType
print("Filter", self.productFilter)
}
func didchangeSwitch(FriesSwitch: UISwitch) {
if FriesSwitch.isOn == true {
self.FriesOnly = true
print("FRIES Only")
} else {
self.FriesOnly = false
print("Drink & FRIES")
}
func didendSelection(button: UIButton) {
print("ran Here")
if (SegmentType == "All" && FriesSwitch == false && mealSize == RestaurantDetails.allProductIdentifier && productFilter == RestaurantDetails.allProductIdentifier && price == 0.0) {
filteredProducts = products
} else {
filteredProducts = products.filter { ($0.usage?.lowercased() ?? "") == bestFor}
}
productCollection.reloadData()
}
I want to filter by selected: Meal Size, Drink, and With Or Without Fries. When didendSelection is run, All the properties of the selected variables print but, the collectionView comes back empty.

how do i make sure users can't enter in duplicates?

Spent all day on this one. I have an array of expenses that populates my tableview. Users can select a row from the tableview to edit the expense, which includes the name, the amount, the due date, etc.
I don't want users to be able to enter in a duplicate name. What I mean is, I want to check their input against the array to make sure the name doesn't already exist. This sounds simple to me, but for some reason I can't get it to work.
This is what I've tried:
CODE #1:
var duplicateCount = 0
for item in Expense.expensesArray.filter({ $0.ownerName == currentUserName }).filter({ $0.category == expense?.category }) {
if item.expenseName != expense?.expenseName {
print("no duplicates found in \(item.expenseName). moving on")
} else if item.expenseName == expense?.expenseName {
duplicateCount += 1
print("duplicate found in \(item.expenseName)")
}
}
CODE #2: (which is pretty similar to #1)
var duplicatesAmount: Int = 0
for expense in Expense.expensesArray.filter({ return $0.ownerName == currentUserName }).filter({ $0.category == expense?.category }) {
if expense.expenseName.lowercased() == expenseNameTextField.text?.lowercased() {
duplicatesAmount += 1
print("POTENTIAL DUPLICATE #\(duplicatesAmount): ",expense.expenseName)
}
}
// if there is more than one expense in the array with the same name, return true
if duplicatesAmount > 1 {
return true
} else {
return false
}
EDIT: The code runs whether there's a duplicate or not. It never sees the duplicate, even if I purposely put one in.
UPDATE: This worked.
if expense?.expenseName == expenseNameTextField.text {
updateExpenseInfo()
} else {
// iterate over the array and see if new name is found anywhere
let dupArray = Expense.expensesArray.filter({ $0.ownerName == currentUserName && $0.category == expense?.category && $0.expenseName == expenseNameTextField.text })
if dupArray.isEmpty {
updateExpenseInfo()
} else {
duplicateNameAlert()
}
}
You can do it like this:
struct Object {
let name: String
let amount: Int
init(name: String = "", amount: Int = 0) {
self.name = name
self.amount = amount
}
}
let a = Object(name: "Foo", amount: 10)
let b = Object(name: "Bar", amount: 20)
let array = [a, b]
func contains(value: String) -> Bool {
return array.filter({ $0.name == value }).isEmpty
}
print(contains(value: "Foo")) // true
print(contains(value: "Test")) // false
So you basically just add the contains function and return array.filter({ $0.name == value }).isEmpty. If it returns true then save otherwise donĀ“t save. The value you pass it the entered value.

Having trouble with syntax in swift looping through an array

I'm trying to figure out how to loop through this usernames array, but am not sure the syntax. I am using swift in xcode
I currently have:
// Read text file
if let filepath = NSBundle.mainBundle().pathForResource("barbers", ofType: "txt")
{
do
{
//let contents = try NSString(contentsOfFile: filepath, usedEncoding: nil) as String;
//print(contents);
let text = try NSString(contentsOfFile: filepath, usedEncoding: nil) as String;
// Create character array & parse
let usernames = text.characters
.split { $0 == "\n" }
.map { String($0) }
.map { String($0.characters.split(" ")[0]) }
// Print Users
print(usernames);
// Test
}
catch
{
// Catch error?
}
}
else
{
// Print error to console log
print("Error: Could not find text file - something went wrong");
}
My question is: How can I loop through my usernames array?
I just dont know the swift syntax
I'm looking for something like
for(int i =0; i < usernames.size(); i ++ )
{
if(usernames[i] == USER)
{
b = true;
break;
}
b = false;
}
UPDATES:
Ok so I've figured out how to loop through but now I'm having troubles
I made a global variable
var abc = "";
I then did
let abc = usernames;
now when I try to do this
// Test
for i in abc.characters
{
print("abc array contents: " + i);
if(i == theUser)
{
print("Barber");
barb = true;
break;
}
print("USER " + theUser);
barb = false;
print("\n");
}
I get the error
Binary operator '+' cannot be applied to operands of type 'String' and 'Character'
and
Binary operator '==' cannot be applied to operands of type 'Character' and 'String'
All of these above work, but my favorite Swifty for loop is
for index in 0..< usernames.count {
//your code here
//to get an object at a specific index you call usernames[index]
}
In response to your updated question I believe you need to cast your character as a string. Something like
let myCharacterAsAString = String(i)
print("abc array contents: " + myCharacterAsAString);
if(myCharacterAsAString == theUser)
{
print("Barber");
barb = true;
break;
}
print("USER " + theUser);
barb = false;
print("\n");
}
for username in usernames
{
if(username == USER)
{
b = true;
break;
}
b = false;
}
or if you need access to current item's index:
for (index, username) in usernames.enumerate()
{
// same body as above
}
I believe latest versions of Swift have done away with the C-style for-loop.
This might not be super helpful but the way to iterate in Swift would likely be with a for-in loop
for username in usernames
{
if username == USER
{
b = true
break
}
b = false
}

Resources