Retrieve and sort results based on several criteria - objective-c

Here's the scenario...
I have several float attributes in my data model which I want to compare against a number of variables (actually the same attributes in another object) and return if any match... straight forward NSPredicate.
However... what I would like to do is to keep track of which of those comparisons evaluate to true and then do a count. I then want to return only the top X results, i.e. those where the most comparisons are true.
Example... (not actual code!!)
object1.float1 = 1;
object1.float2 = 2;
object1.float3 = 3;
object2.float1 = 1;
object2.float2 = 2;
object2.float3 = 4;
object3.float1 = 1;
object3.float2 = 4;
object3.float3 = 4;
float1Variable = 1;
float2Variable = 2;
float3Variable = 3;
kReturnedObjects = 2;
I only want to retrieve object1 and object2.
Any help would be much appreciated, most of my possible solutions so far are incredibly laborious!

What I'd do is define some kind of evaluation-function to calculate the "similarity" of the objects. I.e
s(obj, comparison_obj) := (obj.var1 == comparison_obj.var1) + (obj.var2 == comparison_obj.var2) + (obj.var3 == comparison_obj.var3)
The larger s(obj, comparison_obj) is, the more variables are the same. You can then use Core Data to give you the list of kReturnedObjects objects, sorted by s descending.

Related

array lists in java: exclude the first element from `for` loop

I am taking an introduction to Java programing class and I have an array list where I need to exclude the first element from my for loop that finds an average. The first element in the array list is a weight for the average (which is why it needs to be excluded). I also need to drop the lowest value from the remainder of the array list hence my second for loop. I have tried to create a copy of the list and also tried to create a sub list but I cannot get it to work.
public static double Avgerage(ArrayList<Double> inputValues) {
double avg;
double sum = 0;
double weightValue = inputValues.get(0);
double lowest = inputValues.get(0);
for (int i = 1; i > inputValues.size(); i++) {
if (inputValues.get(i) < lowest) {
lowest = inputValues.get(i);
}
}
for (int i = 0; i < inputValues.size(); i++) {
sum = sum + inputValues.get(i);
}
double average = (sum - lowest) / (inputValues.size() - 1);
avg = average * weightValue;
return avg;
}
To start with good programming practice, you should work with interfaces rather than classes, where possible. The appropriate interface here is List<Double>, and when you create it in your class, you should use
List<Double> nameOfList = new ArrayList<Double>();
What we're doing is creating an object which has the behaviour of a List, with the underlying implementation of an ArrayList (more info here.
With regards to the question, you don't appear to be excluding the first element, as you said you wished to - both for loops iterate through all values in the list. Remember to treat the ArrayList like an array - accessing an element does not modify it, like it might in a Queue.
I have edited your code below to demonstrate this, and have also included some other optimisations and corrected the sign error on line 7:
public static double average(List<Double> inputValues) {
double sum = 0;
//Exclude the first element, as it contains the weight
double lowest = inputValues.get(1);
for (int i = 2; i < inputValues.size(); i++) {
lowest = Math.min(inputValues.get(i), lowest);
}
for (int i = 1; i < inputValues.size(); i++) {
sum += inputValues.get(i);
}
double average = (sum - lowest) / (inputValues.size() - 1);
//Scale by the weight
avg *= inputValues.get(0);
return avg;
}
Note: The convention in java is to use camelCase for method names, I have adjusted accordingly.
Also, I don't know your requirements, but optimally, you should be providing logical parameters. If possible do the following before calling the function:
int weight = inputValues.get(0);
inputValues.remove(0);
//And then you would call like this, and update your method signature to match
average(inputValues, weight);
I don't do this inside the method, as the context implies that we would not be modifying values.

game maker random cave generation

