Swift:How to map a single key to Multiple values? - ios

I have successfully mapped a Single key to single value like this:
class DefaultDoubleModel :BaseObject
{
var key : String = ""
var value : String = ""
}
var toolChart :[DefaultDoubleModel]!
self.BubbleChartXaxislabel = Array(GraphDataModel.toolChart.map({ (item) -> String in
item.key
}))
self.BubbleChartValuesGraph = Array(GraphDataModel.toolChart.map({ (item) -> String in
item.value
}))
This is true for single key and single value. But i have two values in a single key. How can i collect those values in array.
For example i have like this..
{"value2":"80","value1":"120","key":"4"}

A Dictionary with tuples of strings would look like this:
var data: [String: (String, String)]()
data["4"] = ("80", "120")
print(data["4"]!.0)
You access the elements as .0 and .1.

If you want exactly two values, then you can make your DefaultDoubleModel look like this
class DefaultDoubleModel :BaseObject {
var key : String = ""
var value1 : String = ""
var value2 : String = ""
}
I think its more future proof to make it an array of Strings, like this:
class DefaultDoubleModel :BaseObject {
var key : String = ""
var values = [String]()
}
If you go with the second option, then you would map like this:
self.BubbleChartValuesGraph = GraphDataModel.toolChart.flatMap{ $0.values }

Related

Find out common value from two different Type Array

I have two Array with different Data Types
Assume Array1 is an [String] array of String
Assume Array 2 is an [Custom Objects] array of Struct
Pls find a code
struct ScanData{
var serialNo : String!
var intNo : String!
init(serialNo : String, intNo : String) {
self.serialNo = serialNo
self.intNo = intNo
}
}
var validScannedData : [String] = []
var inValidScannedData : [String] = []
var arrayObj = [ScanData(serialNo: "12220116033", intNo: "SN6AT4.270"),ScanData(serialNo: "12198144025", intNo: "SN6AT4.280"),ScanData(serialNo: "12222383027", intNo: "SN6AT4.130"),ScanData(serialNo: "12198213032", intNo: "SN6AT5.260"),ScanData(serialNo: "", intNo: "")]
//print(arrayObj)
//ScanData(serialNo: "12199690049", intNo: "SN6AT6U100")
var localArray = ["12220116033","12198144025","12222383027","12198213032","12199690049"]
let tempArray = arrayObj.filter { data in
return data.serialNo != "" || data.intNo != ""
}
print(tempArray.count)
Now we want to get common values from localArray and tempArray by matching serialNo key
Finally i want to have Array of String Format in validScannedData object
Expected Output :
Valid data : ["12220116033","12198144025","12222383027","12198213032"]
Invalid data : ["12199690049"]
I tried this but its prints custom object array
let a = tempArray.filter () { localArray.contains($0.serialNo) }
print(a)
Thanks in advance
Use forEach to iterate your element and then check and append to the according to array.
localArray.forEach { number in
arrayObj.contains(where: {$0.serialNo == number}) ? validScannedData.append(number) : inValidScannedData.append(number)
}
print(validScannedData)
print(inValidScannedData)

Filtering Arrays Containing Multiple Data Types in Swift3

I have an array like:-
var arrayData : Array<Dictionary<String, [BottleModel]>> = []
Bottle model :-
class BottleModel: NSObject {
var name : String
var price : Int
var reviews : Int
var category : String
var quantity : String
var id : String
var shopData : ShopModel
}
I want filtered array where price is > 2000
I tried let searchByInts = arrayData.filter({m in m.price < 200})
but getting below error:
Contextual closure
type '(Dictionary) -> Bool' expects 1 argument,
but 0 were used in closure body
How to filter such kind of array based on price
Working code:
let searchByInts = arrayData.filter { $0.values.contains { $0.contains { $0.price > 2000 } } }
By the way please write the following using literals:
var arrayData : [[String : [BottleModel]]] = []
Still no idea if that is what you actually want because your goal is very unclear. You have an array of dictionaries of arrays which actually contain the values you want to filter out. If a BottleModel costs more than 2000 do you want to keep the entire array it is contained in and the dictionary that array is in? You might want to map the entire data into one flat array before or after filtering.
Alternative using flatMap:
let flat = arrayData.flatMap { $0.values.flatMap { $0 } }
let searchByInts2 = flat.filter { $0.price < 200 } // or some other criteria

Cannot add an append an array into a dictionary that has an empty array

