Sorting ArrayList of Objects Java - java

I have an ArrayList of Objects that I'd like to sort by their value. Basically I have 9 different mathematical functions (i.e., f1(n) = log n, f2(n) = n, f3(n) = n log n, etc). I plugged the value of 1 into all 9 functions and I placed their results in an ArrayList of Objects with their label attached to them as shown in the code below. I'd like to sort the entire list of results.
ArrayList<Object>val1 = new ArrayList<Object>();
val1.add("f\u2081(1) = " + log(funcValues[0]));
val1.add("f\u2082(1) = " + funcValues[0]);
val1.add("f\u2083(1) = " + exponent(funcValues[0]));
val1.add("f\u2084(1) = " + f4(funcValues[0]));
val1.add("f\u2085(1) = " + squared(funcValues[0]));
val1.add("f\u2086(1) = " + cubed(funcValues[0]));
val1.add("f\u2087(1) = " + twoN(funcValues[0]));
val1.add("f\u2088(1) = " + factorial(funcValues[0]));
val1.add("f\u2089(1) = " + f9(funcValues[0]));
Basically, wherever you see log, funcValues, exponent, f4, squared, etc those are all functions that compute the answers to the mathematical functions. The output of this ArrayList is:
f₁(1) = 0.0 f₂(1) = 1 f₃(1) = 1.0 f₄(1) = 0.0 f₅(1) =
1 f₆(1) = 1.0 f₇(1) = 2.0 f₈(1) = 1 f₉(1) = 0.0
I'd like to sort only the numbers. I was trying to do it this way:
class ValuesSorted implements Comparator<Object> {
#Override
public int compare(Object v1, Object v2) {
if ()
return 0;
}
}
I am stuck on the if statement because I can't do something like if (v1.getValue > v2.getValue) because I am using 9 different function calls to pull each of those values.

Simply try
Collections.sort(testList);
Collections.reverse(testList);
http://docs.oracle.com/javase/7/docs/api/java/util/Collections.html

You are trying to track two things, the value and a label. When you are tracking two associated things, use a Map. In this case, a sorted map, i.e. a TreeMap.
TreeMap map = new TreeMap<Double, String>();
// for each function, map.put(value, label), e.g.
map.put(log(funcValues[0]), "f\u2081(1)");
...
map.put(f4(funcValues[0]),"f\u2084(1)");
...
map.put(f9(funcValues[0]), "f\u2089(1)");
And result will be sorted by numerical value. map.values() will have the labels in sorted order.

class Pair<X,Y>{
private X first;
private Y second;
Pair(X first,Y second){
this.first=first;
this.second=second;
}
public X getX() {
return first;
}
public void setX(X first) {
this.first = first;
}
public Y getY() {
return second;
}
public void setY(Y second) {
this.second = second;
}
public Comparator<Pair<X, Y>> getComparator(){
return new Comparator<Pair<X, Y>>() {
#Override
public int compare(Pair<X, Y> o1, Pair<X, Y> o2) {
double a=(Double) o1.getY();
double b=(Double) o2.getY();
if(a==b){
return 0;
}else if(a>b){
return 1;
}else{
return -1;
}
}
};
}
}
public class Main{
public static void main(String[] arg){
List<Pair<String,Double>> val1 = new ArrayList<Pair<String,Double>>();
val1.add(new Pair<String,Double>("f\u2081(1) = ", 0.1));
val1.add(new Pair<String,Double>("f\u2082(1) = ", 0.2));
val1.add(new Pair<String,Double>("f\u2083(1) = ", 0.1));
val1.add(new Pair<String,Double>("f\u2084(1) = ", 1.1));
val1.add(new Pair<String,Double>("f\u2085(1) = ", 1.2));
val1.add(new Pair<String,Double>("f\u2086(1) = ", 2.0));
val1.add(new Pair<String,Double>("f\u2087(1) = ", 2.1));
val1.add(new Pair<String,Double>("f\u2088(1) = ", 0.3));
Collections.sort(val1,new Pair<String,Double>("",0.0).getComparator());
for (Pair<String, Double> pair : val1) {
System.out.println(pair.getX()+" "+pair.getY());
}
}
}

