BLACK FRIDAY: Save 50% on all my Swift books and bundles! >>

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      

Save 50% in my WWDC sale.

SAVE 50% All our books and bundles are half price for Black Friday, so you can take your Swift knowledge further without spending big! Get the Swift Power Pack to build your iOS career faster, get the Swift Platform Pack to builds apps for macOS, watchOS, and beyond, or get the Swift Plus Pack to learn advanced design patterns, testing skills, and more.

Save 50% on all our books and bundles!

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

   

@chris  

Pretty nice post. I just stumbled upon your weblog and wanted to say that I have really enjoyed browsing your blog posts. After all I’ll be subscribing to your feed and I hope you write again soon!

   

we are doing best here valeurnette.fr

   

Save 50% in my WWDC sale.

SAVE 50% All our books and bundles are half price for Black Friday, so you can take your Swift knowledge further without spending big! Get the Swift Power Pack to build your iOS career faster, get the Swift Platform Pack to builds apps for macOS, watchOS, and beyond, or get the Swift Plus Pack to learn advanced design patterns, testing skills, and more.

Save 50% on all our books and bundles!

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.