implementing Subset Sum with genetic Algorithm - java

import java.util.Collections;
import java.util.Vector;
public class Metaheuristic {
private static int[] DATA;
private static int NUM_CHROMOSOMES ;
private static int MAX_POWER;
private static int MAX_NUMBER;
private static int FITNESS_THRESHOLD;
private static float MUTATE = (float) .05;
private Vector population;
private boolean done = true;
int numRuns = 0;
public void GeneticAlgorithm (int[] data, int target, int n){
NUM_CHROMOSOMES = n;
MAX_POWER = data.length;
MAX_NUMBER = (int) Math.pow(2, MAX_POWER) - 1;
FITNESS_THRESHOLD = target;
DATA = new int[data.length];
DATA = data;
Metaheuristic s = new Metaheuristic();
s.start();
//System.out.println("s");
}
public Metaheuristic(){
generateRandomPopulation();
}
private void generateRandomPopulation(){
System.out.println("***Randomly Generating population with: " + NUM_CHROMOSOMES + " Chromosome(s)***");
population = new Vector();
for(int i = 0; i < NUM_CHROMOSOMES; ++i){
int randomValue = (int) (Math.random()*MAX_NUMBER);
population.add(new Chromosome(randomValue, MAX_POWER));
}
System.out.println("First Population: " + population +"\n");
}
public void start(){
Collections.sort(population);
Chromosome fitess = (Chromosome) population.lastElement();
done = fitess.fitness(DATA, FITNESS_THRESHOLD) >= MAX_POWER? true:false;
if(done){
System.out.println("DONE, solution found: " + fitess);
}
else{
numRuns++;
System.out.println("FITESS: " + fitess + " fitness: " + fitess.fitness(DATA, FITNESS_THRESHOLD ));
generateNewPopulation();
start();
}
}
private void generateNewPopulation(){
System.out.println("***Generating New Population");
Vector temp = new Vector();
for(int i = 0; i < population.size()/2; ++i){
Chromosome p1 = selectParent();
Chromosome p2 = selectParent();
temp.add(cross1(p1, p2));
temp.add(cross2(p1, p2));
}
population.clear();
population.addAll(temp);
System.out.println("New Population: " + population + "\n");
}
private Chromosome selectParent(){
int delta = population.size();
delta = NUM_CHROMOSOMES - NUM_CHROMOSOMES/2;
int num = (int) (Math.random()*10 + 1);
int index;
if(num >= 4){
index = (int) (Math.random()*delta + NUM_CHROMOSOMES/2);
}
else{
index = (int) (Math.random()*delta);
}
return (Chromosome) population.get(index);
}
private Chromosome cross1(Chromosome parent1, Chromosome parent2){
String bitS1 = parent1.getBitString();
String bitS2 = parent2.getBitString();
int length = bitS1.length();
String newBitString = bitS1.substring(0, length/2) + bitS2.substring(length/2, length);
Chromosome offspring = new Chromosome();
offspring.setBitString(newBitString);
if(shouldMutate()){
mutate(offspring);
}
return offspring;
}
private Chromosome cross2(Chromosome parent1, Chromosome parent2){
String bitS1 = parent1.getBitString();
String bitS2 = parent2.getBitString();
int length = bitS1.length();
String newBitString = bitS2.substring(0, length/2) + bitS1.substring(length/2, length);
Chromosome offspring = new Chromosome();
offspring.setBitString(newBitString);
if(shouldMutate()){
mutate(offspring);
}
return offspring;
}
private boolean shouldMutate(){
double num = Math.random();
int number = (int) (num*100);
num = (double) number/100;
return (num <= MUTATE);
}
private void mutate(Chromosome offspring){
String s = offspring.getBitString();
int num = s.length();
int index = (int) (Math.random()*num);
String newBit = flip(s.substring(index, index+1));
String newBitString = s.substring(0, index) + newBit + s.substring(index+1, s.length());
offspring.setBitString(newBitString);
}
private String flip(String s){
return s.equals("0")? "1":"0";
}
public static void main(String[] args) {
double average = 0;
int sum = 0;
for(int i = 0; i < 10; ++i){
Metaheuristic s = new Metaheuristic();
s.start();
sum = sum + s.numRuns;
average = (double) sum / (double)(i+1);
System.out.println("Number of runs: " + s.numRuns);
}
System.out.println("average runs: " + average);
}
}
import java.lang.Comparable;
public class Chromosome implements Comparable{
protected String bitString;
public static int[] DATA;
public int TARGET;
public Chromosome(){
}
public Chromosome(int value, int length){
bitString = convertIntToBitString(value, length);
}
public void setBitString(String s){
bitString = s;
}
public String getBitString(){
return bitString;
}
public int compareTo(Object o) {
Chromosome c = (Chromosome) o;
int num = countOnes(this.bitString) - countOnes(c.getBitString());
return num;
}
public int fitness(int[] data, int target){
DATA = new int[data.length];
System.arraycopy(data, 0, DATA, 0, data.length);
TARGET = target;
return countOnes(bitString);
}
public boolean equals(Object o){
if(o instanceof Chromosome){
Chromosome c = (Chromosome) o;
return c.getBitString().equals(bitString);
}
return false;
}
public int hashCode(){
return bitString.hashCode();
}
public String toString(){
return "Chromosome: " + bitString;
}
public static int countOnes(String bits){
int sum = 0;
for(int i = 0; i < bits.length(); ++ i){
String test = bits.substring(i, i+1);
sum = sum + (DATA[i]*Integer.parseInt(test));
}
return sum;
}
public static String convertIntToBitString(int val, int length){
int reval = val;
StringBuffer bitString = new StringBuffer(length);
for(int i = length-1; i >=0; --i ){
if( reval - (Math.pow(2, i)) >= 0 ){
bitString.append("1");
reval = (int) (reval - Math.pow(2, i));
}
else{
bitString.append("0");
}
}
return bitString.toString();
}
/* public static void main(String[] args){
//System.out.println(convertIntToBitString(2046, 10));
Chromosome c = new Chromosome(1234, 10);
System.out.println(c.fitness());
}*/
}
My fitness function is f(x ) = s · (C − P(x )) + (1 − s) · P(x ) in which C is my target value to reach and P(*x ) = (Sigma) wixi, where wi is the element's set and xi is 0 or 1 (the element is chosen or not). also s is 0 or 1, depends on p(x) value. please help me to write this fitness.
I have just tried it but the program run with errors.