Related

Converting ArrayList to HashMap, however, selecting choice objects with different variable classes within ArrayList

This is a project I am working on for my intro to java class.
My professor has already laid out the base code, and the point of the project is to work with HashMaps and ArrayLists in combination with arithmetic.
Everything here is done by my professor so far except:
HashMap<String, Integer> typeAttack = new HashMap<String, Integer>();
I am also provided with a .csv file containing various statistics of a whole list of pokemon.
Out of the objects that my professor has already passed into the ArrayList "pokemonList," I only need to consider the "type" and "attack" variable, as I need to figure out which type of pokemon in the whole .csv file averages to have the highest attack level.
int attack = Integer.parseInt(split[1]);
String type = split[5];
My question is very simple. How can I convert only a portion of the ArrayList, specifically the "attack" and "type" variables into my HashMap?
import java.util.*;
import java.io.*;
public class Project6 {
public static void main(String[] args) throws IOException {
ArrayList<Pokemon> pokemonList = collectPokemon(args[0]);
HashMap<String, Integer> typeAttack = new HashMap<String, Integer>();
}
// Don't modify this method. If you get errors here, don't forget to add the filename
// as a command line argument.
public static ArrayList<Pokemon> collectPokemon(String filename) throws IOException {
BufferedReader file = new BufferedReader(new FileReader(new File(filename)));
ArrayList<Pokemon> pokemonList = new ArrayList<Pokemon>();
file.readLine();
while(file.ready()) {
String line = file.readLine();
String[] split = line.split(",");
String name = split[0];
int attack = Integer.parseInt(split[1]);
int defense = Integer.parseInt(split[2]);
double height = Double.parseDouble(split[3]);
double weight = Double.parseDouble(split[6]);
String type = split[5];
Pokemon current = new Pokemon(name, attack, defense, height, weight, type);
pokemonList.add(current);
}
return pokemonList;
}
}
POKEMON CLASS
import java.util.*;
public class Pokemon {
private String name;
private int attack;
private int defense;
private double height;
private double weight;
private String type;
public Pokemon(String inName, int inAttack, int inDefense, double inHeight, double inWeight, String inType) {
name = inName;
attack = inAttack;
defense = inDefense;
height = inHeight;
weight = inWeight;
type = inType;
}
public String getName() {
return name;
}
public int getAttack() {
return attack;
}
public int getDefense() {
return defense;
}
public double getHeight() {
return height;
}
public double getWeight() {
return weight;
}
public String getType() {
return type;
}
public String toString() {
return "Pokemon: '" + name + "' Atk: " + attack + " Def: " + defense + " Ht: " + height + "m Wt: " + weight + "Kg Type: " + type;
}
}
You could try with a simple for each loop:
// Note the Map type change to Double!
HashMap<String, Double> typeToAvgAttack = new HashMap<String, Double>();
// Intermediate map to store list of all attack values per type
HashMap<String, List<Integer>> typeToAttack = new HashMap<String, List<Integer>>();
for (Pokemon pokemon: pokemonList) {
String type = pokemon.getType();
int attack = pokemon.getAttack();
// the map is empty at start, we need to check for the keys (pokemon type) existance
List<Integer> attackValues = typeToAttack.get(type);
if (attackValues == null) {
typeToAttack.put(type, attackValues = new ArrayList());
}
attackValues.add(attack);
}
// Iterate over map keys to calculate the average
for (String type : typeToAttack.keySet()) {
List<Integer> attackValues = typeToAttack.get(type);
double average = calculateAverage(attackValues);
typeToAvgAttack.put(type, average);
}
The helper function, copied from here:
public static double calculateAverage(List <Integer> values) {
double sum = 0d;
if(!values.isEmpty()) {
for (Integer value: values) {
sum += value;
}
return sum / values.size();
}
return sum;
}
Be aware though that this approach is neither optimal nor elegant. I'd prefer to use Stream API, but that may not be best suited for your current proficiency.
EDIT: I've adjusted the code not to use Java 8 methods.

How to access a member in a class with arraylist that adds its toString

