Core DAta: Get a random row from the fetched result - objective-c

I'm looking for a memory efficient way to take only one row from a fetch result set. This must be random.
I thought using [context countForFetchRequest:fetch error:nil]; and get an int random value between 0 and that and offset + limit the fetch to 1 result. But I can't find whether or not it doesn't allocate memory for each item it counts.
Is "count" a lightweight operation? Or does it need to instantiate objects in the context before being able to count them?

The documentation is somewhat unclear, but it includes the phrase "number of objects a given fetch request would have returned." Furthermore, Core Data tends to make things like count very lightweight - entity instances, for example, allow you to call count to find out the number of objects on the end of a to-many relationship without instantiating all those objects or firing that fault. I'd say go for it, but profile it yourself - don't optimize prematurely!

Related

Redis Sorted Set ... store data in "member"?

I am learning Redis and using an existing app (e.g. converting pieces of it) for practice.
I'm really struggling to understand first IF and then (if applicable) HOW to use Redis in one particular use-case ... apologies if this is super basic, but I'm so new that I'm not even sure if I'm asking correctly :/
Scenario:
Images are received by a server and info like time_taken and resolution is saved in a database entry. Images are then associated (e.g. "belong_to") with one Event ... all very straight-forward for a RDBS.
I'd like to use a Redis to maintain a list of the 50 most-recently-uploaded image objects for each Event, to be delivered to the client when requested. I'm thinking that a Sorted Set might be appropriate, but here are my concerns:
First, I'm not sure if a Sorted Set can/should be used in this associative manner? Can it reference other objects in Redis? Or is there just a better way to do this altogether?
Secondly, I need the ability to delete elements that are greater than X minutes old. I know about the EXPIRE command for keys, but I can't use this because not all images need to expire at the same periodicity, etc.
This second part seems more like a query on a field, which makes me think that Redis cannot be used ... but then I've read that I could maybe use the Sorted Set score to store a timestamp and find "older than X" in that way.
Can someone provide come clarity on these two issues? Thank you very much!
UPDATE
Knowing that the amount of data I need to store for each image is small and will be delivered to the client's browser, can is there anything wrong with storing it in the member "field" of a sorted set?
For example Sorted Set => event:14:pictures <time_taken> "{id:3,url:/images/3.png,lat:22.8573}"
This saves the data I need and creates a rapidly-updatable list of the last X pictures for a given event with the ability to, if needed, identify pictures that are greater than X minutes old ...
First, I'm not sure if a Sorted Set can/should be used in this
associative manner? Can it reference other objects in Redis?
Why do you need to reference other objects? An event may have n image objects, each with a time_taken and image data; a sorted set is perfect for this. The image_id is the key, the score is time_taken, and the member is the image data as json/xml, whatever; you're good to go there.
Secondly, I need the ability to delete elements that are greater than
X minutes old
If you want to delete elements greater than X minutes old, use ZREMRANGEBYSCORE:
ZREMRANGEBYSCORE event:14:pictures -inf (currentTime - X minutes)
-inf is just another way of saying the oldest member without knowing the oldest members time, but for the top range you need to calculate it based on current time before using this command ( the above is just an example)

Keeping an array sorted - at setting, getting or later?

As an aid to learning objective c/oop, I'm designing an iOS app to store and display periodic bodyweight measurements. I've got a singleton which returns a mutablearray of the shared store of measurement object. Each measurement will have at least a date and a body weight, and I want to be able to add historic measurements.
I'd like to display the measurements in date order. What's the best way to do this? As far as I can see the options are as follows: 1) when adding a measurement - I override addobject to sort the shared store every time after a measurement is added, 2) when retrieving the mutablearray I sort it, or 3) I retrieve the mutablearray in whatever order it happens to be in the shared store, then sort it when displaying the table/chart.
It's likely that the data will be retrieved more frequently than a new datum is added, so option 1 will reduce redundant sorting of the shared store - so this is the best way, yes?
You can use a modified version of (1). Instead of sorting the complete array each time a new object is inserted, you use the method described here: https://stackoverflow.com/a/8180369/1187415 to insert the new object into the array at the correct place.
Then for each insert you have only a binary search to find the correct index for the new object, and the array is always in correct order.
Since you said that the data is more frequently retrieved than new data is added, this seems to be more efficient.
If I forget your special case, this question is not so easy to answer. There are two basic solutions:
Keep array unsorted and when you try to access the element and array is not sorted, then sort it. Let's call it "lazy sorting".
Keep array sorted when inserting elements. Note this is not about appending new element at the end and then sort the whole array. This is about finding where the element should be (binary search) and place it there. Let's call it "sorted insert".
Both techniques are correct and useful and deciding which one is better depends on your use cases.
Example:
You want to insert hundreds of elements into the array, then access the elements, then again insert hundreds of elements, then access. In summary, you will be inserting values in big chunks. In this case, lazy sorting will be better.
You will often insert individual elements and you will access the elements often. Then sorted insert will have better performance.
Something in the middle (between inserting 1 and inserting tens of elements). You probably don't care which one of the methods will be used.
(Note that you can use also specialized structures to keep an array sorted, not based on NSArray, e.g. structures based on a balanced tree, while keeping number of elements in the subtree).

