calculations in coredata results

Discussion in 'iOS Programming' started by mraheel, Jan 28, 2012.

  1. mraheel macrumors regular

    Joined:
    Apr 18, 2009
    #1
    I've read multiple tutorials about core data but most of them have to do with basic setup.. I hope ill learn more each day about it. Cuz it made somethings very simpler. Though the absolute control that sqlite gives was a bit of a tradeoff.. but maybe I'm completely wrong!

    Here I'm trying to fetch things differently..


    Lets say I'm trying to RECORD as well as calculate results based on values stored in core data.

    Lets take Enery equation : E=mc(square)

    I have three entities, Parent/Child/RecentRecords

    **A Category's entity**
    Category
    -Name : Einstein's equation
    -E = mc2

    **Child Entity:**
    - Name: Mass

    another entry:
    - Name:LightSpeed (for the sake of example, lets say the speed of light is not constant.

    Recent Entity: The purpose of this entity is to store and track the Child Entities and so it has:
    -NSDate TimeStamp
    -NSNumber: Value
    -Relationship <---->>ChildEntity

    I'll explain from a User's point of view,
    If I tap "Einstain's equation" (Category/Parent Entity), the detail view will bring out 2 textfields by iterating through the Child entity. When I record my entries of mass, light speed, it should be saved in the Recent entity. SO that overtime i can have a bunch of recordings.

    Now image a similar setup for another formula, v=U+at. where Velocity would be parent. U, a, t would be in CHild entity. And in one recording a user would add three Recent Entity objects.

    My question is I want to find out if theres an efficient way to calculate the results/entries at the Parent/Category entity level.

    Because, EinstainsEquation stores the formula of its child entities, E=mc2 and V=u+at. The thing thats making this complicated is fetching the entries from the recent Entity based on timestamp (recording) and calculating it and showing the result based on the most recent entries.


    Code:
           Parent<-------->>Child<-------->>Recent
            -Einstein <---->>Mass <----------->>Multiple Mass recordings based on time
            -mc2             LightSpeed <------>>Multiple Lighspeed records based on time
            
            -Velocity<------>>U            <--------->>Multiple entries based on time of all 3.
            -u+at             Aceleration
                              TimeTaken
    Based on the graph above, I need to get einstein result FROM the most recent entries of mass/lightspeed and calculate each of those entries with its formula mc2.

    I thought of having a transient Property in Parent entity, how would i go about accomplishing this? How can i use the formula and calculate the child values of recent entity.

    Im kinda lost here..
     
  2. dantastic macrumors 6502a

    dantastic

    Joined:
    Jan 21, 2011
    #2
    I may be misunderstanding what you are trying to do. I think you're trying to have core data calculate something for you and the simple answer is that it can't.

    Core data holds data, you are looking for information, information is a calculated value from the data.

    Data is - "this post was made 2012"
    Information is - "This post was posted this year"

    The information will be outdated next year and will have to be recalculated - you have to do this yourself somehow.


    So you want to get the information based on the last entry of these. If the mass object and the light speed object can be faulted from the same Einstein object then it's all gravy. Then you can make any calculations in a Category of your enisten object and just get the mass and light speed from there.

    If not then you will need to fetch the last light speed object, fetch the last mass object - get the values you need from each, calculate the information you need.

    In this case I see no point in keeping the einstein object though. You create core data entities so that you can add an arbitrary number of objects of that kind, your einstein object is more of a method?
     
  3. mraheel thread starter macrumors regular

    Joined:
    Apr 18, 2009
    #3
    Thanks for replying :)

    Yea, It mass/lightspeed were in the same object as einstein's, this would be kool. But einstain's formula is an object in an entity that holds other formulae.. pertaining to physics, and child entity holds the physical variables.
    there could be more like poiselle's equation, laplace' law, so its more like a formulae category.

    My idea was to somehow store the formula relation within the ParentCategory like ..
    Parent/FormulaEntity
    -name= Einstein
    -Formula=m*(c*c) [mc square].

    If i figure out a way to get the latest Entry of each of child entity of that Formula, from the category object, that would save my life..

    like
    in
    FormulaEntity.m
    Code:
    -(NSNumber*)calculate{
     //Get the latest Child first..
      NSSet *childSet = [self childs];
          //get the two child - mass/lightspeed
          ChildObj1 = [childset objectatindex:0]; (Mass)
          CHildobj2  (Lightspeed)
    
          //then get the last entry... or even an array of all entries made for each of these variables.. mass and light speed.. 
    
      i dunno what comes here..
       
    
      //after getting values,
       return the calculated NSNumber based on self.formula; 
    
    }
     

    this is what I'd want, if i return an array here it self, it could give me the calculated values of the entires..


    I hope you understand what I'm looking for, cuz this thing is hard to explain even for me..
     
  4. mfram macrumors 65816

    Joined:
    Jan 23, 2010
    Location:
    San Diego, CA USA
    #4
    I think I've going to answer the question you're looking for, but I'm not sure. I have a similar situation. I have a game that remembers a game log (scores, dates, stats, etc). Some of the data presented by the "ScoreEntity" class is derived from data stored in CoreData. That derived value is calculated.

    Add an extra property to the class that's not stored in core data, and create accessor routines that return the data.

    In this class, the data specified in the interface is the data stored in CoreData. But there's an extra property at the end called "gameLPM" (game lines per minute) that's calculated.

    Code:
    @interface ScoreEntity : NSManagedObject {
        NSString * playerName;
        NSNumber * gameScore;
        NSDate * gameDate;
        NSNumber * gameDuration;
        NSNumber * gamePieces;
        NSNumber * gameLines;
      
    @private
    }
    @property (nonatomic, retain) NSString * playerName;
    @property (nonatomic, retain) NSNumber * gameScore;
    @property (nonatomic, retain) NSDate * gameDate;
    @property (nonatomic, retain) NSNumber * gameDuration;
    @property (nonatomic, retain) NSNumber * gamePieces;
    @property (nonatomic, retain) NSNumber * gameLines;
    @property (nonatomic, retain) NSNumber * gameLPM;
    
    Implementation:

    Code:
    @implementation ScoreEntity
    @dynamic playerName;
    @dynamic gameScore;
    @dynamic gameDate;
    @dynamic gameDuration;
    @dynamic gamePieces;
    @dynamic gameLines;
    
    - (void) awakeFromInsert
    {
        [super awakeFromInsert];
        
        [self setPrimitiveValue:[NSDate date] forKey:@"gameDate"];
        [self setPrimitiveValue:NSFullUserName() forKey:@"playerName"];
    }
    
    - (NSNumber *)gameLPM
    {
        double lpm;
        
        [self willAccessValueForKey:@"gameLPM"];
    
        if ([gameDuration intValue] == 0)
        {
            lpm = 0.0;
        }
        else
        {
            lpm = ([gameLines doubleValue] * 60) / [gameDuration doubleValue];
        }
    
        [self didAccessValueForKey:@"gameLPM"];
    
        return [NSNumber numberWithDouble:lpm];
    
    }
    
    - (void)setGameLPM:(NSNumber *)gameLPM
    {
        return;
    }
    
    There is an extra property being presented that's derived from other data stored in CoreData. Setting the value doesn't do anything, the value is ignored. But the set routine should be there to follow the property convention.
     
  5. forum user macrumors regular

    Joined:
    Aug 28, 2008
    #5
    You lost me there with light speed, that is way above me. To be honest that is at least one or two lightyears above me. Actually from where I observe anything faster than Autobahn speed is considered ludicrous speed. Anyway:

    You might want to look at constructing your NSFetchrequests using
    Code:
    NSExpression expressionForFunction:@"max:" arguments:[NSArray arrayWithObject:[NSExpression expressionForKeyPath:@"xx-your-timestamp-attribute-here-xx"]] 
    Stackoverflow has a few questions and examples for that. Set your
    Code:
    NSExpressionDescription setExpressionResultType:NSObjectIDAttributeType
    Assuming you store your timestamps as NSDate and not as NSString then the max: will cause the return of the objectID of the entry with latest timestamp available for the given entity. Retrieve the attributes for that objectID and you can do your calculations.

    - Olaf
     
  6. mraheel thread starter macrumors regular

    Joined:
    Apr 18, 2009
    #6
    Hey thanks guys, I did make some changes based on @mfram said, Im adopting the method as you said, probably gonna reach somewhere.. hopefully,



    Just wondering if I could use a transient property? for a result property? I don't have to store it anyway.. ?

    Haha, im struggling to keep up myself, in my attempt to in inSync with Apple and its namingConventions I inadvertently cameUp with lightSpeed for speed of light., Im reading about NSExpression, should come up with something soon.. its pointed me in the right direction!

    Amm, I have a new core data question here, i dunno if i should continue here instead of starting a new thread?.. ahem, here i go again, though this core data has a steep learning curve, its pretty neat and fast once its understood well.. I'm still on the way,
    consider this image:
    [​IMG]
    Lets say this thing is about business cards, theres an entity called User, which stores the user accounts using the application and adding their collection of business cards, it could be the user's or any body else,

    Cardgroup holds like "Workplace", "friends", "silicon valley", which has a many-to-many relationship with cardPerson, this is because a person can be a friend and work in silicon valley as well.. so this is a many-to-many relation ship.
    1 cardPerson can belong to many cardGroup(s)
    1 cardGroup can have many cardPersons.

    cardentry is about much the latest card a card person holds, each card person can hold many jobs thus many cards.

    MY QUESTION IS,...

    Question 1:
    I want One User to have just One CardPerson,
    lets say a User with "john" user name is logged in. He creates a cardgroup with name "WallStreet" adds a cardPerson "Dom" to it. He also creates another cardGroup called "friends" and adds a cardPerson "Dom" again.


    Only this time, I want "Dom" to not be created but taken from an already existing cardPerson object... he already added it to wallstreet group. the behavior I'm looking for is that he should now just "choose" Dom instead of creating a new one and add it to "friends" cardGroup. how can i accomplish this behavior?


    THIS CHANGES.... when the "USER" John logged off,.. and another User "Sam" logs on, Sam will not have "dom" even though its already there in cardPerson entity. Sam should be able to create a friend "Dom" and add the same object to his groups. just like "John" did..

    Question 2:

    So should the User and CardPerson share some relationship? or should i again work my way through it?? and how?

    note: if this calls for a new thread to be created, .. i will,
     
  7. seepel macrumors 6502

    seepel

    Joined:
    Dec 22, 2009
    #7
    It sounds like what you want to do is parse the equation stored in core data and turn the equation into a set of operations that can be run on the variables. To get a general use case will be non-trivial as you will have to program the parsing of each operator (e.g. plus sign means add).

    If you are pre programming all the equations this becomes a bit easier, just store the variables in core data and add a calculate message to the class as mfram suggested.

    If you want to allow a use to input their own formula you will have to work out a parser that can translate the equation (as I mentioned above). Then run the translated operators.
     
  8. dantastic macrumors 6502a

    dantastic

    Joined:
    Jan 21, 2011
    #8
    I'm still a bit curios what you are actually building here. You can store an expression as a string in core data - then have different other entities as children here and then querying a transient property you can calculate the value you want.

    But this isn't very scalable. What other equations are you looking to add? You can't add just any equation as you only have a mass object and a lightspeed object to modify - so this will only scale as far as you can do the calculation with 1 lightspeed object and 1 mass object.

    If you still want to do this you can read up on: http://funwithobjc.tumblr.com/post/6196535272/parsing-mathematical-expressions But I think you are probably better off designing this differently to begin with.

    As for your new question this is how you'd fetch or create for existing. I think this should answer q2 as well really.
    Code:
    
    NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
    // fetch a card person.
    NSEntityDescription *entity = [NSEntityDescription entityForName:@"CardPerson" inManagedObjectContext:self.managedObjectContext];
    [fetchRequest setEntity:entity];
    	
    // fetch a person with firstname Dom. And, go through the groups object,
    // go through the user object, the userName must be John.
    NSPredicate *predicate = [NSPredicate predicateWithFormat:@"firstName = %@ AND groups.user.userName = %@", @"Dom", @"John"];
    [fetchRequest setPredicate:predicate];
    	
    NSError *error = nil;
    NSArray *fetchedObjects = [self.managedObjectContext executeFetchRequest:fetchRequest error:&error];
    if (fetchedObjects == nil) {
    	NSLog(@"critical core data error");
    	abort();
    }
    [fetchRequest release];
    
    CardPerson *dom = nil;
    if (fetchedobjects count] > 0) {
    	dom = [fetchedObjects objectAtIndex:0];
    }
    else {
    	dom = [NSEntityDescription insertNewObjectForEntityForName:@"CardPerson" inManagedObjectContext:self.managedObjectContext];
    	dom.firsrtName = @"Dom";
    }
    
    // add the dom object to the group. Save the context.
    
    
     
  9. mraheel thread starter macrumors regular

    Joined:
    Apr 18, 2009
    #9
    Yes it isn't cuz your thinking only two child entities exist -- mass/lightspeed.
    Im looking to build a db where,

    I could add Energy(einsteins) as ParentObject, it has two child entities - mass/lightspeed. (E = mc^2)

    Another could be Velocity as a ParentObject, which will have U(early speed), Aceleration and Timetaken as child entities. (v= u+at)

    Einstain object and velocity object are unrelated, their child entities are unrelated to each other. Having said that..

    Now the User taps Einstein, two textfields come up based on ChildEntities. After adding values to mass (textfield1) and light speed(textfield2), it gets stored as an "EntryObject" in the entries Entity. with the value(typed) and timestamp!

    Imagine the same thing all over again for "velocity" and its formula of v=u+at. in this case there are 3 input values.

    you've pointed me to the right direction, i definitely need a math parser. This is getting more difficult than i thought, to use 3rd party libraries!

    I hope you got me now..

    There may be a time, when two formulae (stored in the ParentEntity) may share a Child, For example,

    E = mass x speedoflight.
    Density = mass / volume.

    In this case, mass is common (lets assume) to both formulae, if so, i want there to be ONLY ONE child as "Mass". Both formulae can just use that instead of adding more!..

    I'd really like you to suggest me another way perhaps, and i do want scalability..
     
  10. seepel macrumors 6502

    seepel

    Joined:
    Dec 22, 2009
    #10
    I think that the description of the problem is a bit vague. Why is it important to store the values in core data? Why does the data the user inputs need to be persistent? Why is it important that the same mass be useable in two different equations? On that note, are the units important? Are you going to preload all the equations or are you going to let the user define equations? What exactly is the end goal?
     
  11. mraheel thread starter macrumors regular

    Joined:
    Apr 18, 2009
    #11
    Hey,

    Well, storing is only to track the results, this isn't just a calculator. Tracking is also important to it.
    Its not important that mass value be static, its for my understanding that if its chosen to be static how should i go about it..

    This is more of and understanding app ... to understand the methods of core data more than anything else.
     

Share This Page