I have a class, lets say CargoShip, which is a derived class of 'Starcraft', which implements the interface IStarcraft.
I have a function public static ArrayList<String> getSpacecraftDescriptionsByCommissionYear(ArrayList<ISpacecraft> fleet)
Question: The CargoShip has toString which prints name, commissionYear, etc..
I want to do two things: First, I want to use each Ship's toString (like the one in the CargoShip), and second I want it to be sorted by CommissionYear.
Problem: I don't know how to access the commissionYear field after I've added the toString to the arrayList.
ArrayList<String> strCommissions = new ArrayList<String>();
for(ISpacecraft flee : fleet)
{
strCommissions.add(flee.toString());
}
//Collections.sort(//What to write here??//);
return strCommissions;
}
Here is the CargoShip class if you need it:
package starfleet;
public class CargoShip extends Spacecraft{
private int numberOfSpaceCranes;
static int count = 0;
public CargoShip(String name, int commissionYear, float maximalSpeed,int cargoCapacity, int numberOfSpaceCranes)
{
this.name = name;
this.commissionYear = commissionYear;
if(MaximalSpeed())
this.maximalSpeed = maximalSpeed;
this.cargoCapacity = cargoCapacity;
this.numberOfSpaceCranes = numberOfSpaceCranes;
count++;
}
public int getNumberOfSpaceCranes ()
{
return this.numberOfSpaceCranes;
}
#Override
public String getName() {
return this.name;
}
#Override
public int getCommissionYear() {
return this.commissionYear;
}
#Override
public float getMaximalSpeed() {
if(MaximalSpeed())
return this.maximalSpeed;
else
return 0f;
}
#Override
public int getCargoCapacity() {
return this.cargoCapacity;
}
#Override
public int getFirePower() {
return this.firePower;
}
#Override
public int getAnnualMaintenanceCost() {
int cost = 0;
this.commissionYear = 2000;
cost += getCommissionYear();
cost += (500 * this.numberOfSpaceCranes);
cost += (2 * getCargoCapacity()); //To check: TotalCargoWeightCapacity?
// TODO Auto-generated method stub
return 0;
}
public String toString()
{
return
"Name = " + getName() + System.lineSeparator() +
"CommissionYear = " + getCommissionYear() + System.lineSeparator() +
"MaximalSpeed = " + getMaximalSpeed() + System.lineSeparator() +
"CargoCapacity = " + getCargoCapacity() + System.lineSeparator() +
"FirePower = " + getFirePower() + System.lineSeparator() +
"AnnualMaintenanceCost = " + getAnnualMaintenanceCost() + System.lineSeparator() +
"numberOfSpaceCranes = " + getNumberOfSpaceCranes() + System.lineSeparator();
}
}
First, you can copy the list fleet into a new one:
ArrayList<ISpacecraft> objects = new ArrayList<>(fleet);
then you can sort it by commission year:
Collections.sort(objects, Comparator.comparingInt(ISpacecraft::getCommissionYear));
then create the list of Strings:
ArrayList<String> strCommissions = new ArrayList<String>();
objects.forEach(o -> strCommissions.add(o.toString()));
thus your function becomes:
public static ArrayList<String> getSpacecraftDescriptionsByCommissionYear(ArrayList<ISpacecraft> fleet){
ArrayList<ISpacecraft> objects = new ArrayList<>(fleet);
Collections.sort(objects, Comparator.comparingInt(ISpacecraft::getCommissionYear));
ArrayList<String> strCommissions = new ArrayList<String>();
objects.forEach(o -> strCommissions.add(o.toString()));
return strCommissions;
}
reading:
Java 8 Lambda : Comparator example
You should implement Comparable and implement compareTo method or as mentioned above Comparator can be used.
public int compareTo(CargoShip otherCargoShip) {
int i = Name .compareTo(other.Name );
if (i != 0) return i;
i = CommissionYear.compareTo(other.CommissionYear);
if (i != 0) return i;
return Integer.compare(MaximalSpeed , other.MaximalSpeed );
}

Extended Euclidean algorithm JAVA RSA