I have a Profile Data singleton class as follows.
I am trying to store data into an empty array in a dictionary .
After appending data to the array also the count of the array is 0.
class ProfileData{
static let sharedInstance = ProfileData()
var artistProfileDict = [String : Profile]()
var loggedInUserProfile = Profile(artistName: "John Smith", artistDescription: "Admiral of New England, English soldier, explorer, and author.", totalLikes: "174", totalViews: "200", totalFollowing: "100",totalFollowers:"50",imageUrl:"image_singer", feeds:[] )
private init() {
getProfilesDictionary()
}
func getProfilesDictionary()->[String: Profile]{
artistProfileDict["John Smith"] = loggedInUserProfile
return artistProfileDict
}
func add(array: Feed, artistName: String) {
artistProfileDict[artistName]!.feeds.append(array)
}
}
In another view Controller I am trying to add an array to the empty array in the dictionary as follows
let newFeed = Feed(profilePicture: "image",artistName: "New",
videoUrl: "url",videoTitle:"New", videoViews: "160",likes:
"200",shoutouts: "200",comments: [],votes: "50", dateCreated: Date(),
userActivity :"This user liked your video")
ProfileData.sharedInstance.add(array: newFeed,artistName:"John Smith")
After appending the array to the empty array in the dictionary I still get the count of the array as 0.
I am not able to figure out the problem here. Any help will appreciated . Thank you.
Profile class
struct Profile {
var artistName: String
var artistDescription: String
var totalLikes: String
var totalViews: String
var totalFollowing: String
var totalFollowers: String
var imageUrl: String
var feeds : [Feed]
init(artistName: String,artistDescription:String,totalLikes:String,totalViews:String,totalFollowing:String,totalFollowers:String,imageUrl:String, feeds:[Feed]) {
self.artistName = artistName
self.artistDescription = artistDescription
self.totalLikes = totalLikes
self.totalViews = totalViews
self.totalFollowing = totalFollowing
self.totalFollowers = totalFollowers
self.imageUrl = imageUrl
self.feeds = feeds
}
}
It's working fine
ProfileData.sharedInstance.add(array: newFeed,artistName:"John Smith")
ProfileData.sharedInstance.artistProfileDict["John Smith"]?.feeds.count // 1
Probably you are using wrong class ArtistProfileData instead of ProfileData.

How do I create a dictionary from an array of objects in swift 2.1?

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)

Create Dictionary<String, [SomeStruct]> from [SomeStruct] source-array

var sourceEntries: [Entry] = [entry1, ..., entry14]
var myDict: Dictionary<String, [Entry]> = [:]
for entry in sourceEntries {
if var array = myDict[entry.attribute1] { theArray.append(entry) }
else { myDict[entry.attribute1] = [entry] }
}
I am intending to create a Dictionary, which matches all the objects of the struct "Eintrag" with the same attribute from the source-Array "alleEinträge" to a String containing the value of the shared attribute. For some reason my final Dictionary just matches Arrays of one element to the Strings, although some Arrays ought to contain up to four elements.
The problem is that the array is passed by value (i.e. "copied"), so the array you are writing to when you say array.append is not the array that is "inside" the dictionary. You have to write back into the dictionary explicitly if you want to change what's in it.
Try it in a simple situation:
var dict = ["entry":[0,1,2]]
// your code
if var array = dict["entry"] { array.append(4) }
// so what happened?
println(dict) // [entry: [0, 1, 2]]
As you can see, the "4" never got into the dictionary.
You have to write back into the dictionary explicitly:
if var array = dict["entry"] { array.append(4); dict["entry"] = array }
FURTHER THOUGHTS: You got me thinking about whether there might be a more elegant way to do what you're trying to do. I'm not sure whether you will think this is "more elegant", but perhaps it has some appeal.
I will start by setting up a struct (like your Entry) with a name attribute:
struct Thing : Printable {
var name : String
var age : Int
var description : String {
return "{\(self.name), \(self.age)}"
}
}
Now I will create an array like your sourceEntries array, where some of the structs share the same name (like your shared attribute attribute1):
let t1 = Thing(name: "Jack", age: 40)
let t2 = Thing(name: "Jill", age: 38)
let t3 = Thing(name: "Jill", age: 37)
let arr = [t1,t2,t3]
And of course I will prepare the empty dictionary, like your myDict, which I call d:
var d = [String : [Thing]]()
Now I will create the dictionary! The idea is to use map and filter together to do all the work of creating key-value pairs, and then we just build the dictionary from those pairs:
let pairs : [(String, [Thing])] = arr.map {
t in (t.name, arr.filter{$0.name == t.name})
}
for pair in pairs { d[pair.0] = pair.1 }

Resources