You have several problems in your code, and obviously you didn't debug it. Here are some tips though.
First NUM_CHROMOSOMES is 0, because it's an uninitialized field (of the GeneticAlgorithm which you don't use).
Since NUM_CHROMOSOMES is 0, this for loop is useless:
for (int i = 0; i < NUM_CHROMOSOMES; ++i) {
Then, this line:
int randomValue = (int) (Math.random() * MAX_NUMBER);
Since MAX_NUMBER is never manually initialized (same as NUM_CHROMOSOMES, its value is 0, and so is randomValue.
Anyway, population is empty and since you don't test for emptyness, this line:
Chromosome fitess = (Chromosome) population.lastElement();
... throws an exception, because there is no such thing as a last element in your empty population Vector.
As a side note, StringBuffer, Vector are obsolete classes, and you never need to import Comparable, since it belongs to the java.lang package.

Related

Code test - Maximize cost for a given weight of a Package

You want to send your friend a package with different things. Each thing you put inside the package has such parameters as index number, weight and cost. The package has a weight limit. Your goal is to determine which things to put into the package so that the total weight is less than or equal to the package limit and the total cost is as large as possible.
You would prefer to send a package which weights less in case there is more than one package with the same price.
INPUT SAMPLE:
Your program should accept as its first argument a path to a filename. The input file contains several lines. Each line is one test case.
Each line contains the weight that the package can take (before the colon) and the list of things you need to choose. Each thing is enclosed in parentheses where the 1st number is a thing's index number, the 2nd is its weight and the 3rd is its cost. Eg:
81 : (1,53.38,45)(2,88.62,98) (3,78.48,3)(4,72.30,76) (5,30.18,9)(6,46.34,48)
8 : (1,15.3,34)
75:(1,85.31,29) (2,14.55,74)(3,3.98,16) (4,26.24,55)(5,63.69,52) (6,76.25,75)(7,60.02,74) (8,93.18,35)(9,89.95,78)
56 : (1,90.72,13)(2,33.80,40) (3,43.15,10)(4,37.97,16) (5,46.81,36)(6,48.77,79) (7,81.80,45)(8,19.36,79) (9,6.76,$64)
OUTPUT SAMPLE:
For each set of things that you put into the package provide a list (items’ index numbers are separated by comma).
E.g.
4 //for package1
- //for package2
2,7 //for package3
8,9 //for package4
CONSTRAINTS:
Max weight that a package can take is ≤ 100 There might be up to 15 items you need to choose from Max weight and cost of an item is ≤ 100
Is there a more elegant and easy to understand solution than https://discuss.codechef.com/questions/104934/package-problemin-java
Here is the code (KnapSack):
public class FriendPackageKnapsack {
public static void parserThings(String[] sub2, List<Package> things,
double maxWeight) {
for (int i = 0; i < sub2.length; i++) {
String[] sub3 = (sub2[i].substring(1, sub2[i].length() - 1)).split(",");
int id = Integer.parseInt(sub3[0]);
double weight = Double.parseDouble(sub3[1]);
double cost = Double.parseDouble(sub3[2].substring(1, sub3[2].length()));
if (weight <= maxWeight) {
Package condidat = new Package(id, weight, cost);
things.add(condidat);
}
}
}
public static String getOptimumFor(List<Package> things, int r, int maxWt) {
int indexSolution = 0;
String returnData = "";
double maxWeight = 0;
double maxCost = 0;
int[] data = new int[r];
List<Integer> res = new ArrayList<Integer>();
int[] arr = new int[things.size()];
for (int i = 0; i < things.size(); i++) {
arr[i] = i;
}
getCombination(arr, data, res, 0, 0);
for (int i = 0; i <= res.size() - r; i += r) {
double someWeight = 0;
double someCost = 0;
for (int j = 0; j < r; j++) {
someWeight += things.get(res.get(i + j)).getWeight();
someCost += things.get(res.get(i + j)).getCost();
}
if (someWeight <= maxWt) {
if ((someCost > maxCost)
|| ((someCost == maxCost) && (someWeight <= maxWeight))) {
indexSolution = i;
maxWeight = someWeight;
maxCost = someCost;
}
}
}
for (int k = indexSolution; k < r + indexSolution; k++) {
returnData += res.get(k) + ",";
}
return returnData + maxCost + "," + maxWeight;
}
public static void getCombination(int[] arr, int[] data, List<Integer> res, int start,
int index) {
if (index == data.length) {
for (int j = 0; j < data.length; j++) { res.add(data[j]); }
return;
}
for (int i = start; i < arr.length && arr.length - i >= data.length - index; i++) {
data[index] = arr[i];
getCombination(arr, data, res, i + 1, index + 1);
}
}
public static void main(String[] args) {
File file = new File("packageproblem.txt");
BufferedReader in = null;
try {
in = new BufferedReader(new FileReader(file));
}
catch (FileNotFoundException e) { e.printStackTrace(); }
String line = "";
List<Package> things = new ArrayList<>();
try {
while ((line = in.readLine()) != null) {
String s = "";
// Parsing line
String[] sub1 = line.split(" : ");
int N = Integer.parseInt(sub1[0]);
String[] sub2 = sub1[1].split(" ");
if (sub2.length > 1) {
things.clear();
parserThings(sub2, things, N);
double maxCost = 0;
double maxWeight = 0;
for (int i = 1; i <= things.size(); i++) {
String resultat = getOptimumFor(things, i, N);
// System.out.println(resultat);
String[] sub4 = resultat.split(",");
double cost = Double.parseDouble(sub4[sub4.length - 2]);
double weight = Double.parseDouble(sub4[sub4.length - 1]);
if (cost == maxCost) {
if (weight < maxWeight) {
maxCost = cost;
maxWeight = weight;
s = resultat;
}
}
if (cost > maxCost) {
maxCost = cost;
maxWeight = weight;
s = resultat;
}
}
// System.out.println(s);
String[] sub5 = s.split(",");
String ss = "";
for (int i = 0; i < sub5.length - 2; i++) {
ss += things.get(Integer.parseInt(sub5[i])).getId() + ",";
}
if (ss.equals("")) { System.out.println("-"); }
else { System.out.println(ss.substring(0, ss.length() - 1)); }
}
else { System.out.println("-"); }
}
}
catch (IOException e) { e.printStackTrace(); }
}
}
class Package {
private int id;
private double weight;
private double cost;
public Package(int id, double weight, double cost) {
this.id = id;
this.weight = weight;
this.cost = cost;
}
public int getId() { return id; }
public void setId(int id) { this.id = id; }
public double getWeight() { return weight; }
public void setWeight(double weight) { this.weight = weight; }
public double getCost() { return cost; }
public void setCost(double cost) { this.cost = cost; }
}
The code is taken from here.
You can find a full solution of this problem in java here
https://github.com/rantibi/package-challenge

Altering the value of k in kNN algorithm - Java

I have applied the KNN algorithm for classifying handwritten digits. the digits are in vector format initially 8*8, and stretched to form a vector 1*64..
As it stands my code applies the kNN algorithm but only using k = 1. I'm not entirely sure how to alter the value k after attempting a couple of things I kept getting thrown errors. If anyone could help push me in the right direction it would be really appreciated. The training dataset can be found here and the validation set here.
ImageMatrix.java
import java.util.*;
public class ImageMatrix {
private int[] data;
private int classCode;
private int curData;
public ImageMatrix(int[] data, int classCode) {
assert data.length == 64; //maximum array length of 64
this.data = data;
this.classCode = classCode;
}
public String toString() {
return "Class Code: " + classCode + " Data :" + Arrays.toString(data) + "\n"; //outputs readable
}
public int[] getData() {
return data;
}
public int getClassCode() {
return classCode;
}
public int getCurData() {
return curData;
}
}
ImageMatrixDB.java
import java.util.*;
import java.io.*;
import java.util.ArrayList;
public class ImageMatrixDB implements Iterable<ImageMatrix> {
private List<ImageMatrix> list = new ArrayList<ImageMatrix>();
public ImageMatrixDB load(String f) throws IOException {
try (
FileReader fr = new FileReader(f);
BufferedReader br = new BufferedReader(fr)) {
String line = null;
while((line = br.readLine()) != null) {
int lastComma = line.lastIndexOf(',');
int classCode = Integer.parseInt(line.substring(1 + lastComma));
int[] data = Arrays.stream(line.substring(0, lastComma).split(","))
.mapToInt(Integer::parseInt)
.toArray();
ImageMatrix matrix = new ImageMatrix(data, classCode); // Classcode->100% when 0 -> 0% when 1 - 9..
list.add(matrix);
}
}
return this;
}
public void printResults(){ //output results
for(ImageMatrix matrix: list){
System.out.println(matrix);
}
}
public Iterator<ImageMatrix> iterator() {
return this.list.iterator();
}
/// kNN implementation ///
public static int distance(int[] a, int[] b) {
int sum = 0;
for(int i = 0; i < a.length; i++) {
sum += (a[i] - b[i]) * (a[i] - b[i]);
}
return (int)Math.sqrt(sum);
}
public static int classify(ImageMatrixDB trainingSet, int[] curData) {
int label = 0, bestDistance = Integer.MAX_VALUE;
for(ImageMatrix matrix: trainingSet) {
int dist = distance(matrix.getData(), curData);
if(dist < bestDistance) {
bestDistance = dist;
label = matrix.getClassCode();
}
}
return label;
}
public int size() {
return list.size(); //returns size of the list
}
public static void main(String[] argv) throws IOException {
ImageMatrixDB trainingSet = new ImageMatrixDB();
ImageMatrixDB validationSet = new ImageMatrixDB();
trainingSet.load("cw2DataSet1.csv");
validationSet.load("cw2DataSet2.csv");
int numCorrect = 0;
for(ImageMatrix matrix:validationSet) {
if(classify(trainingSet, matrix.getData()) == matrix.getClassCode()) numCorrect++;
} //285 correct
System.out.println("Accuracy: " + (double)numCorrect / validationSet.size() * 100 + "%");
System.out.println();
}
In the for loop of classify you are trying to find the training example that is closest to a test point. You need to switch that with a code that finds K of the training points that is the closest to the test data. Then you should call getClassCode for each of those K points and find the majority(i.e. the most frequent) of the class codes among them. classify will then return the major class code you found.
You may break the ties (i.e. having 2+ most frequent class codes assigned to equal number of training data) in any way that suits your need.
I am really inexperienced in Java, but just by looking around the language reference, I came up with the implementation below.
public static int classify(ImageMatrixDB trainingSet, int[] curData, int k) {
int label = 0, bestDistance = Integer.MAX_VALUE;
int[][] distances = new int[trainingSet.size()][2];
int i=0;
// Place distances in an array to be sorted
for(ImageMatrix matrix: trainingSet) {
distances[i][0] = distance(matrix.getData(), curData);
distances[i][1] = matrix.getClassCode();
i++;
}
Arrays.sort(distances, (int[] lhs, int[] rhs) -> lhs[0]-rhs[0]);
// Find frequencies of each class code
i = 0;
Map<Integer,Integer> majorityMap;
majorityMap = new HashMap<Integer,Integer>();
while(i < k) {
if( majorityMap.containsKey( distances[i][1] ) ) {
int currentValue = majorityMap.get(distances[i][1]);
majorityMap.put(distances[i][1], currentValue + 1);
}
else {
majorityMap.put(distances[i][1], 1);
}
++i;
}
// Find the class code with the highest frequency
int maxVal = -1;
for (Entry<Integer, Integer> entry: majorityMap.entrySet()) {
int entryVal = entry.getValue();
if(entryVal > maxVal) {
maxVal = entryVal;
label = entry.getKey();
}
}
return label;
}
All you need to do is adding K as a parameter. Keep in mind, however, that the code above does not handle ties in a particular way.

calculating fibonacci numbers in java

I am trying to display the first 20 fibbonacci numbers using the model view controller method in java. However the output that I am getting is only the last number(the first 19 are not displaying) if anyone is able to look through my code and point out where im going wrong that would be awesome :)
public class FibonacciModel {
public String fibModel(int a, int b, int c, int count){
String result = "";
//int c;
while(count!=20) // if you want first 100 fibonacci numbers then change 20 to 100 accordingly
{
c=a+b;
count++;
result = c + " ";
a=b;
b=c;
}
return result;
}
}
public class FibonacciController {
public static void main(String[] args) {
// TODO Auto-generated method stub
int a = 1;
int b = 1;
int count = 2;
int c = 0;
FibonacciModel Model = new FibonacciModel();
FibonacciView View = new FibonacciView();
View.say(Model.fibModel(a, b, c, count));
}
}
public class FibonacciView {
public < T > void say( T word ){
System.out.print(word);
}
}
You're overwriting your result variable. Try result = result + c + " "; or result += c + " ";
Check this out :)
public static void getFibbonacci(int n){
int total = 0;
int prev = 1;
for (int x=1; x<n; x++){
total = total + prev;
prev = total - prev;
System.out.println(total);
}
}
public class fibbo {
public static void main(String args[]) {
Scanner sc = new Scanner(System.in);
int a;
System.out.println("Enter the number");
a = sc.nextInt();
int first = 0;
int second = 1;
int third;
System.out.print("Fibbonacci series is= ");
System.out.print("\t" + first + "\t" + second + "\t");
for (int i = 0; i < a - 2; i++) {
third = first + second;
first = second;
second = third;
System.out.print(third + "\t");
}
}

Calculating max field goal percentage in a method in java program

Have to find both max and min in a set of data of a team's field goal percentage.
import java.io.*;
import java.util.Scanner;
public class kstatebball
{
public static void main(String [] args)
throws FileNotFoundException
{
Scanner in = new Scanner(new File("data1.txt"));
String[] firstname = new String [100];
String[] lastname = new String [100];
int fgm[] = new int [100];
int fga[] = new int [100];
double fgp = 0;
int maxFGP;
int minFGP;
System.out.print(" Player FGM FGA FGP%\n");
int count = 0;
for( int i = 0;in.hasNext(); i++)
{
firstname[i] = in.next();
lastname[i] = in.next();
fgm[i] = in.nextInt();
fga[i] = in.nextInt();
fgp = (1.0 * fgm[i]) / (1.0 * fga[i]) * 100;
count++;
System.out.printf("%10s %10s %3d %3d %3.1f \n",firstname[i],lastname[i],fgm[i],fga[i],fgp);
}
maxFGP = maxFGP(fgm,fga,count);
minFGP = minFGP(fgm,fga,count);
System.out.printf("\n\nThe player with the highest field goal percentage is: %3d ",maxFGP(fgm,fga,count));
System.out.printf("\nThe player with the lowest field goal percentage is : %3.1f",fgp);
}
public static int maxFGP(int[] fgm, int[] fga, int count)
{
int max = 0;
for(int i = 0; i < count; i++)
{
if((1.0 * fgm[i]) / (1.0 * fga[i]) * 100 > max)
max = i;
}
return max;
}
public static int minFGP(int[]fgm, int[]fga, int count)
{
int min = 0;
for(int i = 0; i > 13; i++)
{
if(fgm[i] > fgm[count])
count = i;
}
return min;
}
}
Need help with the "if" statement for it to return the correct max.
We have our percentages for all of the players, but need to use the methods in order to find the player with the greatest field goal percentage and also the lowest.
Here's the data file I am using:
Marcus Foster 123 288
Thomas Gipson 102 178
Shane Southwell 88 224
Will Spradling 58 144
Wesley Iwundu 53 111
Nino Williams 49 96
Nigel Johnson 28 80
Jevon Thomas 15 58
D.J. Johnson 34 68
Omari Lawrence 27 65
Shawn Meyer 2 4
Ryan Schultz 2 9
Jack Karapetyan 1 4
Brian Rohleder 1 2
Should be like this:
public static int maxFGP(int[] fgm, int[] fga, int count)
{
int max = 0;
double maxValue=(1.0 * fgm[0]) / (1.0 * fga[0]) * 100;
for(int i = 0; i < count; i++)
{
if((1.0 * fgm[i]) / (1.0 * fga[i]) * 100 > maxValue)
{
max = i;
maxValue=(1.0 * fgm[i]) / (1.0 * fga[i]) * 100;
}
}
return max;
}
note: you already set int max = 0; so no need to loop from i=0. change int i=1 instead
To print the name of the player with max value:
System.out.printf("\n\nThe player with the highest field goal percentage is: %3d ",firstname[maxFGP(fgm,fga,count)]);
max is an array index, I would suggest you add another another method to calculate the percentage
public static int maxFGP(int[] fgm, int[] fga, int count)
{
int max = 0;
for(int i = 1; i < count; i++){
if(fieldGoalPercentage(fgm, fga, i) > fieldGoalPercentage(fgm, fga, max))
max = i;
}
return max;
}
Java's an object oriented language. You're probably a beginner, but here's another way to think about it.
Start with a Player object:
package misc;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
/**
* misc.Player
* #author Michael
* #link http://stackoverflow.com/questions/21843505/calculating-max-field-goal-percentage-in-a-method-in-java-program
* #since 2/17/14 10:07 PM
*/
public class Player {
private final String firstName;
private final String lastName;
private final int numAttempts;
private final int numMakes;
public static void main(String[] args) {
List<Player> team = new ArrayList<Player>() {{
add(new Player("Larry", "Bird", 40, 80));
add(new Player("Robert", "Parish", 4, 10));
add(new Player("Dennis", "Johnson", 35, 50));
}};
System.out.println("before sort: " + team);
Collections.sort(team, new Comparator<Player>() {
#Override
public int compare(Player that, Player other) {
if (that.getFieldGoalPercentage() < other.getFieldGoalPercentage()) {
return -1;
} else if (that.getFieldGoalPercentage() > other.getFieldGoalPercentage()) {
return +1;
} else {
return 0;
}
}
});
System.out.println("after sort: " + team);
}
public Player(String firstName, String lastName, int numMakes, int numAttempts) {
this.firstName = (isBlank(firstName) ? "" : firstName);
this.lastName = (isBlank(lastName) ? "" : lastName);
this.numAttempts = (numAttempts < 0 ? 0 : numAttempts);
this.numMakes = (numMakes < 0 ? 0 : numMakes);
if (this.numMakes > this.numAttempts) {
throw new IllegalArgumentException(String.format("number of makes %d cannot exceed number of attempts %d", numMakes, numAttempts));
}
}
public String getFirstName() {
return firstName;
}
public String getLastName() {
return lastName;
}
public int getNumAttempts() {
return numAttempts;
}
public int getNumMakes() {
return numMakes;
}
public double getFieldGoalPercentage() {
double fieldGoalPercentage = 0.0;
if (this.numAttempts > 0) {
fieldGoalPercentage = ((double) numMakes)/numAttempts;
}
return fieldGoalPercentage;
}
public static boolean isBlank(String s) {
return ((s == null) || (s.trim().length() == 0));
}
#Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Player player = (Player) o;
return firstName.equals(player.firstName) && lastName.equals(player.lastName);
}
#Override
public int hashCode() {
int result = firstName.hashCode();
result = 31 * result + lastName.hashCode();
return result;
}
#Override
public String toString() {
final StringBuilder sb = new StringBuilder("misc.Player{");
sb.append("firstName='").append(firstName).append('\'');
sb.append(", lastName='").append(lastName).append('\'');
sb.append(", numAttempts=").append(numAttempts);
sb.append(", numMakes=").append(numMakes);
sb.append(", percentage=").append(getFieldGoalPercentage());
sb.append('}');
return sb.toString();
}
}

Sorting of two-dimensional array based on two parameters

The following code performs 'hierarchical' sorting of a two-dimensional matrix. Firstly, it sorts elements based on the values of ranks. Secondly, it takes this sorted matrix, searches elements that have the same values of ranks, and sorts them based on dist. In descending order.
Question 1: Is it possible to achieve the same result in the easier way? I tried to create a Comparator, but it provided incorrect result for this particular case.
Question 2: How to get indexes of unsorted elements after sorting?
import java.util.ArrayList;
public class Test {
public static void main(String args[]) {
ArrayList<ArrayList<Double>> values = new ArrayList<ArrayList<Double>>();
ArrayList<Double> ranks = new ArrayList<Double>();
ArrayList<Double> dist = new ArrayList<Double>();
ranks.add(8.0);
ranks.add(3.0);
ranks.add(8.0);
ranks.add(1.0);
dist.add(1.8);
dist.add(2.8);
dist.add(1.9);
dist.add(2.1);
values.add(0,ranks);
values.add(1,dist);
int len = ranks.size();
ArrayList<ArrayList<Double>> sortedranks = new ArrayList<ArrayList<Double>>();
sortedranks = order(values,0,ranks.size());
boolean swapped = true;
int j = 0;
double tmp1, tmp2;
while (swapped) {
swapped = false;
j++;
for (int i = 0; i < len - j; i++) {
double val1 = sortedranks.get(0).get(i);
double val2 = sortedranks.get(0).get(i+1);
if (val1==val2) {
if (sortedranks.get(1).get(i) < sortedranks.get(1).get(i+1)) {
tmp1 = sortedranks.get(1).get(i);
tmp2 = sortedranks.get(1).get(i+1);
sortedranks.get(1).remove(i);
sortedranks.get(1).remove(i);
sortedranks.get(1).add(i,tmp2);
sortedranks.get(1).add(i+1,tmp1);
swapped = true;
}
}
}
}
for (int i = 0; i < len; i++) {
System.out.println("Ranks " + i + " : " + sortedranks.get(0).get(i)
+ ", Distances : " + sortedranks.get(1).get(i));
}
}
public static ArrayList<ArrayList<Double>> order(ArrayList<ArrayList<Double>> values, int i_start, int i_fin) {
boolean swapped = true;
int j = 0;
int i_rank = 0;
int i_dist = 1;
double tmp1_rank, tmp2_rank, tmp1_dist, tmp2_dist;
while (swapped) {
swapped = false;
j++;
for (int i = i_start; i < i_fin - j; i++) {
if (values.get(i_rank).get(i) < values.get(i_rank).get(i+1)) {
tmp1_rank = values.get(i_rank).get(i);
tmp2_rank = values.get(i_rank).get(i+1);
tmp1_dist = values.get(i_dist).get(i);
tmp2_dist = values.get(i_dist).get(i+1);
values.get(i_rank).remove(i);
values.get(i_rank).remove(i);
values.get(i_dist).remove(i);
values.get(i_dist).remove(i);
values.get(i_rank).add(i,tmp2_rank);
values.get(i_rank).add(i+1,tmp1_rank);
values.get(i_dist).add(i,tmp2_dist);
values.get(i_dist).add(i+1,tmp1_dist);
swapped = true;
}
}
}
return values;
}
}
The code that uses Comparator (does not work for my case):
public class MyEntry implements Comparable<MyEntry> {
private Double rank;
private Double dist;
public MyEntry(double rank, double dist) {
this.rank = rank;
this.dist = dist;
}
public static Comparator<MyEntry> ValueComparator = new Comparator<MyEntry>() {
public int compare(MyEntry value1, MyEntry value2) {
Double rfirst = value1.rank;
Double rsecond = value2.rank;
Double dfirst = value1.dist;
Double dsecond = value2.dist;
if (rsecond != rfirst) {
return (int) (rsecond - rfirst);
}
else {
return (int) (dsecond - dfirst);
}
}
};
}
Your Comperator approach would work, but is has a few bugs.
First of all I would replace the Doubles in MyEntry by double.
Comparing Double is not the same as comparing double
For example:
Double a = 1.0;
Double b = 1.0;
System.out.println(a == b);
System.out.println(a.equals(b));
System.out.println(a.doubleValue()== b.doubleValue());
Will return
false
true
true
Then in the comparison you cast to int, but this implies flooring that data.
(int) (2 - 1.9) will give 0
Better is to compare using < and return -1 or 1.
public static Comparator<MyEntry> ValueComparator = new Comparator<MyEntry>() {
public int compare(MyEntry value1, MyEntry value2) {
double rfirst = value1.rank;
double rsecond = value2.rank;
double dfirst = value1.dist;
double dsecond = value2.dist;
if (rsecond != rfirst) {
return rsecond < rfirst?-1:1;
}
else if(dsecond!=dfirst){
return dsecond < dfirst ?-1:1;
}
return 0;
}
}
For your second question you require an index. This could be done in two ways. First option is to include the index in MyEntry like this:
public class MyEntry implements Comparable<MyEntry> {
private double rank;
private double dist;
private int index;
private static int nextIndex = 0;
public MyEntry(double rank, double dist) {
this.rank = rank;
this.dist = dist;
this.index = nextIndex++;
}
This way you will be able to retain the index but it is not so flexible.
A more flexible approach could be to have the index in a separate array, and sort that.
class IndexedArrayComparator implements Comparator<Integer>{
MyEntry[] array;
public IndexedArrayComparator(MyEntry[] entries){
this.array=entries;
}
public Integer[] createIndexes(){
Integer[] index = new Integer[array.length];
for(int i =0;i<index.length;i++){
index[i]=i;
}
return index;
}
public int compare(Integer i0, Integer i1) {
double rfirst = array[i0].rank;
double rsecond = array[i1].rank;
double dfirst = array[i0].dist;
double dsecond = array[i1].dist;
if (rsecond != rfirst) {
return rsecond > rfirst?-1:1;
}
else if(dsecond!=dfirst){
return dsecond > dfirst ?-1:1;
}
return 0;
}
}
You can then use it like this:
MyEntry[] entries = new MyEntry[5];
entries[0]= new MyEntry(1.1,5);
entries[1]= new MyEntry(1.1,4);
entries[2]= new MyEntry(2.1,5);
entries[3]= new MyEntry(0.1,3);
entries[4]= new MyEntry(3.1,1);
IndexedArrayComparator comp = new IndexedArrayComparator(entries);
Integer[] index = comp.createIndexes();
Arrays.sort(index,comp);
for(int i =0;i<index.length;i++){
MyEntry e = entries[index[i]];
System.out.println(String.format("%2d:r= %3.1f, d= %3.1f" ,index[i],e.rank,e.dist));
}
Which will give:
3:r= 0.1, d= 3.0
1:r= 1.1, d= 4.0
0:r= 1.1, d= 5.0
2:r= 2.1, d= 5.0
4:r= 3.1, d= 1.0
The second way of sorting while maintaining the index is also described here. Credits to Jon Skeet

Categories