How to Make a Struct Version of the NSCountedSet Class? - ios

I am developing an app in which I need to take two arrays, both holding the same custom data type, MenuItem.
I need to compare them and find the common elements of both arrays.
I compare the two arrays by converting them both to sets and then using the compare function of the set struct.
However, I then need to convert the array of common elements to a Counted Set so that I can find how many of each element exist in the group of common elements.
The problem I am having is with converting the the array of common elements to a Counted Set. In Swift, there is an NSCountedSet class but no CountedSet struct like there are for most built-in swift Data Types:
let groups = Array(self.menu.keys)
//menu and cart are dictionaries the structure [MenuGroup: [MenuItem]]
let cartGroups = Array(self.cart.keys)
let group = groups[indexPath.section]
if cartGroups.contains(group) {
let items = menu[group] as [MenuItem]!
let cartItems = cart[group]
let itemsSet = Set<MenuItem>(items!)
let cartItemsSet = Set<MenuItem>(cartItems!)
let similarSet = itemsSet.intersection(cartItemsSet)
let similarArray = NSMutableArray(Array(similarSet))
let similarCounterSet = NSCountedSet(array: similarArray)
}
I want to create a struct based off the NSCountedSet class so that I can convert the array of common elements to a counted set.
The if statement is for something else, it does not pertain to this question.
Any thoughts on how to do this? If anybody has a different approach to this problem feel free to mention that too.
Thanks,
Simon

Thanks to Martin R I Found An Example of How to do This:
There are various CountedSet implementation available, e.g. https://github.com/0x7fffffff/CountedSet.

Related

Using CoreData to save array containing dictionaries

I'm trying to use CoreData framework inside an iOS app for the first time and I have some troubles with it.
I have a kind of complex type of array, containing tuples that contains dictionaries:
let DataSet: [( Float, Float, [String : String])] = ...
I created an NSManagedObjectContext and an NSManagedObject, I added the DataSet array to the NSManagedObject, but when I try to save the 1st NSManagedObjectContext, the app is crashing.
That's not happening using normal arrays but only with more complex ones like the one above.
Is there a way to deal with that problem? Do I need to adjust my xcdatamodel?
I would appreciate any help a lot.
First you need to declare 2 separate entities. One for Floats and another for Dictionary.
Then create "One to Many" relation ship between Float entity and Dictionary. It will look like this,
Then you need to convert your tuple into these 2 entities, Like this,
dataSet.forEach{ (member) in
let tuple = Test.(context: mainContext)
tuple.first = member.0
tuple.second = member.1
let dictionary = member.2
dictionary.forEach{ (key, value) in
let dick = Dick.(context: mainContext)
dick.key = key
dick.value = value
tuple.addToContains(dick)
}
}
Finally you need to save the values.
if mainContext.hasChanges {
do {
try mainContext.save()
} catch {
print(\(error))
}
}

Linking 2 strings (or arrays)

