"hasPrefix" not working in Swift - arrays

I have an array of dictionary & I try to filter with prefix from using one of the key as follow:
let b = [["id":1,"name":"India"],["id":2,"name":"america"],["id":3,"name":"africa"],["id":4,"name":"indonesia"],["id":5,"name":"jakarta"],["id":6,"rec_name":"Zimba"]]
let g = b.filter({String(describing: $0["name"]).hasPrefix("I")})
print(g) //retun Empty array
If I try with contains then it working fine
or
If I try with only pure String array then also it working fine
Thank you,

Since your array (b) contains dictionaries where name is not always present (you have an object with rec_name), you could modify your filter to something like this:
let g = b.filter {
guard let name = $0["name"] as? String else { return false }
return name.hasPrefix("I")
}
and thus making sure that only dictionaries with a value for that key are matched by your filter
Fun fact: The reason why the original code doesn't work (as Martin points out) is pretty obvious when we do something like this:
let g = b.map({String(describing: $0["name"])})
print(g)
Which prints:
["Optional(\"India\")", "Optional(\"america\")", "Optional(\"africa\")", "Optional(\"indonesia\")", "Optional(\"jakarta\")", "nil"]

Please check with this.
let b = [["id":1,"name":"India"],["id":2,"name":"america"],["id":3,"name":"africa"],["id":4,"name":"indonesia"],["id":5,"name":"jakarta"],["id":6,"rec_name":"Zimba"]]
let g = b.filter({String(describing: $0["name"] as? String ?? "").hasPrefix("I")})
print(g)

Try this code you'll get the proper solution.
let b = [["id":1,"name":"India"],["id":2,"name":"america"],
["id":3,"name":"africa"],["id":4,"name":"indonesia"],["id":5,"name":"jakarta"],
["id":6,"rec_name":"Zimba"]]
let g = b.filter({($0["name"] as? String ?? "").hasPrefix("I")})
print(g)

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")

Search Multiple Words (or Characters) in String Array (swift)

I am developing an application for words.
My problem resembles the problem: this
But, I want to do the search in the string array.
let myArr: [String] = ["BERLIN","ISTANBUL","TOKYO","NEWYORK","PRAGUE","WIEN"]
let findChrs = ["I","N"]
// myArr.contains(findChrs) //so error
I want to: return 3 or "BERLIN","ISTANBUL" and "WIEN" (Contains "I" and "N")
I tried it, but it's too long...(I look individually. Too many words.):
for i in 0...myArr.count - 1 {
let success = !findChrs.contains(where: { !myArr[i].contains($0) })
if success {
print(myArr[i])
}
}
Is there an easier way? Thank you so much.
There's a swifty way to solve your problem
I started with using just one filter on the myArr array using hardcoded search terms
let filteredStrings : [String] = myArr.filter({
return $0.contains("I") && $0.contains("N")
})
but thats going to help only if your findChars are always going to be I and N only.
Later I realized how to do it without hardcoding the find char characters:
ANSWER 1
let myArr: [String] = ["BERLIN","ISTANBUL","TOKYO","NEWYORK","PRAGUE","WIEN"]
let findChrs = ["I","N"]
let filteredStrings : [String] = myArr.filter({ (aString) in
let hasChars = findChrs.filter({(bString) in
return aString.contains(bString)
})
print(hasChars)
return hasChars.count == findChrs.count
})
print(filteredStrings)
Instead of using $0, I think in the second chunk of code, its easier to understand whats happening with aString and bString.
Do check the code in a playground and see how this code works. If you haven't used the higher order functions, it can be a little daunting to understand filters without a playground and the print statements.
Update:
Was just thinking about this problem and I gave this alternate approach a try, using sets, map and filter. It is super swifty, and can be difficult to read/understand:
ANSWER 2, concise
let myArr: [String] = ["BERLIN","ISTANBUL","TOKYO","NEWYORK","PRAGUE","WIEN"]
let findChrs = ["I","N"]
let finderSet:Set<String> = Set(findChrs)
let filteredArray = myArr.filter {
return Set($0.characters.map({String($0)})).intersection(finderSet).count == findChrs.count
}
For the sake of readability and ease of understanding, here's what is happening:
Answer 2, verbose
let filteredArray = myArr.filter { (aString) -> Bool in
//for each string in myArr, convert it into an array of string chars
let stringArray = aString.characters.map({aCharacter in
String(aCharacter)
})
//convert string array into a set
let aSet = Set(stringArray)
// find the intersection (common elemnts from aSet and finderSet)
let intersect = aSet.intersection(finderSet)
//return true if aString has all of findChrs elements
return intersect.count == findChrs.count
}
Both Answer 2 'concise' and 'verbose' will give you the same results.
Based on some simple code execution time check, it looks like Answer 1 is ~3x faster than Answer 2. So, Answer 1 is still a better choice and probably easier to understand.
Hope this helps anyone reading the answer understand filter and map!
You could also use a set for the filter provided you're not looking for patterns that contain repeated letters:
let myArr: [String] = ["BERLIN","ISTANBUL","TOKYO","NEWYORK","PRAGUE","WIEN"]
let findChrs = Set<Character>(["I","N"]) // let findChrs = Set("IN")
let matchingCities = myArr.filter{ findChrs.isSubset(of:$0) }

