How to change array value depend on condition in Swift? - ios

I have array like this
var country = ["America","Germany","China"]
My need is if this array have America
I would like to make it become "US"
hoping result like this
["US","Europe","Asia"]
don't use country[0] = "US"
because array order every times are different
Use condition that I gave
How should I do ?

Create a dictionary of what a string in countries needs to be replaced with.
let countriesToRegions = ["America": "US", "Germany": "Europe", "China": "Asia"]
Then when you need to convert the countries into regions, you can look them up in the dictionary.
var countries = ["America", "Germany", "China"]
let regions = countries.map { country in
countriesToRegions[country] ?? country
}
The last bit here, ?? country, is handling the possibility that the country is not in the countriesToRegions dictionary.

Here is one way to do it (comments inline):
let country = ["USA", "Germany", "China", "Fakeland"]
// use a dictionary for the replacements
let continentForCountry = ["USA": "North America", "Germany": "Europe", "China": "Asia"]
// use map to replace each item and set a default value if the
// replacement is not found
let result = country.map { continentForCountry[$0, default: "unknown continent"] }
print(result)
["North America", "Europe", "Asia", "unknown continent"]

Try -
let requiredIndex = country.index(where: { $0 is "America" }) {
country[requiredIndex] = "US"
}

You can either use Map or for a more explained version, can use the below function
func replaceOccuranceInArray(inArray:[String], of originalString: String, with replacementString: String) -> [String] {
var arrayToBeReturned = inArray
var indexes = [Int]()
for currentIndex in 0...inArray.count - 1 {
if inArray[currentIndex] == originalString {
indexes.append(currentIndex)
}
}
for eachIndex in indexes {
arrayToBeReturned[eachIndex] = replacementString
}
return arrayToBeReturned
}
I have attached a Playground output for the same below

As some suggested, you can use power of .map function.
Here is simple solution how you can map country to continent:
let americanCountries = ["US", "Argentina", "Brasil"]
let asianCountries = ["China", "Japan", "Korea"]
let europeanCountries = ["Germany", "France", "Spain"]
let countries = ["US","Germany","China"]
let continents = countries.map { country -> String in
if americanCountries.contains(country) {
return "America"
} else if asianCountries.contains(country) {
return "Asia"
} else if europeanCountries.contains(country) {
return "Europe"
} else {
return "Unknown continent"
}
}
Another step would be try to use enums.

A simple solution :
Get the index of the value to be replaced and replace it if existing:
if let ind = country.firstIndex(of: "America"){
country[ind] = "US"
}

Related

Filter content for search text with lowercased and array

I have struct with cities: [String] in firestore
struct CityList {
var country: String
var cities: [String]
}
Struct in firestore looks like on
1
country: Russia
cities: ["Moscow", "Saint-Petersburg"]
2
country: USA
cities: ["New York", "Los Angeles"]
I need to use filter array of strings cities: [String] when I use searchController. Now I have func filterContentForSearchText
private func filterContentForSearchText(_ searchText: String) {
filteredCityList = cityList.filter({ (cityList: CityList) -> Bool in
return cityList.cities[0].lowercased().contains(searchText.lowercased())
})
tableView.reloadData()
}
I know with my mistake is -> cities[0], but I don't understand how to fix it...
And when I write text in searchController, searchController search only first city it's Moscow or New York.
How I can search Moscow, Saint-Petersburg, New York and Los Angeles?
So your cities[0] only takes the first city, I assume you need to search in all cities so I would check cities.contains. I would also use localizedCaseInsensitiveContains instead of manually lowercasing.
cities.contains {
$0.localizedCaseInsensitiveContains(searchText)
}
the filter would be:
cityList.filter { list in
list.cities.contains { city in
city.localizedCaseInsensitiveContains(searchText)
}
}
let arrayFiltered = CityList.cities.filter{
$0.lowercased().contains(searchText.lowercased())
}
Please try this.
You trying to filter on Struct, it won't work. Try using filter on Array of cities instead.
I think your data structure can be improved like this:
let searchText = "Moscow"
// for easch Country: Cities array
let worldCities: [String: [String]] = [ "Russia": ["Moscow", "Saint-Petersburg"],
"USA": ["New York", "Los Angeles"]
]
let result = worldCities["Russia"]?.filter({ city -> Bool in
if city.lowercased().contains(searchText.lowercased()) {
return true
} else {
return false
}
})
In case you want go over all countries, you should probably use single array of all cities or merge with above example:
let all = worldCities.values

How to generate a 2D-array from a 1D-array using map and filter?