I'm trying to make a connection between multiple arrays. Example; (Mario bros)
var names = ["Mario", "Luigi"]
var colors = ["Red", "Green"]
Instead of making if-statements such as if names == "Mario" && colors == "Red" I would like to make an easier connection - just like buttons has tags I would like to make a String-tag ("Mario".tag = 1 and "Red".tag = 1)
Note that I have 10 different arrays such as the above.
Rather than having 10 parallel arrays, I suggest you create a struct with 10 properties, and make an array of those structs.
Structs are a package of data that abstracts away the details of the contents, and lets you deal with the data as a whole.
I would recommend you check out the Swift Programming guide (in its entirity). It's very well written. In particular, here is the page on Classes and Structs.
In addition, if you want to compare one struct to, say, Mario (as you do in your example), you could implement a method == and make your struct conform to the Equatable protocol, which will allow you do something like:
if someCharacter == Mario {... //automatically compares all properties.
See The Swift Programming Language (Swift 2.2) - Protocols.
First of all you need a ModelValue
struct Element {
let name: String
let color: String
}
Now given
let names = ["Mario", "Luigi"]
let colors = ["Red", "Green"]
you can create a list of Element(s).
let elements = zip(names, colors).map { Element(name: $0.0, color: $0.1) }
Finally your can use it
elements[0].name
elements[0].color

How to convert NSArray to Set?

Most of the posts here are on about how to convert a set into an array.But I would like to know if I could convert an array to a set.I have downloaded my array from parse and want to convert it to a set because I want the user to edit their details and the form builder I used needs to accept a set data type only.
This is what I got.The "Subjects" field is an NSArray in Parse.
let subjects = Set(currentuser?.objectForKey("Subjects"))
Basically the syntax is correct, but the compiler (and me too) doesn't know that the object for key Subjects is supposed to be an array. Use optional binding to check at least for an array of NSObject to conform to the requirement that the items in the array are hashable (thanks to dan for pointing that out):
if let userSubjects = currentuser?.objectForKey("Subjects") as? [NSObject] {
let subjects = Set(userSubjects)
}
If the real type of Subjects is more specific than [NSObject] use that instead

Multidimensional Array Looping in cellForRowAtIndexPath Swift

I have a multidimensional array that I want to display the values of onto one UILabel in each respective cell.
My arrays look like this:
var arrayExample = [["beverages", "food", "suppliers"]["other stuff, "medicine"]]
I'm looping through these values in the cellForRowAtIndexPath in order for it to display on different cells (on a UILabel) the appropriate values:
if let onTheLabel: AnyObject = arrayOfContactsFound as? AnyObject {
for var i = 0; i < objects!.count; i++ {
cell?.contactsUserHas.text = "\(onTheLabel[indexPath.row][i])" as! String
print("arrayOfContactsFound Printing! \(onTheLabel)")
}
}
When printing to the console I get:
arrayOfContactsFound Printing! (
(
beverages,
"supply chain",
pharmacuticals
)
)
But on my label I get "beverages". That's it. How can I get the other 2 values (or X amount if there are more or less than 3 values)?
My for in loop is obviously not doing the trick. Assuming I can optimize/fix that to display all the values?
Thanks in advance.
In your loop you're setting the text of your label multiple times. Each time you set it it doesn't accumulate, it completely replaces the current text with the new text. You'll want something like this:
// Remove the cast and the loop in your code example, and replace with this
let items = arrayOfContactsFound[indexPath.row]
let itemsString = items.joinWithSeparator(" ")
cell?.contactsUserHas.text = itemsString
Another thing to note is your cast doesn't quite make a lot of sense.
var arrayExample = [["beverages", "food", "suppliers"]["other stuff, "medicine"]]
So arrayExample is of type [[String]]. I'm assuming each cell in your table view represents one of the arrays of strings in your array. So each cell represents one [String]. So your items should be arrayExample[indexPath.row]. The cast to AnyObject doesn't make too much sense. If anything you'd be casting it to [[AnyObject]], but there's no reason to because the compiler should already know it's [[String]].

Swift automatically creating temporary dictionaries

I'm working with a datasource for a UITableView where I need an array with dictionaries.
I tried making an array, and filling it with dictionaries in a for loop like this.
temporaryDataDict = [:]
temporaryDataDict = ["name":stockName, "ticker":ticker, "lastPrice":lastPrice, "purchasePrice":purchasePrice, "weight":weight, "daysHeld":daysHeld]
temporaryDataArray.append(temporaryDataDict)
But of course, when I start filling my tableView with the dataSource. I end up for 23 of the exact same dictionaries (the last one in the for loop).
This is of course, because it's changing the dictionary every time.
I havn't been able to find a way to keep the data in the dictionaries, or programatically make a new dictionary every time (since they need a new name otherwise it'll overwrite the data).
So how can I programatically make dictionaries everytime a for loop runs, then get the keys & values of these dictionaries?
or am I going about this completely wrong?
If it helps, here's the kind of data I'm working with.
I have a stock (or item) with 6 properties. So I think it makes the most sense to have an array where every item in the array is the "stock" as a dictionary that contains the 6 properties.
So is it possible to make swift automatically create these dictionaries for me? Since I don't know the amount of dictionaries needed.
PS.
I know this is what CoreData is for. I'm using these arrays and Dictionaries to later fill in my CoreData.
If the above isn't possible I am aware that I can probably create a new CoreData entity to accomplish what I want, but it doesn't seem like the best way to go about it.
Any help would be greatly appreciated! Thanks
I don't believe that a dictionary is the best sort of data structure to use in this case. Since typically a dictionary is composed of a unique key and a value.
I have edited this answer. Originally I suggested creating a class containing a property for each record field. Then I figured that this could be done using a tuple via a typealias for each record. Using a typealias gets around an issue related to creating arrays of tuples.
ETA: However please read the comments because Zaph who knows more about this than me reckons that using a Class is a stronger solution.
This is my tuple based solution. Most of what follows is just about quickly creating some dummy data:
typealias StockRecord = (stockName:String, ticker: String, lastPrice: Double, purchasePrice: Double, weight: Double, daysHeld: Int)
var temporaryDataArray = [StockRecord]()
// use a loop to create dummy records and add each to the array
// rough and ready - just to test the solution
var loopCounter: Int
for loopCounter = 0; loopCounter <= 23; loopCounter++ {
//some dummy field values for each record
var stockName = "stockName" + ("\(loopCounter)")
var ticker = "ticker" + ("\(loopCounter)")
var lastPrice = Double(loopCounter)
var purchasePrice = Double(loopCounter)
var weight = Double(loopCounter)
var daysHeld = loopCounter
var newRecord = (stockName, ticker, lastPrice, purchasePrice, weight, daysHeld)
temporaryDataArray.append(newRecord)
}
ETA: Iterate over the array - eg:
for recordEntry in temporaryDataArray {
var a = recordEntry.stockName
var b = recordEntry.ticker
// etc
}
Or with enumeration - eg:
for (count,recordEntry) in enumerate(temporaryDataArray) {
println("\(count) \(recordEntry)")
}
Output:
0 (stockName0, ticker0, 0.0, 0.0, 0.0, 0)
1 (stockName1, ticker1, 1.0, 1.0, 1.0, 1)
2 (stockName2, ticker2, 2.0, 2.0, 2.0, 2)
3 (stockName3, ticker3, 3.0, 3.0, 3.0, 3)
etc

Resources