Swift Realm Results to Editable object or array - swift

OK, I understand that I can not modify the results of a Realm Object.
So what is best way to change the data.
First I get all the Realm data as Results< Month >
let m = Month.getAllEntriesByDateAsc()
Now I need to loop through all the data to modify it. (This is a function to recalculate the entire table data.)
So I want to loop through the data and do something like:
for i in m {
var d = i
// perform calculations like
d.value = 9999
}
I want to do all the modifying on d.
Is these some sort of mapping I can use to create the new edible object from the Realm data?
Previously I did something like this:
for i in m {
let d = Month()
d.value = i.value
d.status = i.status
}
But there are now to many variables.
I guest what I need to so change the Realm Object to the Model object?
And the .toArray() stuff will not work inside the loop? Not sure why.
Thanks.

extension Results {
func toArray<T>(ofType: T.Type) -> [T] {
var array = [T]()
for i in 0 ..< count {
if let result = self[i] as? T {
array.append(result)
}
}
return array
}
}
From here

Related

how to read data into object array in Swift 4

class Employee{
var id:Int
var name:String
var salary:Int
init(){
self.id=0
self.name=""
self.salary=0
}
func getInfo(){
self.name=readLine()!
self.id=Int(readLine()!)!
self.salary=Int(readLine()!)!
}
}
var count=0
var flag="y"
var empData:[Employee]=[]
repeat{
count+=1
empData[count]=Employee()
empData[count].getInfo()
flag=readLine()!
}while(flag=="y") `
I have a class Employee with properties id , nam and salary. The function getInfo() is used to get information from user. I want to read data until the flag!="y" . I am getting index out of range error.
What is the right way of inputting data? Can we index the objects ?
You need to append to your array to make it increase in size. Replace
empData[count]=Employee()
with
empData.append(Employee())
to avoid index out of range error
Update
To make your code a little less horrible I would do
repeat {
var employee = Employee()
employee.getInfo()
empData.append(employee)
flag=readLine()!
}while( flag == "y" )
The subscript operator cannot be used to add elements to an array index which doesn't exist yet. You either need to initialize the array with an element count if you know at the time of initialization how many elements your array will have or use the append operator to add new elements to the array after the last index.
You don't even need the count variable, as you can simply access empData.last safely after calling append and adding a new Employee to the Array.
var flag="y"
var empData:[Employee]=[]
repeat {
empData.append(Employee())
empData.last!.getInfo()
flag=readLine()!
} while(flag=="y")
I would advise you to seriously reconsider your implementation as it is really unsafe at the moment. You are not validating user input in any way, hence your getInfo function can easily cause runtime errors if the user input is not in the expected form. Moreover, creating an empty initializer for Employee doesn't make sense, you could simply create a failable initializer, where you read the input and if the input is not of the correct form, make the initializer return nil.
class Employee{
let id:Int
let name:String
let salary:Int
init?(){
guard let name = readLine() else { return nil }
self.name = name
guard let idString = readLine(), let id = Int(idString) else { return nil }
self.id = id
guard let salaryString = readLine(), let salary = Int(salaryString) else { return nil}
self.salary = salary
}
}
var flag="y"
var empData:[Employee]=[]
repeat {
if let employee = Employee() {
empData.append(employee)
} else {
// Display error message to the user
}
flag=readLine() ?? ""
} while(flag=="y")

Swift step through dictionary

I was wondering if there's a way to step through a dictionary in Swift. I know I can iterate through, but I was hoping to step one by one through a dictionary of items as the user taps a "next" button.
I was thinking I could initially iterate through the dictionary and store the keys in an array, then step through the keys and retrieve each item as needed, since the array can be indexed. This seems a little inelegant, though. Any thoughts?
My current approach:
var iterator = 0
var keys = [String]()
func loadKeys() {
for (key, value) in items {
keys.append(key)
}
}
func step() {
iterator += 1
let currentKey = keys[iterator]
let currentItem = items[currentKey]
}
I figure it would work just fine, just not sure it's the best practice.
Thanks for your help!
A dictionary also provides you with an iterator, so you can step through it using that:
var iterator = items.makeIterator()
func step() {
if let v = iterator.next() {
let currentKey = v.key
let currentValue = v.value
}
}
A dictionary is an indexed collection, so you can use a dictionary's index to step through the keys and values:
var i = items.startIndex
func step() {
guard i != items.endIndex else {
// at the end of the dictionary
return
}
let (currentKey, currentValue) = items[i]
i = items.index(after: i)
}

Swift rating system loop and assign

Trying to build a rating system in Swift and looking for a cleaner way to loop through each of the values.
private func calculateRating(user: String) throws -> String {
let query = try Rating.makeQuery().filter("user", user).all()
var fiveStars = [Int]()
var fourStars = [Int]()
var threeStars = [Int]()
var twoStars = [Int]()
var onestar = [Int]()
if query.count > 1 {
for rating in query {
// Check each value and assign it to its associated value
// insert large if/else condition here :)
}
// Perform calculation and return value below
return ""
} else {
// Only one rating has been set
return query[0].value
}
}
Currently I'm looping through each of the values and assigning the rating to it's associated array fiveStars fourStars etc. I will then calculate the rating by the standard multiplication method. Is there a cleaner way to loop through the ratings and assign it to the relevant fiveStars array etc without creating a long if/else conditional?
Thanks
Edit: Sample output would be a single rounded up value out of 5 i.e. "4" out of five based on 1000's of multiple ratings.
let twoStars: [Int] = query.filter {$0.val == 2} .map {$0.val}
And so on.

Swift diff realm.io without fetching it in advance

I was wondering if there is a possibility in realm.io (swift) to select all items from one "table" that are not in the other one.
Lets say you have 2 classes:
class A: Object {
dynamic var id: Int = 0
dynamic var text: String = ""
}
class B: Object {
dynamic var id: Int = 0
dynamic var value: Bool = false
}
Is it possible to get an result of items from A who's id is not present in B?
There is actually a very simple way to do this using NSPredicate on Realm filter API.
func fetch() throws -> [A] {
do {
// Create Realm
let realm = try Realm()
// Get B objects from Realm and put their IDs to [Int] array
let IdB: [Int] = realm.objects(B).map { $0.id }
// Create predicate
// Filter all items where property id is not present in array IdB
let predicateFilter = NSPredicate(format: "NOT (id IN %#)", IdB)
// Get all A objects from array using predicateFilter
let objectsA = realm.objects(A).filter(predicateFilter)
// Return the [A] array
return objectsA.map { $0 }
} catch {
// Throw an error if any
throw error
}
}
Also note that all objects from fetched using Realm are lazy loaded which means that this method is also very fast. From the documentation:
All queries (including queries and property access) are lazy in Realm. Data is only read when the properties are accessed.

How to remove duplicate data in the UIPickerView in Swift

May I know how to remove the duplicate data which all the data is passing from the Parse database. I just select one column and pass that column data to this picker view.
I've try to find the query.wherekey but it didn't have the DISTINCT function which similar to the SQL statement, so what should I do to avoid the data duplication?
As you add items one by one into your self.pickerString array, just verify if this array contains or not the new value before addObject new value to the array. For example:
if !self.pickerString.contains(object["Intake"] as! String) {
self.pickerString.append(object["Intake"] as! String)
}
There is no built-in function to remove duplicate items in an array in swift (correct me if I'm wrong). However, you can add new features for array with 'extension' keyword:
extension Array {
func distinct<T: Equatable>() -> [T] {
var newArray = [T]()
for item in self {
if !contains(newArray, item as! T) {
newArray.append(item as! T)
}
}
return newArray
}
}
usage:
let s = ["344","333","1","2","333"]
var p = s.distinct() as [String]
I don't think you have anything like distinct on Parse, you'll have to download all rows and then filter out equal values.
For a functional approach:
func distinct<T: Equatable>(source: [T]) -> [T] {
var unique = [T]()
for item in source {
if !contains(unique, item) {
unique.append(item)
}
}
return unique
}
[...]
self.pickerString = distinct(objects)
[...]