I have the desired output using a loop today but how can I exchange this loop with a one line expression using map and filter?
I start with an array of countries. From this one I generate a second array with the initial letters using map. I would now like to build a 2D-array that contains all the countries with the same initial letter in separate arrays using map and filter so that I can get rid of the loop I use today.
let countries = ["Albania", "Algeria", "Angola", "Bahamas", "Bahrain", "Canada"]
var initials = Set(countries.map { $0.prefix(1) }).sorted()
func countriesByInitial() -> [[String]] {
var result = [[String]]()
for initial in initials {
result.append(countries.filter { $0.prefix(1) == initial })
}
return result
}
You can achieve it by group > sort > map combination as:
let countries = ["Algeria", "Albania", "Belarus", "Bahamas", "Canada"]
let groupedDict = Dictionary(grouping: countries, by: { $0.prefix(1) })
let sortedDict = groupedDict.sorted(by: { $0.key < $1.key })
let arr2D = sortedDict.map({ $0.value })
You can write it in a single line:
let arr = (Dictionary(grouping: countries, by: { $0.prefix(1) })).sorted(by: { $0.key < $1.key }).map({ $0.value })
You can use reduce on array as well:
// $0 will be of type [[String]]
// $1 will be of type String
let arr2D: [[String]] = countries.reduce(into: []) {
let checkChar = $1.first
if let idx = $0.index(where: {$0.first?.first == checkChar }) {
$0[idx].append($1)
} else {
$0.append([$1])
}
}
You can use Swift 4 method reduce(into:) if your array it is already sorted, otherwise you just need to sort it before grouping it:
let countries = ["Albania", "Algeria", "Angola", "Bahamas", "Bahrain", "Canada"]
let grouped: [[String]] = countries.reduce(into: []) {
if $0.last?.last?.prefix(1) == $1.prefix(1) {
$0[$0.index(before: $0.endIndex)].append($1)
} else {
$0.append([$1])
}
}
print(grouped) // [["Albania", "Algeria", "Angola"], ["Bahamas", "Bahrain"], ["Canada"]]\n"
You could map the initial set by filtering countries strings' first letter as:
let countries = ["Albania", "Algeria", "Angola", "Bahamas", "Bahrain", "Canada"]
var initials = Set(countries.map { $0.prefix(1) }).sorted()
let array = initials.map { letter -> [String] in
return countries.filter { $0.prefix(1) == letter }
}
therefore, array is an array of arrays of strings ([[String]]), as:
[["Albania", "Algeria", "Angola"], ["Bahamas", "Bahrain"], ["Canada"]]

Get list of indexes using Array.filter instead of objects

is there any way to get list of filtered indexes instead of objects.
class Object
{
var name
var goal
}
var array<Object> = Array<Object>()
var filteredIndexes = array.filter{$0.name = "Sane"} // How to implement this?
There are several ways to achieve your goal. For instance, you can filter Array.indices instead of the array itself.
Self contained example:
struct Object {
let name:String
let goal:String
}
let objects = [Object(name: "John", goal: "a"),Object(name: "Jane", goal: "a"),Object(name: "John", goal: "c"),Object(name: "Pete", goal: "d")]
let nameToBeFound = "John"
let filteredIndices = objects.indices.filter({objects[$0].name == nameToBeFound}) //[0,2]
let animals = ["cat", "dog", "cat", "dog", "cat"]
let indexes = animals.enumerated().filter({ return $1 == "cat" }).map { return $0.offset }
print(indexes)
prints out [0, 2, 4]
As Lame said above, the solution from Return an array of index values from array of Bool where true can be adapted
to this case:
let filteredIndices = objects.enumerated().flatMap { $0.element.name == "Sane" ? $0.offset : nil }
One could also define a custom extension
extension Sequence {
func indices(where predicate: (Element) -> Bool ) -> [Int] {
return enumerated().flatMap { predicate($0.element) ? $0.offset : nil }
}
}
which is then used as
let filteredIndices = objects.indices(where: { $0.name == "Sane" })
Remark: In Swift 4.1, this flatMap() method has been renamed to compactMap()

How to make an array string from enum member raw value in swift

