I have Array which contain ID like
var ID = ["782", "783", "784", "785", "786", "788", "789", "790", "791", "792", "793", "795", "805"]
And One Arr Of Dictionary like
Var arr2 = [["ID":"782","AmenitiesURL":"xyx.com"],["ID":"783","AmenitiesURL":"xybx.com"],["ID":"784","AmenitiesURL":"xyax.com"]]
Aslo see in image. Now I want to get the url of the ID.
Ex. if arr ID= 784 Then i want find that ID in the arr2 and get their url and append in New array,
In short Two array one is for ID and other for URL.
To get the URL of a specific id
let id = "784"
if let dict = arr2.first(where: { $0["ID", default:""] == id }), let urlString = dict["AmenitiesURL"] {
print(urlString)
}
You can get that working using the following approach:
let urls = ID.compactMap { (id) in
return arr2.first(where: {$0["ID"] == id})?["AmenitiesURL"]
}
Output:
print(urls) //["xyx.com", "xybx.com", "xyax.com"]
For all the ids in ID array, you'll get AmenitiesURL values from arr2 array.
Another approach. Though this one retains the structure of arr2
let filteredArray = arr2.filter { dict -> Bool in
for id in ID{
if dict["ID"] == id{
return true
}
}
return false
}
Related
I am trying to filter my dictionary according to user input in UISearchController. I have following model and array of objects.
struct People {
var name: String
var id: Int
}
let first = People(name: "Atalay", id: 1)
let second = People(name: "Ahmet", id: 2)
let third = People(name: "Mehmet", id: 3)
let fourth = People(name: "Yusuf", id: 4)
let peoples: [People] = [first, second, third, fourth, fifth]
I put them into a dictionary to create section indexed table view with following code.
var dict: [String: [People]] = Dictionary(grouping: peoples, by: { (people) -> String in
return String(people.name.prefix(1))
})
Above code gives me a dictionary with first letter of People names. Now, I would like to filter my array according to user input. However, I tried following code for filtering but it is not working as I expected.
let filteredDict = (dict.filter { $0.1.contains { $0.name.lowercased().contains("ata") } })
It returns all "A" letter section indexes like ["A": People(name: "Atalay", id: 1), People(name: "Ahmet", id: 2)]
How can I achieve filter also my array inside dictionary?
If I'm not mistaken, you want your final dictionary to have all the keys and only the filtered array of items as the values. If that is right, reduce is the tool for that:
let filtered = dict.reduce(into: [String: [People]]()) {
$0[$1.key] = $1.value.filter { $0.name.lowercased().contains("ata") }
}
I decided it was simplest to get this right by using an old fashioned for loop and filter each group separately
var filtered = [String: [People]]()
for (k, v) in dict {
let result = v.filter {$0.name.lowercased().contains("ata")}
if result.count > 0 {
filtered[k] = result
}
}
Note that if you want to keep all the groups in the result dictionary just skip the if result.count > 0 condition
How can I achieve filter also my array inside dictionary?
You should have an array first, you can use flatMap to group all the values in your filteredDict
let array = filteredDict.flatMap { $0.value }
Then you just filter the array as usually
let filteredArray = array.filter { $0.name.lowercased().contains("ata") }
I just want to create a dictionary with the help of for loop
sample code :
var counter: Int = 1;
var pageCountDict = [String:Any]();
for filterCount in counter..<6
{
if let count = "page_\(filterCount)_vtime" as? String
{
pageCountDict = [count: timeInterval_Int];
}
}
print(pageCountDict);
This print command give me only last value of forloop
I just want all the value of this variable pageCountDict in a dictonary
The way to assign to a dictionary is first use the subscript and assign the value to it:
pageCountDict[YourKey] = YourValue
Also, you can see many examples and explanations in Apple documentation regarding dictionaries.
With each loop, you are replacing the dictionary with one that contains only one element. What you want to do is this :
pageCountDict[count] = timeInterval_Int
Also, you shouldn't need the as? String part. This should be sufficient :
for filterCount in counter..<6
{
pageCountDict[count] = "page_\(filterCount)_vtime"
}
var pageCountDict = [String:Any]()
You can add values to this dictionary by merging previous contents and new data as follows...
let counter: Int = 1
var pageCountDict = [String:Any]()
for filterCount in counter..<6
{
let value = 9
let count = "page_\(filterCount)_vtime" //'if' is not needed as it is always true
pageCountDict.merge([count: timeInterval_Int], uniquingKeysWith:{ (key, value) -> Any in
//assign value for similar key
timeInterval_Int
})
}
print(pageCountDict)`
I got User Defaults with the key "abc" for example and it contains a string.
The last string stored in this key is "aaa".
Now, I want to store an additional value for this key, but I don't want to delete the last value "aaa" because I need it.
I want to have an Array of strings contains at the second retreive: ["aaa","some_other_value", "some_other_value2"...].
This is my code so far to store the information in user defaults:
self.user_defaults.set(self.myTextField.text, forKey:"asd")
This is the code for get the data:
if let arr = user_defaults.string(forKey:"asd"){
print (arr)
}
Try follwing code for save new value :
if let arr = user_defaults.array(forKey: "asd")
{
var arrvalues = arr as! [String]
arrvalues.append(self.myTextField.text)
self.user_defaults.set(arrvalues, forKey:"asd")
self.user_defaults.synchronize()
print (arr)
}
else
{
self.user_defaults.set([self.myTextField.text], forKey:"asd")
}
This is the code for get the data:
if let arr = user_defaults.array(forKey:"asd"){
print (arr)
}
let asdArr = [String]()
if NSUserDefaults.standardUserDefaults().objectForKey("asd") != nil {
asdArr = NSUserDefaults.standardUserDefaults().objectForKey("asd")
}
asdArr.append(self.myTextField.text)
NSUserDefaults.standardUserDefaults().setObject(asdArr, forKey: "asd")
I have this class
class InboxInterests {
var title = ""
var eventID = 0
var count = ""
var added = 0
init(title : String, eventID : NSInteger, count: String, added : NSInteger) {
self.title = title
self.eventID = eventID
self.count = count
self.added = added
}
}
And i use it like this
var array: [InboxInterests] = [InboxInterests]()
Add item
let post = InboxInterests(title: "test",eventID : 1, count: "test", added: 0)
self.array.append(post)
I want to find the index by eventID key and change the value of added key in the same index
How is that possible?
For me, the above answer did not work. So, what I did was first find the index of the object that I want to replace then using the index replace it with the new value
if let row = self.upcoming.index(where: {$0.eventID == id}) {
array[row] = newValue
}
In Swift 5.0:
if let row = self.upcoming.firstIndex(where: {$0.eventID == id}) {
array[row] = newValue
}
Since you are using a class, use filter and first to find the value:
array.filter({$0.eventID == id}).first?.added = value
In this you:
filter the array down to elements that match the event ID
pick the first result, if any
then set the value
This works since classes are pass by reference. When you edit the return value from array.filter({$0.eventID == id}).first?, you edit the underlying value. You'll need to see the answers below if you are using a struct
EDIT: In Swift 3 you can save yourself a couple of characters
array.first({$0.eventID == id})?.added = value
EDIT: Swift 4.2:
array.first(where: { $0.eventID == id })?.added = value
array.filter {$0.eventID == id}.first?.added = value
The filter operator is not the best in this case, it works for some of you because classes are passed by reference.
Explanation: (You can copy the following code in a playground if you want to verify it).
class Book {
let id: Int
var title = "default"
init (id: Int) {
self.id = id
}
}
var arrayBook = [Book]()
arrayBook.append(Book(id: 0))
arrayBook.append(Book(id:1))
arrayBook.forEach { book in
print(book.title)
}
arrayBook.filter{ $0.id == 1 }.first?.title = "modified"
arrayBook.forEach { book in
print(book.title)
}
Arrays are copied by value not reference, so when you are using filter you are creating a new array (different than the initial), but when you modify the new one, the initial one gets modified too because both are pointing to the same class (classed are passed by reference), so after the filter your array will have changed and the new one gets deallocated. So in this case it will print "default", "default" and then "default, "modified".
What happens if you change class for struct, the value will be passed by value not reference so you will have 2 arrays in memory with different values, so if you go through arrayBooks again it will print before the filter "default","default", and then "default", "default" again. Because when you are using the filter you are creating and modifying a new array that will get deallocated if you do not store it).
The solution is using map, creating a new array with all the values but with the modified items or fields that we want and then replace our array with the new one. This will print "default", "default" before the map, and then "default", "modified"
This will work with structs, classes and everything that you want :).
struct Book {
let id: Int
var title = "default"
init (id: Int) {
self.id = id
}
}
var arrayBook = [Book]()
arrayBook.append(Book(id: 0))
arrayBook.append(Book(id:1))
arrayBook.forEach { book in
print(book.title)
}
arrayBook = arrayBook.map{
var mutableBook = $0
if $0.id == 1 {
mutableBook.title = "modified"
}
return mutableBook
}
arrayBook.forEach { book in
print(book.title)
}
array = array.map { $0.eventID == id ? newValue : $0 }
If you conform your class to Equatable then this would work:
extension Array where Element: Equatable {
#discardableResult
public mutating func replace(_ element: Element, with new: Element) -> Bool {
if let f = self.firstIndex(where: { $0 == element}) {
self[f] = new
return true
}
return false
}
}
Use like this:
array.replace(prev, with: new)
I have an array of type "drugList", and they are derived from a struct "DrugsLibrary":
struct DrugsLibrary {
var drugName = ""
var drugCategory = ""
var drugSubCategory = ""
}
var drugList = [DrugsLibrary]()
//This is the dictionary i'm trying to build:
var dictionary = ["": [""," "]]
My data model is initialized using this function:
func createDrugsList() {
var drug1 = DrugsLibrary()
drug1.drugName = "drug1"
drug1.drugCategory = "Antibiotics"
drug1.drugSubCategory = "Penicillins"
self.drugList.append(drug1)
var drug2 = DrugsLibrary()
drug2.drugName = "drug2"
drug2.drugCategory = "Antibiotics"
drug2.drugSubCategory = "Penicillins"
self.drugList.append(drug2)
var drug3 = DrugsLibrary()
drug3.drugName = "drug2"
drug3.drugCategory = "Antibiotics"
drug3.drugSubCategory = "Macrolides"
self.drugList.append(drug3)
}
my problem is that i'm trying to create a dictionary from the drugList where the key is the drugSubCategory and the value is the drug name. The value should be an array if there are several drugs in this subcategory
for example, the dictionary should look something like this for this example:
dictionary = [
"Penicillins": ["drug1","drug2"]
"Macrolides": ["drug3"]
]
I tried this method:
for item in drugList {
dictionary["\(item.drugSubCategory)"] = ["\(item.drugName)"]
}
this gave a dictionary like this, and it couldn't append drug2 to "Penicllins":
dictionary = [
"Penicillins": ["drug1"]
"Macrolides": ["drug3"]
]
So I tried to append the items into the dictionary using this method but it didn't append anything because there were no common items with the key "" in the data model:
for item in drugList {
names1[item1.drugSubCategory]?.append(item1.drugName)
}
Anyone knows a way to append drug2 to the dictionary?
I would appreciate any help or suggestion in this matter.
You need to create a new array containing the contents of the previous array plus the new item or a new array plus the new item, and assign this to your dictionary:
for item in drugList {
dictionary[item.drugSubCategory] = dictionary[item.drugSubCategory] ?? [] + [item.drugName]
}
You can use .map and .filter and Set to your advantage here. First you want an array of dictionary keys, but no duplicates (so use a set)
let categories = Set(drugList.map{$0.drugSubCategory})
Then you want to iterate over the unique categories and find every drug in that category and extract its name:
for category in categories {
let filteredByCategory = drugList.filter {$0.drugSubCategory == category}
let extractDrugNames = filteredByCategory.map{$0.drugName}
dictionary[category] = extractDrugNames
}
Removing the for loop, if more Swifty-ness is desired, is left as an exercise to the reader ;).
I have two unrelated observations:
1) Not sure if you meant it as an example or not, but you've initialized dictionary with empty strings. You'll have to remove those in the future unless you want an empty strings entry. You're better off initializing an empty dictionary with the correct types:
var dictionary = [String:[String]]()
2) You don't need to use self. to access an instance variable. Your code is simple enough that it's very obvious what the scope of dictionary is (see this great writeup on self from a Programmers's stack exchange post.
Copy this in your Playground, might help you understand the Dictionaries better:
import UIKit
var str = "Hello, playground"
struct DrugsLibrary {
var drugName = ""
var drugCategory = ""
var drugSubCategory = ""
}
var drugList = [DrugsLibrary]()
//This is the dictionary i'm trying to build:
var dictionary = ["":""]
func createDrugsList() {
var drug1 = DrugsLibrary()
drug1.drugName = "drug1"
drug1.drugCategory = "Antibiotics"
drug1.drugSubCategory = "Penicillins"
drugList.append(drug1)
var drug2 = DrugsLibrary()
drug2.drugName = "drug2"
drug2.drugCategory = "Antibiotics"
drug2.drugSubCategory = "Penicillins"
drugList.append(drug2)
var drug3 = DrugsLibrary()
drug3.drugName = "drug2"
drug3.drugCategory = "Antibiotics"
drug3.drugSubCategory = "Macrolides"
drugList.append(drug3)
}
createDrugsList()
print(drugList)
func addItemsToDict() {
for i in drugList {
dictionary["item \(i.drugSubCategory)"] = "\(i.drugName)"
}
}
addItemsToDict()
print(dictionary)