Sort NSFetchRequest by a predicate - cocoa

I have a SQLite-backed core data storage and would like to fetch a list of managed objects using NSFetchRequest. I want said list to be sorted by a boolean value that can be easily calculated at the database level. I know this because it’s possible to formulate the same conditions using an NSPredicate, which would look as follows:
[NSPredicate predicateWithFormat:#"uid = %#", currentUID]
Sadly, there seems to be no way to formulate a condition like this using an NSSortDescriptor. How do I best go about this? Do I fetch two lists, one with
[NSPredicate predicateWithFormat:#"uid = %#", currentUID]
and one with
[NSPredicate predicateWithFormat:#"uid != %#", currentUID]
and combine them later on? Can I then still elegantly use a NSFetchedResultsController?
Or should I fetch all items and sort them later in code? Or is there anything I’ve missed.

Just create an array (even if it contains only a single element) of NSSortDescriptors to sort the result as desired.
You use setSortDescriptors: to set them.
The fetch can handle both predicates and sorting at the same time.

What you're asking for doesn't make sense.
A predicate is used to select which objects should be returned in a set of results. This is determined by evaluating the predicate against each object to see if the predicate evaluates to YES or NO (a binary value, or one of 2 possible values). If it evaluates to YES, then the object is included. If it evaluates to NO, then the object is excluded. There is no middle ground.
By contrast, a sort descriptor evaluates to less than, equal, or greater than. In other words, it is a ternary value (it can be one of 3 things). There is no way to express a ternary value with a predicate (since a predicate is binary), and so using a predicate as a sort descriptor makes absolutely no sense. The API doesn't allow it, because logic doesn't allow it.
So the real question is: what are you trying to do? Why do you think you need a predicate in your sort descriptors?

Related

How do I prevent to operate over an empty matrix or a matrix with empty columns or row?

In the problem that I want to solve a well defined matrix has no empty rows or columns.
For example the matrix [[],[]] is not valid.
When I call the function first_column, how do I prevent to execute it if the matrix that I send as an argument is not valid as defined before?
first_column([],[],[]).
first_column([[H|T]|Tail],[H|Col],[T|Rows]):- first_column(Tail,Col,Rows).
Technically, what you're asking can be done by testing for an end-condition of a list with one element, rather than an empty list, based on the specs you gave.
first_column([[H|T]],[H],[T]).
first_column([[H|T]|Tail],[H|Col],[T|Rows]):- first_column(Tail,Col,Rows).
However, beyond your specs, I suspect that you'll also need to "transfer" your final Col,Rows to end variables, something like:
first_column([[H|T]],C,R,[H|C],[T|R]).
first_column([[H|T]|Tail],[H|C],[T|R],Col,Rows):-
first_column(Tail,C,R,Col,Rows).
The modified predicate would be called with initial conditions, like
first_column(List,[],[],Col,Rows).

how to enumerate array indices as odd and even numbers in parameters part of omnet.ini

I have this parameter as an array. The array is big, 100 cells. It is a parameter that can be initiated in omnet.ini file. The cells with even numbers should get value A and odd numbers should get value B. How can I do this in an automated manner?
Is there a way besides having all odd and even indices initiated one by one manually?
Wildcards can be useful but I do not know how to use them to separate odd and even indices.
Thanks.
You can access the actual module index with the index operator. Combining this with the conditional operator ?: you can easily define the value:
**.myModule[*].myParameter = index % 2 == 0 ? "A" : "B"
I'm not aware of any feature like this. There are a number of work-arounds you could use:
Provide two parameters and select the correct one in code
Use the volatile keyword (probably not appropriate here)
Put the entire thing in your .ini file
I'd personally implement the first approach, that way you can use the wildcard to pass both parameters ([*].myNode.parameterEven and [*].myNode.parameterUneven) and then set the correct values in your array in a for loop.
However, you could also use the volatile keyword in your NED file, see the manual for more details. However, this approach mostly works well if you have different parameters depending on which node you are assigning it to. For this case I think the first approach is better.
The last alternative is just putting the entire thing in your .ini file, which may be useful if you want to parameterize the array later.

Method returns one or more, should it return an Array when there is only one item?

Let's say we have a Ruby method like this:
# Pseudocode
def get(globbed)
a_items = Dir.glob(globbed)
a_items.length == 1 ? a_items.first : a_items
end
The method is meant to return a String containing information about the items in question. If there are many items, it will return an Array. The ternary makes it so that if there is only one item, it just returns that String.
What is the best practice here? Should such a method always return an Array even if there is only one item?
It should always return an array. Returning different things means that whatever method that calls this method would also have to have a condition. That is not good. Whenever you can get rid of a condition, you should. A condition should only be used as a last resort.
As a real example, the jQuery library built on top of JavaScript has the notion of selectors, expressed in the form $(...). This can result in multiple matching dom objects, or a single one. But jQuery always returns an array even if the matched dom object is one. That makes things simple.
It's always about use cases. You have to define what's the responsibility of that method and then decide what makes sense to do.
In this specific case, I would say that, unless there isn't any specific reason to return different types, you should choose the way that is simpler, both to test and to read.
Always returning an array in this case means clearer method interface:
"The method returns an array with the directory content"
instead of the more convoluted
"The method returns an array of directory content if there more than
one object, otherwise return the single object."
So, clarity first of all.
And: testing would result easier. The cyclomatic complexity of the routine is less.
There are cases where the uniformity of return types can't be fulfilled. Just think of the Array method index: it wouldn't be possible to distinguish between "object not found" and "index 0" if the practice here was applied.
Conclusion: here I don't see any reason why to make the method more complex by distinguishing the two cases, so.. KISS.
Hi, ruby provides block, yield and iterator to permit easy array or hash treatment. And it's a good practice to use the same code for one or several numbers of element. Exemple :
a_items.each { |element| file_treatment(element) }
Regards.

Prolog: append a list to itself

suppose I have a list ListSum, and I want to append a new list to ListSum recursively, like
appList(ListSum):-
%%generate a list: ListTemp,
append(ListTemp,ListSum,ListSum),
appList(ListSum).
but append(ListTemp,ListSum,ListSum) didn't work in the way i wanted.
Can anyone help me out?
Cheers
You have to understand the concept of unification (or actually "matching" as implemented in Prolog). You can't bind two or more values to the same variable. Variables in Prolog once matched persisted its value until the final goal achieved, or fails somewhere. After that, if there're more possibilities then the variable is re-instantiated with another value and so on.
For example, if I query appList([]), then the append would be tested to match as:
append(ListTemp,[],[])
If ListTemp isn't empty list, this clause would fail because the semantic of append is "append the first argument with second, both are lists, resulting in the third". The recursive call to appList(ListSum) would be called as appList([]) since ListSum is matched with [] previously, resulting in infinite recursion (fortunately, if ListTemp isn't [], this won't be reached).
You must have two arguments in the clause, where one is the original list, and the other is the resulting list. The first two argument of append is then ListSum and ListTemp (depends on the append order you want), while the third is the resulting list. Done, no recursion required.
here's a non-recursive solution, not sure why you even need recursion:
appself(L,X) :- append(L,L,X).

Case insensitive NSPredicate for strings from an array?

I have a situation where I want to fetch objects from my core data store by the username key, but I want the comparison to be case-insensitive. The predicate I have is this:
username IN $usernames
I then do a variable substitution with an array of strings that are the usernames I want to find. It works but is case-sensitive. I'd like to do something like this, I think:
username IN[c] $usernames
Unfortunately that doesn't appear to work. The string comparison must still be happening in a case-sensitive way. (I don't get an error about it being an unsupported query.)
Is there a different way to write this predicate so it works the way I need or am I just missing something obvious here?
The case modifier on the IN operator is apparently ignored when executing a fetch against the SQLite store. (You omitted the store type from your question.)
I'd recommend filing a bug against the documentation so that this limitation/behavior can be documented.
I'd also recommend filing a feature request in the bug reporter so that this can be considered for future support.
In the meantime, you'll have to pull your fetch request out of the data model and build it up programatically. You can build a compound predicate OR predicate that does a case insensitive equality match for each of your values (and test that it meets your performance needs.)
Note that if you are supporting OS targets prior to 10.6 the case modifier on == is not supported, in which case yet another alternate solution will be required.
You might try something like ANY $usernames LIKE[c] username. I've done something similar, where instead of the variable substution, I just have a key path like "persons.name", and that predicate works for me. Not sure if it works any differently with a variable there instead of a key path, but it's worth a shot.
Here is another workaround, but requires you to change the MOM.
Make username a full blown entity. Create the inverse relationship between username and whatever your other entity is.
Now for the fetch request, set the entity as "Username" then run this predicate (assuming a "name" property and "parent" property):
[NSPredicate predicateWithFormat:"(name like[c] %#) && (parent == %#)", theUserName, theParentObject]
This may be overkill, but will allow you to run your search as desired.
Although this question is several years old I just stumbled upon the same problem and solved it like this:
NSArray *values = #[#"FOO", #"bar" ,#"lorem"];
NSString *predicate;
predicate = #"value LIKE[cd] '";
predicate = [predicate stringByAppendingString:
[values componentsJoinedByString:
#"' OR value LIKE[cd] '"]];
predicate = [predicate stringByAppendingString:#"'"];
NSLog(#"%#", predicate);
// Output:
// value LIKE[cd] 'FOO' OR value LIKE[cd] 'bar' OR value LIKE[cd] 'lorem'
This creates a static predicate expression from the value list. Maybe it will be usefull to someone.
UPDATE 2:
Actually it seems like the updated solution below does not work with sqlite and produces an
'NSInvalidArgumentException',
reason: 'unimplemented SQL generation for predicate : ... (bad LHS)'
I think for array/dict/set comparisions and IN there are only keys allowed on the left side of the operator.
UPDATE:
After some research on expressions and predicates I found another aproach, that seems to work quite well:
NSPredicate *predicate =
[NSPredicate predicateWithFormat:
#"lowercase(value) IN %#", values];
This uses the function expression lowercase: to get the lowercase representation of the value. All that's left to do is to ensure that all entries of values are lowercase and you'll be able to use case insensitive IN expressions.

Resources