I am new in programming and swift. I have an enum like this
enum City : String {
case tokyo = "tokyo"
case london = "london"
case newYork = "new york"
}
Could I possibly get that city name to an array from enum raw value? I hope I can get something like this :
let city = ["tokyo","london","new york"]
Something like this.
let cities = [City.tokyo, .london, .newYork]
let names = cities.map { $0.rawValue }
print(names) // ["tokyo", "london", "new york"]
To get all enum values as an array see this.
Swift 4.0
If you want to iterate through enum you can do like this.
enum City : String {
case tokyo = "tokyo"
case london = "london"
case newYork = "new york"
static let allValues = [tokyo,london,newYork]
}
let values = City.allValues.map { $0.rawValue }
print(values) //tokyo london new york
Hope this might help. Please look into this https://stackoverflow.com/a/28341290/2741603 for more detail
enum City : String {
case tokyo = "tokyo"
case london = "london"
case newYork = "new york"
}
func iterateEnum<T: Hashable>(_: T.Type) -> AnyIterator<T> {
var k = 0
return AnyIterator {
let next = withUnsafeBytes(of: &k) { $0.load(as: T.self) }
if next.hashValue != k { return nil }
k += 1
return next
}
}
var cityList:[String] = []
for item in iterateEnum(City.self){
cityList.append(item.rawValue)
}
print(cityList)
Starting from the answer by https://stackoverflow.com/users/5991255/jaydeep-vora, you can also add conformity to CaseIterable protocol and then use the allCases method
enum City : String, CaseIterable {
case tokyo = "tokyo"
case london = "london"
case newYork = "new york"
}
let values = City.allCases.map { $0.rawValue }
print(values)

Sorting of an array alphabetically in swift

I am new to swift.I am trying one sample app in which I need to implement the sorting of an array in alphabetical order.I getting the json data and I am adding the titles in the array.Now i would like to sort that alphabetically.Here is my code .....
func updateSearchResults(data: NSData?)
{
do
{
let json = try NSJSONSerialization.JSONObjectWithData(data!, options: .AllowFragments)
if let blogs: NSArray = json["results"] as? [AnyObject] {
print(blogs)
for blog in blogs {
if let name = blog["original_title"] as? String {
names.addObject(name)
}
}
print(names)
**let sortedArray = sorted(names, {
(str1: String, str2: String) -> Bool in
return str1.toInt() < str2.toInt()** // Here I am getting the Error Message
})
}
}
catch {
print("error serializing JSON: \(error)")
}
}
The error message I am getting is "Cannot invoke 'sorted' with an argument list of type '(NSMutableArray, (String, String) -> Bool)'"
I tried a lot to achieve this but I didn't find the solution.
Can anyone help me to resolve this issue.
Thanks In Advance.
First convert NSMutableArray to the Array by using below line of code.
let swiftArray = mutableArray as AnyObject as! [String]
Use below line of code to sort the Array.
var sortedArray = names.sorted { $0.localizedCaseInsensitiveCompare($1) == NSComparisonResult.OrderedAscending }
Check below link for sort Closures.
https://developer.apple.com/library/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Closures.html
Update for Swift 3.0
var sortedArray = swiftArray.sorted { $0.localizedCaseInsensitiveCompare($1) == ComparisonResult.orderedAscending }
Use this simple code of line to sort ur array
let sortedNames = names.sort { $0.name < $1.name }
For Swift 4 you can use only this
let sortedNames = names.sorted(by: <)
Swift4
var names = [ "Alpha", "alpha", "bravo", "beta"]
var sortedNames = names.sorted { $0.localizedCaseInsensitiveCompare($1) == ComparisonResult.orderedAscending }
print(sortedNames) //Logs ["Alpha", "alpha","beta", "bravo"]
Swift 4(working code)
JSON response -> Stored in aryNameList
"DATA": [
{
email = "iosworker#gmail.com";
firstname = Harvey
},
{
email = "poonam#openxcell.com";
firstname = poonam
},
{
email = "t#t.com";
firstname = rahul
},
{
email = "android.testapps#gmail.com";
firstname = Chulbulx
},
{
email = "t#t2.com";
firstname = rahul
},
{
email = "jaystevens32#gmail.com";
firstname = Jay
},
{
email = "royronald47#gmail.com";
firstname = Roy
},
{
email = "regmanjones#hotmail.com";
firstname = Regan
},
{
email = "jd#gmail.com";
firstname = Jaydip
}
]
Code
self.aryNameList = self.aryNameList.sorted(by: { (Obj1, Obj2) -> Bool in
let Obj1_Name = Obj1.firstname ?? ""
let Obj2_Name = Obj2.firstname ?? ""
return (Obj1_Name.localizedCaseInsensitiveCompare(Obj2_Name) == .orderedAscending)
})
working every case (for ex: lowerCase, upperCase..)
For an array of objects:
items = items.sorted(by: { (item1, item2) -> Bool in
return item1.product.name.compare(item2.product.name) == ComparisonResult.orderedAscending
})
Try this one
var names = [ "Alpha", "alpha", "bravo"]
var sortedNames = names.sort { $0.localizedCaseInsensitiveCompare($1) == NSComparisonResult.OrderedAscending }
print(sortedNames) //Logs ["Alpha", "alpha", "bravo"]
Swift 3 solution:
let yourStringArray = [ "beTA", "ALPha", "Beta", "Alpha"]
var sortedArray = yourStringArray.sorted()
// Result will be ["ALPha", "Alpha", "Beta", "beTA"]
Creds to jjatie

Resources