How to Get Value from Array to Variable Swift

I have a Questions
I want to move Value in array to Variable
ex.
[1,2,3] = array
i want to get "1" to Variable
Var = 1 <= Which "1" is Value in array
My code :
//Loop For Seach Value
for result in 0...DataSearch.count-1 {
let Object = DataSearch[result] as! [String:AnyObject];
self.IDMachine_Array.append(Object["IDMac"] as! String!);
self.Password_Array.append(Object["password"] as! String!);
self.Conpassword_Array.append(Object["password_con"] as! String!);
self.Tel_Array.append(Object["Tel"] as! String!);
self.Email_Array.append(Object["Email"] as! String!);
self.Email = String(self.Email_Array);
}
I try Value Email = Email_Array
Result print :
[xxxx#xxxx.com]
but i want Result is :
xxxx#xxxx.com -> without []
Please Help me please.
Thank you.
Sorry if my solution is wrong.
Just get the first element from the array?
self.Email = self.EmailArray.first!
(this is the same as self.Email = self.EmailArray[0])
NB: first! or [0] will both crash if the array is empty. The original question uses as! so obviously just need this to work. However, if you wanted safety you would use something like
if let email as self.EmailArray.first {
self.Email = email
}
or
self.Email = self.EmailArray.first ?? "no email found"

Adding a string from UserDefaults into an already made array Swift 3

I've got my users first name and I've set it in a UserDefault and I call it like so..
let firstName = UserDefaults.standard.object(forKey: "firstName")
Then I have an array of strings and I would like to add the users first name into that..
var arrayOfTitle = ["HEY", "FIND EVENTS CLOSE TO YOU", "BOOK"]
I've tried what I would think it should look like which is
var arrayOfTitle = ["HEY \(firstName)", "FIND EVENTS CLOSE TO YOU", "BOOK"]
but that isn't working.
Would anyone be able to push me or demonstrate to get me in the right direction.
Thanks!
UserDefaults.string(forKey:)
Use UserDefaults.string(forKey:) instead of UserDefaults.object(forKey:).
let firstName = UserDefaults.standard.string(forKey: "firstName") ?? "YOU"
var arrayOfTitle = ["HEY \(firstName)", "FIND EVENTS CLOSE TO YOU", "BOOK"]
UserDefaults.standard.object(forKey:) returns Any? which you must unwrap and convert to a string. UserDefaults.standard.string(forKey:) converts the result to String? which can simplify your code.
The nil-coalescing operator, ??, unwraps the String? result if it contains a value, or returns the default value "YOU" if the result is nil. Without the ?? operator, if there is not a UserDefault stored for "firstName", it will return nil resulting in "HEY nil".
Optional Binding
You can use optional binding with UserDefaults.string(forKey:) if you want to conditionally run code if a value exists or not.
if let firstName = UserDefaults.standard.string(forKey: "firstName") {
print("\(firstName)")
}
if let name = UserDefaults.standard.object(forKey: "firstName") as? String{
arrayOfTitle.append(name)
}

Convert [String]? to String in Swift

For my project, I extracted tweets from a CSV file in Swift. Problem is now all tweets are parsed as one element in an array, separated by ",".
let tweetsOfColumns = columns["tweet"]
let seperatedColumns = tweetsOfColumns.componentsSeparatedByString(",")
Error message: '[String]?' does not have a member named
'componentsSeparatedByString'.
I checked if tweetsOfColumns contains multiple elements, but it doesn't allow me to subscript with tweetsOfColumns[index].
Looking at the link you reference, columns["tweets"] is going to give you back an array of the values from the "tweets" column, so it's what you need already, there's no additional comma's to split things on, you just need:
let seperatedColumns = columns["tweet"]
to have an array containing the tweet column for each row.
When you try to get an element from a dictionary, like
columns["tweet"]
it will give you back an optional, because if there is nothing associated with the key, it gives you back nil (None), otherwise the value wrapped in an optional (Some(data)).
So you have to unwrap the optional for example:
columns["tweet"]!
You have to either use the optional ? to access the string:
let seperatedColumns = tweetsOfColumns?.componentsSeparatedByString(",")
But you should unwrap it:
if let unwrappedTweets = tweetsOfColumns?.componentsSeparatedByString(","){
let seperatedColumns = unwrappedTweets
}
The problem is probably that you'll get an optional back, which you have to unwrap. And the easiest and most elegant is to use the if-let unwrapper.
if let tweetsOfColumns = columns["tweet"] {
let seperatedColumns = tweetsOfColumns.componentsSeparatedByString(",")
// do something with the seperatedColumns
}
Based on David's question and the OP's response in the OP comments, you can use map on the Array returned by columns["tweet"]. Please post actual data/code in the future.
let columns = [
"tweet":["handleX,tag1,tag2,textA,textB",
"handleY,tag1,tag2,textC,textD"]]
var chunk = [[String]]()
if columns["tweet"] != nil {
chunk = columns["tweet"]!.map {
return $0.componentsSeparatedByString(",")
}
}

Resources