I want to make a cave explorer game in game maker 8.0.
I've made a block object and an generator But I'm stuck. Here is my code for the generator
var r;
r = random_range(0, 1);
repeat(room_width/16) {
repeat(room_height/16) {
if (r == 1) {
instance_create(x, y, obj_block)
}
y += 16;
}
x += 16;
}
now i always get a blank frame
You need to use irandom(1) so you get an integer. You also should put it inside the loop so it generates a new value each time.
In the second statement, you are generating a random real value and storing it in r. What you actually require is choosing one of the two values. I recommend that you use the function choose(...) for this. Here goes the corrected statement:
r = choose(0,1); //Choose either 0 or 1 and store it in r
Also, move the above statement to the inner loop. (Because you want to decide whether you want to place a block at the said (x,y) location at every spot, right?)
Also, I recommend that you substitute sprite_width and sprite_height instead of using the value 16 directly, so that any changes you make to the sprite will adjust the resulting layout of the blocks accordingly.
Here is the code with corrections:
var r;
repeat(room_width/sprite_width) {
repeat(room_height/sprite_height) {
r = choose(0, 1);
if (r == 1)
instance_create(x, y, obj_block);
y += sprite_height;
}
x += sprite_width;
}
That should work. I hope that helps!
Looks like you are only creating a instance if r==1. Shouldn't you create a instance every time?
Variable assignment r = random_range(0, 1); is outside the loop. Therefore performed only once before starting the loop.
random_range(0, 1) returns a random real number between 0 and 1 (not integer!). But you have if (r == 1) - the probability of getting 1 is a very small.
as example:
repeat(room_width/16) {
repeat(room_height/16) {
if (irandom(1)) {
instance_create(x, y, obj_block)
}
y += 16;
}
x += 16;
}
Here's a possible, maybe even better solution:
length = room_width/16;
height = room_height/16;
for(xx = 0; xx < length; xx+=1)
{
for(yy = 0; yy < height; yy+=1)
{
if choose(0, 1) = 1 {
instance_create(xx*16, yy*16, obj_block); }
}
}
if you want random caves, you should probably delete random sections of those blocks,
not just single ones.
For bonus points, you could use a seed value for the random cave generation. You can also have a pathway random generation that will have a guaranteed path to the finish with random openings and fake paths that generate randomly from that path. Then you can fill in the extra spaces with other random pieces.
But in regards to your code, you must redefine the random number each time you are placing a block, which is why all of them are the same. It should be called inside of the loops, and should be an integer instead of a decimal value.
Problem is on the first line, you need to put r = something in the for cycle

Changing content of a matrix in c