Better to use size or count on collection?

When counting a collection. Is it better to do it via size or count?
Size = Ruby (#foobars.size)
Count = SQL (#foobars.count)
I also notice, count makes another trip to the db.
I tend to suggest using size for everything, just because it's safer. People make fewer silly mistakes using size.
Here's how they work:
length: length will return the number of elements from an array, or otherwise loaded collection - the key point is that the collection will be loaded here regardless. So if you're working with an activerecord association, it will pull the elements from the DB to memory, and then return the number.
count: count issues a database query, so if you have an array already it's a pointless call to your database.
size: best of both worlds - size checks which type you're using and then uses whichever seems more appropriate (so if you have an array, it will use length; if you have an unretrieved ActiveRecord::Association it will use count, and so on).
Source:
http://blog.hasmanythrough.com/2008/2/27/count-length-size/
It depends on the situation. In the example you show I would go with size since you already have the collection loaded and a call to size will just check the length of the array. As you noticed, count will do an extra db query and you really want to avoid that.
However, in the scenario that you only want to display the number of Foobars and not show those objects, then I would go with count because it will not load the instances into memory, just return the number of records.

Is there any built in method for sorting in Objective-c?

I have two sorted NSMutableArrays (or I can use any other collection, not critical), I need to insert objects from the first array to the second and preserve sort order in the second array. What is the optimal (fastest) method to do that? I can implement all the known good algorithms, but my question is, if there is already some built-in method? If not, what is the best algorithm in my case?
The real answer would be: it depends, since you are asking: what is the fastest way of inserting objects from one array into another while preserving sort order.
There is no built in way of inserting in the right place of a sorted array. You can achieve the same effect by just adding the two arrays together but it won't be "the fastest way".
What is actually faster depends on many things like: how much data does the arrays contain, what is the ratio of data in array1 vs array2 (does one array contain much more data than the other)?, etc.
NOTE: You should probably begin with the simple solution and only optimize once you experience performance problems. Do measurements with a large data set though, to see that your solution works with whatever data your users may have.
Inserting items from one sorted array into another sorted array
If you want to merge the two arrays by inserting objects in the right place then normal algorithms apply. You should insert the smaller array into the bigger array and try to insert entire sorted sequences where possible instead of every item one by one.
For best performance you should try to make a batch insert using insertObjects:atIndexes: instead of inserting the object one by one.
You can use indexOfObject:inSortedRange:options:usingComparator: to find the index that each item should be inserted in the other array if you specify NSBinarySearchingInsertionIndex for the options. Also, the comparator you are using must be the same as the comparator that sorted the array, otherwise the result is "undefined".
With this in mind you would do something like this
Create mutable index
For every ITEM in SMALLER ARRAY
Find the index where to insert ITEM in LONGER ARRAY
Add (the insertion location + the location in the short array) as the index in the mutable set.
Next item.
Batch insert all items.
The documentation for insertObjects:atIndexes: tells you that "the corresponding location specified in indexes after earlier insertions have been made." Which in your case with two sorted array mean all items with a lower index will already have been added and thus you should add the index of the object in the short array to the value returned from indexOfObject:inSortedRange:options:usingComparator:.
Another (probably very premature optimization) you can do is decrease the sortedRange for every item in the loop so that you don't have to search through parts of the array that you know the item to be inserted is bigger than.
There are probably many other optimizations that can be made. You should still measure first! Hopefully this will get you started.
NSArray *newArray=[firstArray arrayByAddingObjectsFromArray:secondArray];
newArray = [newArray sortedArrayUsingSelector:#selector(localizedCaseInsensitiveCompare:)];
I would start by simply adding all of the objects of the first array to the second and then resorting the second. Time how long it takes. If it is acceptable, stop there.
If not, you could try a binary search to find the insertion point in the second array for each item in the first array. Since both arrays are sorted, you might be able to optimise the search by using the last insertion point as the lower bound each time round. Something like this:
NSInteger insertionPoint = -1;
for (id object in array1)
{
insertionPoint = [self binarySearch: array2 for: object lowerBound: insertionPoint + 1];
[array2 insertObject: object atIndex: insertionPoint];
}
The Cocoa class NSSortDescriptor together with sortedArrayUsingDescriptors: from NSArray should do what you are after.
Since you are using mutable arrays, you might want to use sortUsingDescriptors: which sorts the mutable array without creating a new one.
Look at the documentation here to see if any of the NSArray sort methods work for you. http://developer.apple.com/library/mac/#documentation/Cocoa/Reference/Foundation/Classes/NSArray_Class/NSArray.html. You can scroll down to the methods and there's 7 built-in ones for sorting. You could probably just combine the two arrays and run the sortedArrayUsingComparator: or one of the other methods.

Bind Top 5 Values of a To-Many Core Data Relationship to Text Fields

I am making an application that represents a cell phone bill using Core Data. I have three entities: Bill, Line, and Calls. Bills can have many lines, and lines can have many calls. All of this is set up with relationships. Right now, I have a table view that displays all of the bills. When you double click on a bill, a sheet comes down with a popup box that lists all of the lines on the bill. Below the popup box is a box that has many labels that display various information about that line. Below that information I want to list the top 5 numbers called by that line in that month. Lines has a to-many relationship with Calls, which has two fields, number and minutes. I have all of the calls for the selected line loaded into an NSArrayController with a sort descriptor that properly arranges the values. How do I populate 5 labels with the top 5 values of this array controller?
EDIT: The array of calls is already unique, when I gather the data, I combine all the individual calls into total minutes per number for each month. I just need to sort and display the first 5 records of this combined array.
I may be wrong (and really hope I am), but it looks like you'll need to use brute force on this one. There are no set / array operators that can help, nor does NSPredicate appear to help.
I think this is actually a bit tricky and it looks like you'll have to do some coding. The Core Data Programming Guide says:
If you execute a fetch directly, you
should typically not add
Objective-C-based predicates or sort
descriptors to the fetch request.
Instead you should apply these to the
results of the fetch. If you use an
array controller, you may need to
subclass NSArrayController so you can
have it not pass the sort descriptors
to the persistent store and instead do
the sorting after your data has been
fetched.
I think this applies to your case because it's important to consider whether sorting or filtering takes place first in a fetch request (when the fetch requests predicate and sort descriptors are set). This is because you'll be tempted to use the #distinctUnionOfObjects set/array operator. If the list is collapsed to uniques before sorting, it won't help. If it's applied after sorting, you can just set the fetch request's limit to 5 and there're your results.
Given the documentation, I don't know that this is how it will work. Also, in this case, it might be easier to avoid NSArrayController for this particular problem and just use NSTableViewDataSource protocol, but that's beyond the scope of this Q&A.
So, here's one way to do it:
Create a predicate to filter for the
selected bill's line items.*
Create a sort descriptor to sort the
line items by their telephone number
(which are hopefully in a
standardized format internally, else
trouble awaits) via #"call.number" in your case.
Create a fetch request for the line
item entity, with the predicate and
sort descriptors then execute it**.
With those sorted results, it would be nice if you could collapse and "unique" them easily, and again, you'll be tempted to use #distinctUnionOfObjects. Unfortunately, set/array operators won't be any help here (you can't use them directly on NSArray/NSMutableArray or NSSet/NSMutableSet instances). Brute force it is, then.
I'd create a topFive array and loop through the results, adding the number to topFive if it's not there already, until topFive has 5 items or until I'm out of results.
Displaying it in your UI (using Bindings or not) is, as I said, beyond the scope of this Q&A, so I'll leave it there. I'd LOVE to hear if there's a better way to do this - it's definitely one of those "looks like it should be easy but it's not" kind of things. :-)
*You could also use #unionOfObjects in your key path during the fetch itself to get the numbers of the calls of the line items of the selected bill, which would probably be more efficient a fetch, but I'm getting tired of typing, and you get the idea. ;-)
**In practice I'd probably limit the fetch request to something reasonable - some bills (especially for businesses and teenagers) can be quite large.