Order an NSMutable array in descending order - nsmutablearray

I've been reading a few posts about ordering an NSMutable array but have had trouble getting it working, essentially I have a number of entries in a tableview, an unlimited amount can be added but I need to order them by an NSMutable array that contains numerical values, that would go well above 10. I'd really appreciate any help anyone could give me, I've been using the compare parameter but I can't seem to get it to reverse the order, secondly I read that numbers above 10 would start ordering in a strange way. Ill post y code shortly but anything for me to mull over would be great.
Thanks

The answer depends a bit on whether the objects in your array are numbers or strings. There are also various methods to sort arrays (sortUsingDescriptors, sortUsingComparator, ...).
If you have an array of numbers, you can sort them in decreasing order for example like this:
NSMutableArray *a = [NSMutableArray arrayWithObjects:#1, #55, #9, #17, nil];
[a sortUsingComparator:^NSComparisonResult(NSNumber *obj1, NSNumber *obj2) {
return -[obj1 compare:obj2];
}];
// Result: 55, 17, 9, 1.
Note the minus-sign in the comparator block which has the effect of reversing the order from increasing to decreasing.
If you have an array of strings, and you proceed in the same way, then you will get what you have called "that numbers above 10 would start ordering in a strange way":
NSMutableArray *a = [NSMutableArray arrayWithObjects:#"1", #"55", #"9", #"17", nil];
[a sortUsingComparator:^NSComparisonResult(NSString *obj1, NSString *obj2) {
return -[obj1 compare:obj2];
}];
// Result: 9, 55, 17, 1.
The object are sorted as strings, not as numbers.
The solution is to use the NSNumericSearch option:
NSMutableArray *a = [NSMutableArray arrayWithObjects:#"1", #"55", #"9", #"17", nil];
[a sortUsingComparator:^NSComparisonResult(NSString *obj1, NSString *obj2) {
return -[obj1 compare:obj2 options:NSNumericSearch];
}];
// Result: 55, 17, 9, 1.

Related

The optimal data structure for filtering for objects that match criteria

I'll try to present the problem as generally as I can, and a response in any language will do.
Suppose there are a few sets of varying sizes, each containing arbitrary values to do with a category:
var colors = ["red", "yellow", "blue"] // 3 items
var letters = ["A", "B", "C", ... ] // 26 items
var digits = [0, 1, 2, 3, 4, ... ] // 10 items
... // each set has fixed amount of items
Each object in this master list I already have (which I want to restructure somehow to optimize searching) has properties that are each a selection of one of these sets, as such:
var masterList = [
{ id: 1, color: "red", letter: "F", digit: 5, ... },
{ id: 2, color: "blue", letter: "Q", digit: 0, ... },
{ id: 3, color: "red", letter: "Z", digit: 3, ... },
...
]
The purpose of the search would be to create a new list of acceptable objects from the master list. The program would filter the master list by given search criteria that, for each property, contains a list of acceptable values.
var criteria = {
color: ["red", "yellow"],
letter: ["A", "F", "P"],
digit: [1, 3, 5],
...
};
I'd like to think that some sort of tree would be most applicable. My understanding is that it would need to be balanced, so the root node would be the "median" object. I suppose each level would be defined by one of the properties so that as the program searches from the root, it would only continue down the branches that fit the search criteria, each time eliminating the objects that don't fit given the particular property for that level.
However, I understand that many of the objects in this master list will have matching property values. This connects them in a graphical manner that could perhaps be conducive to a speedy search.
My current search algorithm is fairly intuitive and can be done with just the master list as it is. The program
iterates through the properties in the search criteria,
with each property iterates over the master list, eliminating a number of objects that don't have a matching property, and
eventually removes all the objects that don't fit the criteria. There is surely some quicker filtering system that involves a more organized data structure.
Where could I go from here? I'm open to a local database instead of another data structure I suppose - GraphQL looks interesting. This is my first Stack Overflow question, so my apologies for any bad manners 😶
As I don't have the context of number of sets and also on the number of elements in the each set. I would suggest you some very small changes which will make things at-least relatively fast for you.
To keep things mathematical, I will define few terms here:
number of sets - n
size of masterlist - k
size of each property in the search criteria - p
So, from the algorithm that I believe you are using, you are doing n iterations over the search criteria, because there can be n possible keys in the search criteria.
Then in each of these n iterations, you are doing p iterations over the allowed values of that particular set. Finally, in each of these np iterations you are iterating over the master list, with k iterations ,and checking if this value of record should be allowed or not.
Thus, in the average case, you are doing this in O(npk) time complexity.
So, I won't suggest to change much here.
The best you can do is, change the values in the search criteria to a set (hashset) instead of keeping it as a list, and then iterate over the masterlist. Follow this Python code:
def is_possible(criteria, master_list_entry):
for key, value in master_list_entry.items(): # O(n)
if not key in criteria or value not in criteria[key]: # O(1) average
return False
return True
def search(master_list, criteria):
ans = []
for each_entry in master_list: # O(k)
if is_possible(criteria, each_entry): # O(n), check above
ans.append(each_entry)
return ans
Just call search function, and it will return the filtered masterlist.
Regarding the change, change your search criteria to:
criteria = {
color: {"red", "yellow"}, # This is a set, instead of a list
letter: {"A", "F", "P"},
digit: {1, 3, 5},
...
}
As, you can see, I have mentioned the complexities along with each line, thus we have reduced the problem to O(nk) in average case.

string 'w32' == 0 evaluates to true in php. huh?

So I was getting a notice in my php while creating a google product feed.
The notice was
"The following php notice has occurred 4989 times on the _ site today:
PHP Notice: Undefined index: 0 in /xxx/Status.php on line 583"
This was the code in that class
public function inStockLocally($productcode)
{
if($this->_status[$productcode]['status'] == self::IN_STOCK) {
return $this->_status[$productcode]['in_stock_local'];
}
return false;
}
The function was getting a $productcode = 0, but the productcode was infact 'w32', so the key didn't exist.
up the stack where the function was being called I put this in, in order to break on the troublesome product.
if ($productcode == 0) {
$test = 'breakhere';
}
Using netbeans and firebug, it broke on the line when $productcode = 'w32'
So my question is why does 'w32' == 0 evaluate to true?
It is also evaluating to true with other similar structure codes like 'h94'.
Any help would be appreciated as no one in the department can figure out why this is happening.
I guess I didn't put enough info in the q. Two things going on.
1. 'w32' converted to a number = 0 for some reason. 2. [0] is being inserted as my key in the array when the productcode has the structure 'x##';
I'm a little new here, so pardon if this isn't the answer you were expecting, but PHP does a lot of automatic type conversion. So any string that doesn't start with a numeric character (0..9, +, -, etc) will evaluate to zero.
"If you compare a number with a string or the comparison involves numerical strings, then each string is converted to a number and the comparison performed numerically. "
http://php.net/manual/en/language.operators.comparison.php
Additionally, I suppose you have an indexed array, although you expect it to be an associative array:
The array() function is used to create an array.
In PHP, there are three types of arrays:
Indexed arrays - Arrays with numeric index
Associative arrays - Arrays with named keys
Multidimensional arrays - Arrays containing one or more arrays
Syntax
Syntax for indexed arrays:
array(value1,value2,value3,etc.);
Syntax for associative arrays:
array(key=>value,key=>value,key=>value,etc.);

How can I sort a list of strings in Dart?

I see in the API docs there is a sort() method on List, but I'm not clear what it needs for a parameter. The current need is for a very simple straight up alpha comparison.
1. A Quick Solution
Thanks for the question! You can sort a list of Strings like this:
main() {
final List<String> fruits = <String>['bananas', 'apples', 'oranges'];
fruits.sort();
print(fruits);
}
The above code prints:
[apples, bananas, oranges]
2. Slightly more advanced usage
Notice that sort() does not return a value. It sorts the list without creating a new list. If you want to sort and print in the same line, you can use method cascades:
print(fruits..sort());
For more control, you can define your own comparison logic. Here is an example of sorting the fruits based on price.
main() {
final List<String> fruits = <String>['bananas', 'apples', 'oranges'];
fruits.sort((a, b) => getPrice(a).compareTo(getPrice(b)));
print(fruits);
}
Let's see what's going on here.
A List has a sort method, which has one optional parameter: a Comparator. A Comparator is a typedef or function alias. In this case, it's an alias for a function that looks like:
int Comparator(T a, T b)
From the docs:
A Comparator function represents such a total ordering by returning a negative integer if a is smaller than b, zero if a is equal to b, and a positive integer if a is greater than b.
3. How to do it with a list of custom objects
Additionally, if you create a list composed of custom objects, you could add the Comparable<T> as a mixin or as inheritance (extends) and then override the compareTo method, in order to recreate the standard behavior of sort() for your list of custom objects. For more info, do check out this other, related StackOverflow answer.
Here is the one line code to achieve it.
fruits.sort((String a, String b)=>a.compareTo(b)); //fruits is of type List<String>
For Sorting Simple List of Integers or Strings:
var list = [5 , -5 ,1];
list.sort(); //-5 , 1 , 5
For Reversing the list order:
list.reversed;
For Sorting List of Objects or Map by field of it:
List<Map<String, dynamic>> list= [
{"name": "Shoes", "price": 100},
{"name": "Pants", "price": 50},
];
// from low to high according to price
list.sort((a, b) => a["price"].compareTo(b["price"]));
// from high to low according to price
list.sort((a, b) => b["price"].compareTo(a["price"]));
To add just one point to Seth's detailed answer, in general, in
(a, b) => foo(a, b)
passed into sort, the function foo should answer an integer result as follows:
if a < b, result should be < 0,
if a = b, result should be = 0, and
if a > b, result should be > 0.
For the above law of trichotomy to hold, both a and b must be Comparables.
use compareAsciiUpperCase instead of compareTo, as it supports strings and automatically ignores case sensitive:
import "package:collection/collection.dart";
data.sort((a, b) {
return compareAsciiUpperCase(a.name, b.name);
});
After today, you should just be able to do list.sort() .
The sort method's argument is now optional, and it defaults to a function that calls compareTo on the elements themselves. Since String is Comparable, it should Just Work now.
How I have solved this problem.
List<Product> _dataSavingListProducts = [];
List<Product> _dataSavingListFavoritesProducts = [];
void _orderDataSavingLists() {
_dataSavingListProducts.toList().reversed;
_dataSavingListFavoritesProducts.toList().reversed;
}

core data predicate and expression madness

This is one for core data experts, I guess. Maybe this is just beyond the bounds of what it's supposed to... anyway:
on iOS, using sqlite persistent store.
I have entities like so:
A<-->>B<<-->C
B has an attribute 'v' which is a float, and another attribute 'd' which is a date.
B has relationship 'a' which is single to A, and 'c' which is single to C.
I can calculate the average of all B.v where B.a == someA, code is below. But, what I really want to do is calculate the average of all B.v where B.a == someA and where B is the last B for a C, ordered by B.d. So the average function would 'pick up' only one B for each C (the highest-dated one). Any ideas?
// create the fetch request
NSFetchRequest * request = [[NSFetchRequest alloc] init];
[request setEntity:[NSEntityDescription entityForName:#"B" inManagedObjectContext:managedObjectContext]];
// create the expression
NSExpression * keyPathExpression = [NSExpression expressionForKeyPath:#"v"];
NSString * aggregationFunction = #"average:";
NSExpression * aggregationExpression = [NSExpression expressionForFunction:aggregationFunction arguments:[NSArray arrayWithObject:keyPathExpression]];
NSExpressionDescription * expressionDescription = [[NSExpressionDescription alloc] init];
[expressionDescription setName:#"aggregateValue"];
[expressionDescription setExpression:aggregationExpression];
[expressionDescription setExpressionResultType:NSDecimalAttributeType];
[request setPropertiesToFetch:[NSArray arrayWithObject:expressionDescription]];
NSPredicate * predicate = [NSPredicate predicateWithFormat:#"a == %#", someA];
[request setPredicate:predicate];
[request setResultType:NSDictionaryResultType];
// Execute the fetch.
NSError * error = nil;
NSArray * objects = [managedObjectContext executeFetchRequest:request error:&error];
When you use setPropertiesToFetch: you are telling the fetch to ignore all other properties. This means your predicate of #"a == %#" which is keyed on the a attribute, is going to be ignored.
What you probably want to do in this case is to convert the #"a == %#" predicate into an NSSubqueryExpressionType equality expression and then make that the first expression in the array passed to setPropertiesToFetch:.
That will direct the fetch to first find all B objects that match #"a == %#" and then to run the v expression against that set of objects.
However, when you find yourself having to create convoluted predicates, that is usually an indication that your data model is poorly designed. Quite often, you end up with complex predicates because you are trying to create logical relationships within a predicate instead of modeling them in the data model.
Further, as a rule, when you have a particular object in a hand e.g. someAand/or someC then you don't do a fetch at all but instead you walk the relationships. Why fetch all B objects related to the someA object when you can just use someA.bObjects?
I think your data model really looks like this:
A<-->>B<<-->C
… and your looking for an intersection of B objects between the sets of someA.bs and someC.bs. So, the first thing to do is to get the intersection of the sets:
NSMutableSet *secSet=[[NSMutableSet setWithSet:someA.bs] intersectSet:someC.bs];
… now all you have to do is find the B object with the most recent date:
BClass *someB=[secSet valueForKeyPath:#"#max.dateAttribute"];
… and you're done. Iterate the process to find the intersections between multiple A and C objects.

Methods for nearby numbers in Groovy

In groovy are there any methods that can find the near by numbers? For example :
def list = [22,33,37,56]
def number = 25
//any method to find $number is near to 22 rather than 33.
Is there any method for the above mentioned purpose, or i have to construct my own method or closure for this purpose.
Thanks in advance.
The following combination of Groovy's collection methods will give you the closest number in the list:
list.groupBy { (it - number).abs() }.min { it.key }.value.first()
The list.groupBy { (it - number).abs() } will transform the list into a map, where each map entry consists of the distance to the number as key and the original list entry as the value:
[3:[22], 8:[33], 12:[37], 31:[56]]
The values are now each a list on their own, as theoretically the original list could contain two entries with equal distance. On the map you then select the entry with the smallest key, take its value and return the first entry of the value's list.
Edit:
Here's a simpler version that sorts the original list based on the distance and return the first value of the sorted list:
list.sort { (it - number).abs() }.first()
If it's a sorted List, Collections.binarySearch() does nearly the same job. So does Arrays.binarySearch().

Resources