How do you change just part of a matrix in c (I'm actually in Objective-C, but using matrices in c). For example:
NSInteger tempMapMatrix[100][100] =
{{0,0,1,1,2,2,1,1,0,2,4,4,4,0,0,1,2,2,1,0,0,0,0,0,0},
{0,1,1,2,3,2,1,1,4,4,3,4,4,0,0,1,2,2,1,0,0,0,0,0,0},
{1,1,2,3,3,2,1,4,1,3,3,4,4,0,0,1,2,2,1,0,0,0,0,0,0},
{1,1,3,3,3,2,4,1,1,1,4,4,4,0,0,1,2,2,1,0,0,0,0,0,0},
{0,1,1,2,2,2,4,4,4,4,4,4,4,0,0,1,1,1,1,0,0,0,4,4,0},
{0,0,1,1,2,2,1,0,0,2,3,4,4,0,0,0,0,0,0,0,0,0,4,4,0},
{4,4,1,1,2,2,1,1,0,1,1,0,4,0,0,0,0,0,0,0,0,0,4,4,4},
{0,4,1,2,2,2,1,1,0,4,4,4,4,4,4,4,0,0,0,0,1,0,0,0,0},
{0,1,2,2,2,2,1,1,0,1,2,4,4,0,0,4,0,3,3,3,3,3,3,3,0},
{0,1,2,2,2,2,1,1,0,1,2,4,4,0,0,4,4,3,2,2,2,2,2,3,0},
{0,1,2,2,2,2,1,1,0,1,2,4,4,0,0,4,4,3,2,3,3,3,2,3,0},
{0,1,2,2,2,2,1,1,0,1,2,4,4,0,0,4,4,3,2,3,2,2,2,3,0},
{0,1,2,2,2,2,1,1,0,1,2,4,4,0,0,4,3,3,2,3,2,3,3,3,0},
{0,1,2,2,2,2,1,1,0,1,2,4,4,0,4,4,1,2,2,3,2,0,0,0,0},
{0,1,2,2,2,2,1,1,0,1,2,4,4,0,4,3,3,3,3,3,0,0,0,0,0},
{0,1,2,2,2,2,1,1,0,1,2,4,4,4,4,0,0,0,0,0,0,0,0,0,0},
{0,1,2,2,2,2,1,1,0,1,2,4,4,0,0,0,1,0,0,0,0,0,0,0,0},
{0,1,2,2,2,2,1,1,0,1,2,4,4,0,0,0,1,0,0,0,1,1,1,0,0},
{0,1,2,2,2,2,1,1,0,1,2,4,4,0,0,1,0,0,0,0,0,1,1,0,0},
{0,0,1,2,2,2,1,0,0,0,4,4,4,0,0,1,1,0,0,0,0,0,1,0,0}};
then I want to change the first couple (x and y) of integers:
tempMapMatrix[100][100] =
{{5,5,5,5,5,1,2,3},
{5,5,5,5,5,1,2,3},
{5,5,1,1,1,1,2,3},
{5,5,1,5,5,1,2,3},
{5,5,1,1,1,1,2,3},
{5,5,5,5,5,5,5,5},
{5,5,5,5,5,1,2,3},
{5,2,2,2,5,1,2,3},
{5,2,5,2,5,1,2,3},
{5,2,2,2,5,1,2,3}};
but I'm getting an error (Expected Expression). I've tried
tempMapArray = stuff;
tempMapArray[][] = stuff;
but none work.
Any way to change the first couple of ints in the matrix?
You need to iterate over them, this is C, you don't have syntactic sugar to assingn pieces of arrays like you want. If you want to change, for example, every first element of each row you could do something like:
for (int = 0; i < 100; ++i) {
tempMatrix[i][0] = 5;
}
so for the first couple of every row you should do
for (int = 0; i < 100; ++i) {
tempMatrix[i][0] = 5;
tempMatrix[i][1] = 5;
}
and so on.
You have to access and change each element in the matrix individually.
I.e.:
tempMapMatrix[0][0] = 5;
tempMapMatrix[0][1] = //...
There is no way to "batch change" the contents of an array (one-dimensional or n-dimensional) in C.
The easiest way to achieve this effect is to write a for-loop and iterate over the contents of the two dimensional array and insert the required values in the required places.

Given 4 objects, how to figure out whether exactly 2 have a certain property

I have another question on how to make most elegant solution to this problem, since I cannot afford to go to computer school right so my actual "pure programming" CS knowledge is not perfect or great. This is basically an algorhythm problem (someone please correct me if I am using that wrong, since I don't want to keep saying them and embarass myself)
I have 4 objects. Each of them has an species property that can either be a dog, cat, pig or monkey. So a sample situation could be:
object1.species=pig
object2.species=cat
object3.species=pig
object4.species=dog
Now, if I want to figure out if all 4 are the same species, I know I could just say:
if ( (object1.species==object2.species)
&& (object2.species==object3.species)
&& (object3.species==object4.species)
) {
// They are all the same animal (don't care WHICH animal they are)
}
But that isn't so elegant right? And if I suddenly want to know if EXACTLY 3 or 2 of them are the same species (don't care WHICH species it is though), suddenly I'm in spaghetti code.
I am using Objective C although I don't know if that matters really, since the most elegant solution to this is I assume the same in all languages conceptually? Anyone got good idea?
Thanks!!
You can use a hash table (or dictionary in objective-C) with the key on the species, incrementing the count every time.
For clarity (pseudo-code):
// N is 4 for your particular case
for ( int i = 0; i < N; i++ )
hashtable[ object[i].species ]++;
hashtable[ Species.PIG ]; // number of pigs (constant)
or if you want to unroll it manually:
hashtable[ object1.species ]++;
hashtable[ object2.species ]++;
hashtable[ object3.species ]++;
hashtable[ object4.species ]++;
now you can check through the species to see the count:
for each key in hashtable
if ( hashtable[ key ] == 3 ) // species "key" has 3 items
/* Code */
of course, "hashtable" can be just a simple array if species is just a simple enum/integer. The above should be the same theory in either case.
This is precisely what sets and counted sets are for.
BOOL allSameSpecies(NSArray *animals) {
NSSet *speciesSet = [NSSet setWithArray:[animals valueForKey:#"species"]];
return [[speciesSet] count] == 1;
}
BOOL sameSpeciesNumber(NSArray *animals, NSUInteger targetCount) {
NSCountedSet *speciesCounts = [NSCountedSet setWithArray:[animals valueForKey:#"species"]];
for (id species in speciesCounts) {
if ([speciesCounts countForObject:species] == targetCount)
return YES;
}
return NO.
}
You can count how many comparisons match of all possible comparisons. If exactly 1 comparison is true, then exactly 2 items are the same, if 3 comparisons match, exactly 3 items are the same. This example is in C, you'll have to convert it to objective-C on your own.
int count = 0;
count += object1.species == object2.species;
count += object1.species == object3.species;
count += object1.species == object4.species;
count += object2.species == object2.species;
count += object2.species == object3.species;
count += object3.species == object4.species;
// count 0 - all different
// count 1 - exactly 2 are the same
// count 2 - two pairs of 2
// count 3 - exactly 3 are the same
// count 6 - all are the same
The counting can also be implemented as a loop:
for (int i = 0; i < 4; i++)
for (int j = i + 1; j < 4; j++)
count += objects[i].species == objects[j].species;
This approach only works if the amount of objects is 5 or less. Because of this and the fact that the amount of comparisons scales quadratically, it's better to use a hashtable if the amount of objects is larger.

Generate combinations ordered by an attribute

I'm looking for a way to generate combinations of objects ordered by a single attribute. I don't think lexicographical order is what I'm looking for... I'll try to give an example. Let's say I have a list of objects A,B,C,D with the attribute values I want to order by being 3,3,2,1. This gives A3, B3, C2, D1 objects. Now I want to generate combinations of 2 objects, but they need to be ordered in a descending way:
A3 B3
A3 C2
B3 C2
A3 D1
B3 D1
C2 D1
Generating all combinations and sorting them is not acceptable because the real world scenario involves large sets and millions of combinations. (set of 40, order of 8), and I need only combinations above the certain threshold.
Actually I need count of combinations above a threshold grouped by a sum of a given attribute, but I think it is far more difficult to do - so I'd settle for developing all combinations above a threshold and counting them. If that's possible at all.
EDIT - My original question wasn't very precise... I don't actually need these combinations ordered, just thought it would help to isolate combinations above a threshold. To be more precise, in the above example, giving a threshold of 5, I'm looking for an information that the given set produces 1 combination with a sum of 6 ( A3 B3 ) and 2 with a sum of 5 ( A3 C2, B3 C2). I don't actually need the combinations themselves.
I was looking into subset-sum problem, but if I understood correctly given dynamic solution it will only give you information is there a given sum or no, not count of the sums.
Thanks
Actually, I think you do want lexicographic order, but descending rather than ascending. In addition:
It's not clear to me from your description that A, B, ... D play any role in your answer (except possibly as the container for the values).
I think your question example is simply "For each integer at least 5, up to the maximum possible total of two values, how many distinct pairs from the set {3, 3, 2, 1} have sums of that integer?"
The interesting part is the early bailout, once no possible solution can be reached (remaining achievable sums are too small).
I'll post sample code later.
Here's the sample code I promised, with a few remarks following:
public class Combos {
/* permanent state for instance */
private int values[];
private int length;
/* transient state during single "count" computation */
private int n;
private int limit;
private Tally<Integer> tally;
private int best[][]; // used for early-bail-out
private void initializeForCount(int n, int limit) {
this.n = n;
this.limit = limit;
best = new int[n+1][length+1];
for (int i = 1; i <= n; ++i) {
for (int j = 0; j <= length - i; ++j) {
best[i][j] = values[j] + best[i-1][j+1];
}
}
}
private void countAt(int left, int start, int sum) {
if (left == 0) {
tally.inc(sum);
} else {
for (
int i = start;
i <= length - left
&& limit <= sum + best[left][i]; // bail-out-check
++i
) {
countAt(left - 1, i + 1, sum + values[i]);
}
}
}
public Tally<Integer> count(int n, int limit) {
tally = new Tally<Integer>();
if (n <= length) {
initializeForCount(n, limit);
countAt(n, 0, 0);
}
return tally;
}
public Combos(int[] values) {
this.values = values;
this.length = values.length;
}
}
Preface remarks:
This uses a little helper class called Tally, that just isolates the tabulation (including initialization for never-before-seen keys). I'll put it at the end.
To keep this concise, I've taken some shortcuts that aren't good practice for "real" code:
This doesn't check for a null value array, etc.
I assume that the value array is already sorted into descending order, required for the early-bail-out technique. (Good production code would include the sorting.)
I put transient data into instance variables instead of passing them as arguments among the private methods that support count. That makes this class non-thread-safe.
Explanation:
An instance of Combos is created with the (descending ordered) array of integers to combine. The value array is set up once per instance, but multiple calls to count can be made with varying population sizes and limits.
The count method triggers a (mostly) standard recursive traversal of unique combinations of n integers from values. The limit argument gives the lower bound on sums of interest.
The countAt method examines combinations of integers from values. The left argument is how many integers remain to make up n integers in a sum, start is the position in values from which to search, and sum is the partial sum.
The early-bail-out mechanism is based on computing best, a two-dimensional array that specifies the "best" sum reachable from a given state. The value in best[n][p] is the largest sum of n values beginning in position p of the original values.
The recursion of countAt bottoms out when the correct population has been accumulated; this adds the current sum (of n values) to the tally. If countAt has not bottomed out, it sweeps the values from the start-ing position to increase the current partial sum, as long as:
enough positions remain in values to achieve the specified population, and
the best (largest) subtotal remaining is big enough to make the limit.
A sample run with your question's data:
int[] values = {3, 3, 2, 1};
Combos mine = new Combos(values);
Tally<Integer> tally = mine.count(2, 5);
for (int i = 5; i < 9; ++i) {
int n = tally.get(i);
if (0 < n) {
System.out.println("found " + tally.get(i) + " sums of " + i);
}
}
produces the results you specified:
found 2 sums of 5
found 1 sums of 6
Here's the Tally code:
public static class Tally<T> {
private Map<T,Integer> tally = new HashMap<T,Integer>();
public Tally() {/* nothing */}
public void inc(T key) {
Integer value = tally.get(key);
if (value == null) {
value = Integer.valueOf(0);
}
tally.put(key, (value + 1));
}
public int get(T key) {
Integer result = tally.get(key);
return result == null ? 0 : result;
}
public Collection<T> keys() {
return tally.keySet();
}
}
I have written a class to handle common functions for working with the binomial coefficient, which is the type of problem that your problem falls under. It performs the following tasks:
Outputs all the K-indexes in a nice format for any N choose K to a file. The K-indexes can be substituted with more descriptive strings or letters. This method makes solving this type of problem quite trivial.
Converts the K-indexes to the proper index of an entry in the sorted binomial coefficient table. This technique is much faster than older published techniques that rely on iteration. It does this by using a mathematical property inherent in Pascal's Triangle. My paper talks about this. I believe I am the first to discover and publish this technique, but I could be wrong.
Converts the index in a sorted binomial coefficient table to the corresponding K-indexes.
Uses Mark Dominus method to calculate the binomial coefficient, which is much less likely to overflow and works with larger numbers.
The class is written in .NET C# and provides a way to manage the objects related to the problem (if any) by using a generic list. The constructor of this class takes a bool value called InitTable that when true will create a generic list to hold the objects to be managed. If this value is false, then it will not create the table. The table does not need to be created in order to perform the 4 above methods. Accessor methods are provided to access the table.
There is an associated test class which shows how to use the class and its methods. It has been extensively tested with 2 cases and there are no known bugs.
To read about this class and download the code, see Tablizing The Binomial Coeffieicent.
Check out this question in stackoverflow: Algorithm to return all combinations
I also just used a the java code below to generate all permutations, but it could easily be used to generate unique combination's given an index.
public static <E> E[] permutation(E[] s, int num) {//s is the input elements array and num is the number which represents the permutation
int factorial = 1;
for(int i = 2; i < s.length; i++)
factorial *= i;//calculates the factorial of (s.length - 1)
if (num/s.length >= factorial)// Optional. if the number is not in the range of [0, s.length! - 1]
return null;
for(int i = 0; i < s.length - 1; i++){//go over the array
int tempi = (num / factorial) % (s.length - i);//calculates the next cell from the cells left (the cells in the range [i, s.length - 1])
E temp = s[i + tempi];//Temporarily saves the value of the cell needed to add to the permutation this time
for(int j = i + tempi; j > i; j--)//shift all elements to "cover" the "missing" cell
s[j] = s[j-1];
s[i] = temp;//put the chosen cell in the correct spot
factorial /= (s.length - (i + 1));//updates the factorial
}
return s;
}
I am extremely sorry (after all those clarifications in the comments) to say that I could not find an efficient solution to this problem. I tried for the past hour with no results.
The reason (I think) is that this problem is very similar to problems like the traveling salesman problem. Until unless you try all the combinations, there is no way to know which attributes will add upto the threshold.
There seems to be no clever trick that can solve this class of problems.
Still there are many optimizations that you can do to the actual code.
Try sorting the data according to the attributes. You may be able to avoid processing some values from the list when you find that a higher value cannot satisfy the threshold (so all lower values can be eliminated).
If you're using C# there is a fairly good generics library here. Note though that the generation of some permutations is not in lexicographic order
Here's a recursive approach to count the number of these subsets: We define a function count(minIndex,numElements,minSum) that returns the number of subsets of size numElements whose sum is at least minSum, containing elements with indices minIndex or greater.
As in the problem statement, we sort our elements in descending order, e.g. [3,3,2,1], and call the first index zero, and the total number of elements N. We assume all elements are nonnegative. To find all 2-subsets whose sum is at least 5, we call count(0,2,5).
Sample Code (Java):
int count(int minIndex, int numElements, int minSum)
{
int total = 0;
if (numElements == 1)
{
// just count number of elements >= minSum
for (int i = minIndex; i <= N-1; i++)
if (a[i] >= minSum) total++; else break;
}
else
{
if (minSum <= 0)
{
// any subset will do (n-choose-k of them)
if (numElements <= (N-minIndex))
total = nchoosek(N-minIndex, numElements);
}
else
{
// add element a[i] to the set, and then consider the count
// for all elements to its right
for (int i = minIndex; i <= (N-numElements); i++)
total += count(i+1, numElements-1, minSum-a[i]);
}
}
return total;
}
Btw, I've run the above with an array of 40 elements, and size-8 subsets and consistently got back results in less than a second.