UPGRADE YOUR SKILLS: Learn advanced Swift and SwiftUI on Hacking with Swift+! >>

Data from multiple entities into array for math ops

Forums > Swift

Hello,

I have multiple entities of a type which I would like to extract all of the elements of a certain field into an array and then perform a math operation onto it. An example is if I had multiple homes each with a field 'price' and I would like to determine the max price. I expect either a fetch or or calling allObjects and converting the target field to an array operation followed by calling .max() on the array. Thank you

3      

You can use NSExpression to create a fetch request for the following functions: sum, count, min, max, and average.

Some sample code (from Group by, Count and Sum in CoreData | Cocoanetics):

let keypathExp1 = NSExpression(forKeyPath: "col")
let expression = NSExpression(forFunction: "sum:", arguments: [keypathExp1])
let sumDesc = NSExpressionDescription()
sumDesc.expression = expression
sumDesc.name = "sum"
sumDesc.expressionResultType = .integer64AttributeType

let request = NSFetchRequest(entityName: "Record")
request.returnsObjectsAsFaults = false
request.propertiesToFetch = [sumDesc]
request.resultType = .dictionaryResultType

Another example, from objc.io's book Core Data (pp82-83):

let request = NSFetchRequest<NSManagedObject>(entityName: "Employee") 
request.resultType = .dictionaryResultType

let salaryExp = NSExpressionDescription() 
salaryExp.expressionResultType = .doubleAttributeType
salaryExp.expression = NSExpression(forFunction: "average:", arguments: [NSExpression(forKeyPath: "salary")])
salaryExp.name = "avgSalary" 

request.propertiesToGroupBy = ["type"]
request.propertiesToFetch = ["type", salaryExp] 
_ = try! context.fetch(request)

Hopefully these can get you started. And maybe someone else on here has an example from their own code they can share.

3      

thanks for posting, I believe the first example is exactly what I am looking for. Will try it out

3      

Hacking with Swift is sponsored by Essential Developer

SPONSORED Join a FREE crash course for mid/senior iOS devs who want to achieve an expert level of technical and practical skills – it’s the fast track to being a complete senior developer! Hurry up because it'll be available only until April 28th.

Click to save your free spot now

Sponsor Hacking with Swift and reach the world's largest Swift community!

hmm, I must be missing something.

let's take a simple department, employee example, in which I would like to find the sum of employee computers. The following expected code does not work for me. What am I doing wrong? results is always invalid. Thank you


let keypathExp1 = NSExpression(forKeyPath: "computer")
let expression = NSExpression(forFunction: "sum:", arguments: [keypathExp1])
let sumDesc = NSExpressionDescription()
sumDesc.expression = expression
sumDesc.name = "sum"
sumDesc.expressionResultType = .integer64AttributeType

let request = NSFetchRequest(entityName: "department")
request.returnsObjectsAsFaults = false
request.propertiesToFetch = [sumDesc]
request.resultType = .dictionaryResultType

let fetch: NSFetchRequest = department.fetchRequest()
do{
    let results = try? fetch.execute()
    print(results ?? "invalid?")  // results is now an array
}
catch {
   NSLog("Error fetching entity: %@", error.localizedDescription)
}

Edit: put source in code block for clean formatting

3      

First things first...

When posting code to these forums, place three backticks ``` on the line before your code and three backticks ``` on the line after your code so that it will be formatted properly. You can also highlight an entire code block and click the </> button on the toolbar to wrap the block for you.

This makes it far easier to read and also makes it easier for other posters to copy/paste the code in order to test solutions and such.

Doing this will ensure that you end up with something like this:

let keypathExp1 = NSExpression(forKeyPath: "computer") 
let expression = NSExpression(forFunction: "sum:", arguments: [keypathExp1]) 
let sumDesc = NSExpressionDescription() 
sumDesc.expression = expression 
sumDesc.name = "sum" 
sumDesc.expressionResultType = .integer64AttributeType

let request = NSFetchRequest(entityName: "department") 
request.returnsObjectsAsFaults = false 
request.propertiesToFetch = [sumDesc] 
request.resultType = .dictionaryResultType

let fetch: NSFetchRequest = department.fetchRequest() 
do{ 
    let results = try? fetch.execute() 
    print(results ?? "invalid?") // results is now an array 
} catch { 
    NSLog("Error fetching entity: %@", error.localizedDescription) 
}

instead of this:

let keypathExp1 = NSExpression(forKeyPath: "computer") let expression = NSExpression(forFunction: "sum:", arguments: [keypathExp1]) let sumDesc = NSExpressionDescription() sumDesc.expression = expression sumDesc.name = "sum" sumDesc.expressionResultType = .integer64AttributeType

let request = NSFetchRequest(entityName: "department") request.returnsObjectsAsFaults = false request.propertiesToFetch = [sumDesc] request.resultType = .dictionaryResultType

let fetch: NSFetchRequest = department.fetchRequest() do{ let results = try? fetch.execute() print(results ?? "invalid?") // results is now an array } catch { NSLog("Error fetching entity: %@", error.localizedDescription) }

4      

bump

3      

Sorry it's taken me so long to respond; real life got in the way for a while.

Anyway, check out this simple sample project I uploaded to github: roosterboy/CoreDataFunctions

Hopefully, this will give you a good idea how to do what you are looking to do.

4      

thanks so much for the reply @roosterboy. Taking a look at this solution now. Will reply back

3      

sorry that it has been this long, but I have finally been able to download and run this code. And it seems to suit my purpose, thanks for putting it together, especially the sweet preview readme file. I am going to dig in and add this to my project. Stay tuned!

3      

Hello,

In response to https://www.hackingwithswift.com/forums/swift/data-from-multiple-entities-into-array-for-math-ops/18754/18881 above, I have cloned and tested that project and it works great!

I have adapted it to my project, and it works in some capacity there too. My project (weight lifting data logger) has core data for a number of exercises and each exercise has one or more sets. Sets contain a weight lifted and the number of repetitions completed. I am able to fetch the maximum weight lifted across sets of all exercises (bench press, squat, etc), which is good, however I would like to fetch the max weight of all sets limited to a given exercise. How can I accomplish this? I expect that an NSPredicate may be part of the solution, but I am not able to find something working in a search. Alternatively, I believe it could be by exercising the relationship from set to exercise (which is an inverse relationship in my data). Any help is appreciated.

The function that I have and is working now to get max of all sets in the data:

    func maxSetWeight() -> Float {
        let request = NSFetchRequest<NSDictionary>(entityName: "Set")
        request.resultType = .dictionaryResultType

        let maxWeightExpression = NSExpressionDescription()
        maxWeightExpression.expressionResultType = .floatAttributeType
        // max, min, sum, average
        maxWeightExpression.expression = NSExpression(forFunction: "max:", arguments: [NSExpression(forKeyPath: "weight")])
        maxWeightExpression.name = "maxSetWeight"

        request.propertiesToFetch = [maxWeightExpression]

        let result = try! container.viewContext.fetch(request) as! [[String: AnyObject]]
        let maxSetWeight = result[0]["maxSetWeight"] as? Float ?? 0.0
        return maxSetWeight
    }

My data model:

Exercise {String name}
Set {UUID id, Float weight, Int16 reps} has relationship {exercises} Destination {Exercise} Inverse {sets}

3      

bump

3      

bump, still looking for suggestions on this! thanks

2      

You can achieve this by fetching the entities and extracting the 'price' field into an array. Here's a quick example in Python:

# Assuming 'homes' is your collection of entities
prices = [home['price'] for home in homes]

# Now, find the max price
max_price = max(prices)

# 'max_price' holds the maximum price value

Feel free to adapt it to your specific implementation.

2      

https://www.hackingwithswift.com/forums/swift/data-from-multiple-entities-into-array-for-math-ops/18754/25156 is a correct python representation of the info I am trying to extract. But I do not see how to use the NSFetch to do the equivalent. Substituting the entities for my case:

weights = [exercises['weights'] for 'Bench Press' in exercises]

max_weight = max(weights) // this is specific to the exercise 'Bench Press'

2      

bump, still looking for suggestions on this! thanks

   

Hacking with Swift is sponsored by Essential Developer

SPONSORED Join a FREE crash course for mid/senior iOS devs who want to achieve an expert level of technical and practical skills – it’s the fast track to being a complete senior developer! Hurry up because it'll be available only until April 28th.

Click to save your free spot now

Sponsor Hacking with Swift and reach the world's largest Swift community!

Reply to this topic…

You need to create an account or log in to reply.

All interactions here are governed by our code of conduct.

 
Unknown user

You are not logged in

Log in or create account
 

Link copied to your pasteboard.