I´m trying to implement the EEA. I found this pattern which I use also.
extended_euclid(a,b)
1 if b = 0
2 than return (a,1,0)
3 (d',s',t') <-- extended_euclid(b, a mod b)
4 (d,s,t) <--- (d',t',s' - (a div b)t')
5 return (d,s,t)
And my code looks like this:
public static Triple extendedEuclid(BigInteger a, BigInteger b) {
if (b.equals(new BigInteger("0"))) {
return new Triple(a, new BigInteger("1"), new BigInteger("0"));
} else {
Triple i = extendedEuclid(b, a.mod(b));
return new Triple(i.getA(), i.getB(), (i.getC().divide(i.getB()).multiply(i.getC())));
}
}
I´m not quite sure if my code is correct. I looked up many pages like twenty or so but I still don´t get it. I´m mentally stuck.
Thanks.
It looks like you got the operations in the final return out of order. You also implemented the third value of Triple incorrectly. Here is my implementation. (I also used BigInteger's helper constants/methods + renamed variables for clarity.)
public class ExtendedEuclidAlgorithm {
public static void main(final String[] args) {
System.out.println("eea(240, 46) = " + apply(BigInteger.valueOf(240), BigInteger.valueOf(46)));
System.out.println("eea(65, 40) = " + apply(BigInteger.valueOf(65), BigInteger.valueOf(40)));
System.out.println("eea(1239, 735) = " + apply(BigInteger.valueOf(1239), BigInteger.valueOf(735)));
}
/*
* extended_euclid(d,s)
if s = 0
than return (d,1,0)
(d',s',t') <-- extended_euclid(s, d mod s)
return (d',t',s' - (d div s)t')
*/
public static Triple apply(final BigInteger a, final BigInteger b) {
if (b.equals(BigInteger.ZERO)) {
return new Triple(a, BigInteger.ONE, BigInteger.ZERO);
} else {
final Triple extension = apply(b, a.mod(b));
return new Triple(extension.d, extension.t, extension.s.subtract(a.divide(b).multiply(extension.t)));
}
}
private static class Triple {
public final BigInteger d;
public final BigInteger s;
public final BigInteger t;
private Triple(final BigInteger d, final BigInteger s, final BigInteger t) {
this.d = d;
this.s = s;
this.t = t;
}
#Override
public String toString() {
return "Triple{" +
"d=" + d +
", s=" + s +
", t=" + t +
'}';
}
}
}
eea(240, 46) = Triple{d=2, s=-9, t=47}
eea(65, 40) = Triple{d=5, s=-3, t=5}
eea(1239, 735) = Triple{d=21, s=-16, t=27}
I validated the response values from Wikipedia and here.

What is wrong with my implementation of Kruskal's algorithm using union-find data structure.

I am trying to implement the Kruskal's algorithm, and find the sum of the weights in the MST.
I think my problem lays somewhere where I set the parent of each node, but I am not sure, because in small examples it works fine, however with big example it doesnt detect a cycle, and the final answer is wrong. so my find might be wrong, but I am not sure.
Here is my code:
import java.io.File;
import java.io.FileNotFoundException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Scanner;
public class Graph {
private static int parent[];
private static int numberOfNodes, numberOfEdges, weight;
private static Node startNode, endNode;
private static Graph g;
private static ArrayList<Integer> listOfWeights = new ArrayList<Integer>();
private static ArrayList<Edge> listOfEdges = new ArrayList<Edge>();
private static ArrayList<Node> listOfNodes = new ArrayList<Node>();
private static HashMap<Edge, Integer> distance = new HashMap<Edge, Integer>();
private static HashMap<Edge, Integer> sortedMap = new HashMap<Edge, Integer>();
//values = Integer
private Scanner sc;
public static void main(String[] args) throws FileNotFoundException {
// TODO Auto-generated method stub
g = new Graph();
}
public Graph() throws FileNotFoundException {
sc = new Scanner(new File("data"));
numberOfNodes = Integer.parseInt(sc.next());
numberOfEdges = Integer.parseInt(sc.next());
if(numberOfEdges > 0){
for(int i = 0; i < numberOfEdges; i++) {
//read the start point
startNode = new Node(Integer.parseInt(sc.next()));
//read the end point
endNode = new Node(Integer.parseInt(sc.next()));
//read the price per node
weight = Integer.parseInt(sc.next());
Edge e = new Edge(startNode,endNode);
//set the weight per node
e.setWeight(weight);
//put them in a hashmap
distance.put(e,e.getWeight());
if(!listOfNodes.contains(startNode)){
listOfNodes.add(startNode);
}
if(!listOfNodes.contains(endNode)){
listOfNodes.add(endNode);
}
//System.out.println(distance.get(e));
}
System.out.println("without sort distance: " + distance.toString());
for (Object key : distance.keySet()) {
listOfEdges.add((Edge) key);
}
for (Object value : distance.values()) {
listOfWeights.add((Integer) value);
}
sortedMap = sortHashMapByValuesD(distance);
//System.out.println("list of nodes: "+ listOfNodes);
parent = new int[listOfNodes.size()];
System.out.println("sorted by weights: "+sortedMap.toString());
System.out.println(kruskalAlgo(sortedMap));
}
else{
System.out.println(0);
}
}
public static void makeSet(int x){
parent[x-1] = x;
}
public static int find(int x){
//System.out.println("FIND ==> x: " + x + ".parent = " + parent[x-1] );
if(parent[x-1] == x){
return x;
}
return find(parent[x-1]);
}
public static void union(int x, int y){
//System.out.println("parent[0]: "+parent[0]);
parent[x-1] = y;
System.out.println("x: " + x + " UNION parent[x-1]: " + parent[x-1] + " y " + y );
}
public static int kruskalAlgo(HashMap<Edge, Integer> s){
parent[0] = 0;
for(int i = 0; i < parent.length; i++){
makeSet(listOfNodes.get(i).getId());
//System.out.println("parent is: "+parent[i] + " for node"+ listOfNodes.get(i));
}
// for each edge (u,v) ∈ G, taken in increasing order by weight
int min = 0;
int edgeNumber = 0;
for (Edge key : s.keySet()) {
if(edgeNumber == listOfNodes.size()-1){
//System.out.println("edgeNumber: "+ edgeNumber);
//System.out.println("listOfNodes.size()-1: "+ (listOfNodes.size()-1));
return min;
}
Node u = key.getFromNode();
//System.out.println(u);
Node v = key.getToNode();
//System.out.println(v);
if(find(u.getId()) != find (v.getId())){
min += key.getWeight();
union(u.getId(),v.getId());
System.out.println(key + " weight is: " + key.getWeight());
edgeNumber++;
}
}
return min;
}
public static ArrayList<Edge> findSet(Node v){
ArrayList<Edge> nodes = new ArrayList<Edge>();
return nodes;
}
//make an ordered listed by increasing weights
public LinkedHashMap<Edge, Integer> sortHashMapByValuesD(HashMap<Edge, Integer> newMap) {
//list of edges
List<Edge> mapKeys = new ArrayList<Edge>(newMap.keySet());
//list of nodes
List<Integer> mapValues = new ArrayList<Integer>(newMap.values());
//sort the nodes
Collections.sort(mapValues);
LinkedHashMap<Edge, Integer> sortedMap = new LinkedHashMap<Edge, Integer>();
Iterator<Integer> valueIt = mapValues.iterator();
while (valueIt.hasNext()) {
Object val = valueIt.next();
Iterator<Edge> keyIt = mapKeys.iterator();
while (keyIt.hasNext()) {
Object key = keyIt.next();
String comp1 = newMap.get(key).toString();
String comp2 = val.toString();
if (comp1.equals(comp2)){
newMap.remove(key);
mapKeys.remove(key);
sortedMap.put((Edge)key, (Integer)val);
break;
}
}
}
return sortedMap;
}
}
I think the problem may be in your implementation of union:
public static void union(int x, int y){
parent[x-1] = y;
}
the problem is if x already has been joined into a set, it will already have a parent which you override.
The solution is to join the root of the two candidates instead of the leaf nodes:
public static void union(int x, int y){
x=find(x);
y=find(y);
parent[x-1] = y;
}
By the way,a good description of this Disjoint-set algorithm, plus hints on making it more efficient via "union by rank" and "path compression" is on wikipedia at this page.

How to sort a treemap and display its values and indices of the values and also skip to the next index if the previous one is same with the next

I have a TreeMap in which I have stored some values. The map is sorted using the values, from highest to lowest. Now I want print out the contents of the TreeMap with their various indices.
If I have the following pairs in the map :
("Andrew", 10),
("John", 5),
("Don",9),
("Rolex", 30),
("Jack", 10),
("Dan",9)
I want to print out:
Rolex, 30 , 1
Jack, 10, 2
Andrew, 10, 2
Dan, 9, 4
Don, 9, 4
John, 5, 6.
This is what I've been trying but it doesn't seem to work well:
/**
*
* #author Andrew
*/
import java.util.*;
public class SortArray {
static <K,V extends Comparable<? super V>> SortedSet<Map.Entry<K,V>>entriesSortedByValues(Map<K,V> map) {
SortedSet<Map.Entry<K,V>> sortedEntries = new TreeSet<Map.Entry<K,V>>(
new Comparator<Map.Entry<K,V>>() {
#Override public int compare(Map.Entry<K,V> e1, Map.Entry<K,V> e2) {
int res = e1.getValue().compareTo(e2.getValue());
return res!= 0 ? res : 1;
//return e1.getValue().compareTo(e2.getValue());
}
});
sortedEntries.addAll(map.entrySet());
return sortedEntries;
}
public void test(){
Map mm = new TreeMap();
mm.put("Andrew", 11);
mm.put("Mbata", 21);
mm.put("Chinedu", 14);
mm.put("Bol", 14);
mm.put("Don", 51);
mm.put("Rolex", 16);
mm.put("Son", 41);
SortedSet newMap = entriesSortedByValues(mm);
Iterator iter = newMap.iterator();
int x = newMap.size();
List names = new ArrayList();
List scores = new ArrayList();
while(iter.hasNext()){
String details = iter.next().toString();
StringTokenizer st = new StringTokenizer(details, "=");
String name = st.nextToken();
names.add(name);
String score = st.nextToken();
scores.add(score);
//System.out.println(name + " Score:" +score + " Position:" + x);
x--;
}
Collections.reverse(names);
Collections.reverse(scores);
int pos = 1;
for(int i = 0; i<names.size();){
try{
int y = i+1;
if(scores.get(i).equals(scores.get(y))){
System.out.print("Name: "+ names.get(i)+"\t");
System.out.print("Score: "+ scores.get(i)+"\t");
System.out.println("Position: "+ String.valueOf(pos));
//pos++;
i++;
continue;
} else{
System.out.print("Name: "+ names.get(i)+"\t");
System.out.print("Score: "+ scores.get(i)+"\t");
System.out.println("Position: "+ String.valueOf(pos++));
}
i++;
} catch(IndexOutOfBoundsException e) {}
}
}
public SortArray(){
test();
}
public static void main(String [] args){
new SortArray();
}
}
First of all, Why are you catching that IndexOutOfBoundsException and doing nothing with it? if you run that you'll get that exception thrown (and I thing you already know it) the problem is in your algorithm inside the last "for" loop. I shouldn't give you the solution, but wth... at least you did some effort to make it run, so this is a more less working version:
import java.util.*;
public class SortArray {
static <K,V extends Comparable<? super V>> SortedSet<Map.Entry<K,V>>entriesSortedByValues(Map<K,V> map) {
SortedSet<Map.Entry<K,V>> sortedEntries = new TreeSet<Map.Entry<K,V>>(
new Comparator<Map.Entry<K,V>>() {
#Override public int compare(Map.Entry<K,V> e1, Map.Entry<K,V> e2) {
int res = e1.getValue().compareTo(e2.getValue());
return res != 0 ? res : 1;
//return e1.getValue().compareTo(e2.getValue());
}
});
sortedEntries.addAll(map.entrySet());
return sortedEntries;
}
public void test(){
Map mm = new TreeMap();
mm.put("Andrew", 11);
mm.put("Mbata", 21);
mm.put("Chinedu", 14);
mm.put("Bol", 14);
mm.put("Don", 51);
mm.put("Rolex", 16);
mm.put("Son", 41);
SortedSet newMap = entriesSortedByValues(mm);
Iterator iter = newMap.iterator();
int x = newMap.size();
List names = new ArrayList();
List scores = new ArrayList();
while(iter.hasNext()){
String details = iter.next().toString();
StringTokenizer st = new StringTokenizer(details, "=");
String name = st.nextToken();
names.add(name);
String score = st.nextToken();
scores.add(score);
//System.out.println(name + " Score:" +score + " Position:" + x);
x--;
}
Collections.reverse(names);
Collections.reverse(scores);
int pos;
int posBis = 0;
String lastScore = "";
for(int i = 0; i<names.size(); i++){
System.out.print("Name: "+ names.get(i)+"\t");
System.out.print("Score: "+ scores.get(i)+"\t");
if(i == 0 || !lastScore.equals(scores.get(i))) {
pos = i + 1;
posBis = pos;
} else {
pos = posBis;
}
System.out.println("Position: "+ String.valueOf(pos));
lastScore = (String)scores.get(i);
}
}
public SortArray(){
test();
}
public static void main(String [] args){
new SortArray();
}
}
Your SortedSet is the wrong way to go about this. You can see in your Comparator that it gets a bit messy when both values have to be looked up by the same key then you've got this messy (and incorrect) return res != 0 ? res : 1 (the 1 should really be e1.getKey().compareTo(e2.getKey()) rather than always returning 1).
A better way to go about this would be to just sort the keys yourself in a List, rather than creating a separate SortedSet. This way you don't have to worry about duplicate sorting values.
You can also abstract out the Comparator stuff a little, to make it more reusable in other code later, if you need it.
import java.util.*;
public class PrintSomething {
public static <T extends Comparable<T>> Comparator<T> reverseComparator(final Comparator<T> oldComparator) {
return new Comparator<T>() {
#Override
public int compare(T o1, T o2) {
return oldComparator.compare(o2, o1);
}
};
}
public static <K,V extends Comparable<V>> Comparator<K> keyedComparator(final Map<K,V> lookup) {
return new Comparator<K>() {
#Override
public int compare(K o1, K o2) {
return lookup.get(o1).compareTo(lookup.get(o2));
}
};
}
public static void main(String[] args) {
Map<String, Integer> mm = new HashMap<>();
mm.put("Andrew", 10);
mm.put("John", 5);
mm.put("Don", 9);
mm.put("Rolex", 30);
mm.put("Jack", 10);
mm.put("Dan", 9);
Comparator<String> comparator = reverseComparator(keyedComparator(mm));
List<String> keys = Arrays.asList(mm.keySet().toArray(new String[mm.size()]));
//Collections.sort(keys); // optional, if you want the names to be alphabetical
Collections.sort(keys, comparator);
int rank = 1, count = 0;
Integer lastVal = null;
for (String key : keys) {
if (mm.get(key).equals(lastVal)) {
count++;
} else {
rank += count;
count = 1;
}
lastVal = mm.get(key);
System.out.println(key + ", " + mm.get(key) + ", " + rank);
}
}
}
In general things like SortedSet make more sense when you need to keep the data itself sorted. When you just need to process something in a sorted manner one time they're usually more trouble than they're worth. (Also: is there any reason why you're using a TreeMap? TreeMaps sort their keys, but not by value, so in this case you're not taking advantage of that sorting. Using a HashMap is more common in that case.)
You do a lot of work with the iterator, calling toString(), then splitting the results. And your Comparator is extra work too. Stay with a Map on both sides - you can use keys() and values() more directly, and let Java do the sorting for you. Most of your above code can be replaced with: (for clarity, I changed your name "mm" to "originalMap")
Map<Integer, String> inverseMap = new TreeMap<Integer, String>();
for (Map.Entry<String, Integer> entry : originalMap.entrySet()) {
inverseMap.put(entry.getValue(), entry.getKey());
}
Now, iterate over inverseMap to print the results. Note that if a count does exist twice in originalMap, only one will be printed, which is what you want. But which one gets printed left as an exercise for the reader :-). You might want to be more specific on that.
EDIT ADDED: If you do want to print out duplicate scores, this is not what you want. The original post I read said to skip if they were the same, but I don't see that after the edits, so I'm not sure if this is what OP wants.

Categories