I have 2 arrays:
private String[] placeName;
private Double[] miles;
The data in them look like this:
placeName = {"home", "away", "here"};
miles = {111, 11, 3};
The position of the values match to each other. ie home = 111 and away = 11
I need to sort these arrays together so I don't lose how they are matched by the the number- lowest to highest. What is the best way to accomplish this? Do I need to combine the arrays first?
Since the two values are so tightly coupled together I would actually write a custom class to contain the information and then sort those classes instead of playing around with raw arrays. Doing so would leave you open to many possible bugs down the line.
This allows for much better control, data encapsulation and future expansion of what methods or data your class may contain.
public class MyDistance implements Comparable<MyDistance> {
private String placename;
private double mileage;
public MyDistance(String placename, double milage) {
this.placename = placename;
this.milage = milage;
}
public String getPlacename() {
return this.placename;
}
public double getMilage() {
return this.milage;
}
#Override
public int compareTo(MyDistance anotherDistance)
{
return milage.compareTo(anotherDistance.getMilage());
}
}
If you want more flexibility in your sort then instead of having your MyDistance class implement Comparable you can write a custom Comparator<MyDistance> class:
public class DistanceComparator extends Comparator<MyDistance> {
#Override
public int compare(MyDistance dist1, MyDistance dist2) {
return dist1.getMilage().compareTo(dist2.getMilage());
}
}
You can use this Comparator to sort using Collections:
List<MyDistance> distanceList = getDistanceListSomehow();
Collections.sort(distanceList, new DistanceComparator());
You are not restricted to a List, I just used it for explanatory purposes. You should look at the full range of Java Collections types to best choose one that suits your purposes. As a suggestion though, the ArrayList type is easy to use and retains order like you would want.
One way is to create a TreeMap. Assuming you are sorting by miles.
TreeMap tm = new TreeMap<Double, String>();
for (int i=0; i<miles.length; i++) {
tm.put(miles[i], placeName[i]);
}
// tm is already sorted - iterate over it...
NOTE: IF you have places with the same exact distance in miles this will not work. e.g. if you had a "work" that was 11 miles, just like "away", this won't work. You'd probably want some form of MultiMap for that...
Maybe put the arrays in a TreeMap and sort it
SortedMap<Double,String> map = new TreeMap<>();
map.put(111,"home");
map.put(11,"away");
map.put(3,"here");
The elemtns are inserted sorted by their key
Related
I have an ArrayList<ArrayList<String>> that is a list of couple of values:
John, 12.3
Marcus, 35.0
Sue, 11.4
How to sort the list by amount?
If in this case there is a better way than using an ArrayList of an ArrayList, please tell me and tell me then how to sort it. Thank you.
Instead I will recommend you to use a class and use class like comparable or comparator to sort.
Something like this:
class Person implements Comparable<Person> {
String name;
double amount;
Person(String n, double d) {
name = n;
amount = d;
}
public int compareTo(Person other) {
if (amount != other.amount)
return Double.compare(amount, other.amount);
return name.compareTo(other.name);
}
}
and this is easy to implement and understand.
Use a Comparator:
A comparison function, which imposes a total ordering on some
collection of objects. Comparators can be passed to a sort method
(such as Collections.sort or Arrays.sort) to allow precise control
over the sort order. Comparators can also be used to control the order
of certain data structures (such as sorted sets or sorted maps), or to
provide an ordering for collections of objects that don't have a
natural ordering.
It'd be great if you could add more information about why you are using those values then I am sure a better approach can be suggested.
I solved with this:
Collections.sort(data, new Comparator<ArrayList<String>>() {
#Override
public int compare(ArrayList<String> one, ArrayList<String> two) {
// Replacements for using Double.parseDouble(string) later
String value1 = one.get(1).replace(",", ".");
String value2 = two.get(1).replace(",", ".");
if (Double.parseDouble(value1) < Double.parseDouble(value2))
return -1;
else if (Double.parseDouble(value1) > Double.parseDouble(distanza2))
return 1;
else
return 0;
}
});
I am building a couple of methods which are supposed to create a cache of input strings, load them in to a list, and then determine the number of occurrences of each string in that list, ranking them in order of the most common elements.
The string, or elements themselves are coming from a JUnit test. It's calling up a method called
lookupDistance(dest)
where "dest" is a String (destination airport code), and the lookupDistance returns the distance between two airport codes....
There's the background. The problem is that I want to load all of the "dest" strings in to a cache. What's the best way to do that?
I have skeleton code that has a method called:
public List<String> mostCommonDestinations()
How would I add "dest" strings to the List in a transparent way? The JUnit test case is only calling lookupDistance(dest), so how can I also redirect those "dest" strings to the List in this method?
How would I then quantify the number of occurrences of each element and say, rank the top three or four?
Have a Map<String, Integer> destinations = new HashMap<>();
In lookupDistance(dest), do something like this (untested pseudocode):
Integer count = destinations.get(dest);
if (count == null) {
destinations.put(dest, Integer.valueOf(1));
} else {
count = Integer.valueOf(count.intValue() + 1);
}
This way, you count the occurences of each dest.
Go through the Map and find the highest counts. That's a bit tricky. One approach might be:
List> list = new ArrayList<>();
list.addAll(destinations.entrySet());
// now you have a list of "entries", each of which maps from dest to its respective counter
// that list now has to be sorted
Collections.sort(list, comparator);
The comparator we used in this invocation has still to be written. It has to take two arguments, which are elements of the list, and compare them according to their counter value. the sort routine will do the rest.
Comparator<Map.Entry<String, Integer>> comparator = new Comparator<>() {
public #Override int compare(Map.Entry<String, Integer> a, Map.Entry<String, Integer> b) {
return a.getValue().intValue() - b.getValue().intValue();
}
}
Ok, so we have a sorted List of Entrys now from which you can pick the top 5 or so. Think that's pretty much it. All this looks more complicated than it should be, so I'm curios for other solutions.
You can add known destination at startup and keep adding new strings to cache as they arrive. That's one way. The other way is to cache strings as they are requested, keeping them for future request. In that case your lookupDistance should also cache string.
Start by making a small class that contains a Hashmap. The key would be your destination string, and the value can either be an object if you want to keep multiple information or just a number specifying how many times that string is used. I would recommend using a data object.
Please note that code below is just to you an idea, more like a pseudo-code.
class Cache {
private Hashmap<String, CacheObject>;
public void Add(string, CacheObject);
public CacheObject Lookup(string);
public CacheObject Remove(string);
public static Cache getInstance(); //single cache
}
class CacheObject {
public int lookupCount;
public int lastUsed;
}
In your lookupDistance you can simply do
if(Cache.getInstance().Lookup(string) == null) {
Cache.getInstance().Add(string, new CacheObject() { 1, Date.now});
}
I want some way to pair String values and pass it on as a data structure. Any recommendations? Would a Map work? The issue that I'm having with a Map is that not all strings will be paired in this context, only a few of them. I need to have all the strings and if there exists one, it's string pair as well. If anything lacks clarity, let me know.
A Map can be used, with a special value for string without pair.
Well, this is probably not the best way, but what I sometimes use is a duplex type structure that is similar to Python's tuple.
I build a generic structure like so:
class Duplex<T,T> {
private T item1, item2;
public Duplex(T one){
item1 = one;
}
public Duplex(T one, T two){
item1 = one;
item2 = two;
}
//Getters + Accessors
}
Doesn't have to be generic, but it lets you reuse it for other situations.
I haven't used maps before though, so those might actually be better.
A map will give you the key value pairing that you want. What you may want is something like this:
class MyPair
{
String first;
String second;
// Equals and Hashcode
}
Now it is up to you to decide the inner parameters of your MyPair class.
Map pairings = new HashMap();
Since most of your elements will be one String I suggest turning your pairs into Strings as well.
public static final String SEP = "\uFFFF"; // not a valid character by definition.
public static String pair(String a, String b) {
return a + SEP + b;
}
public static String[] split(String str) {
return str.split(SEP);
}
One straightforward way is to use arrays.
List<String[]> pairs = new ArrayList<String[]>();
...
pairs.add(new String[]{"first", "second"});
pairs.add(new String[]{"pairless"});
Or use whatever container you want, List here is just an example, point is String[].
Note: Using plain array is sort of "quick and dirty", it's more "proper" to create a custom "Pair" class. Especially if you have methods which operate on sigle pair, it makes sense to create a class to contain them. In that class you can still internally use this kind of array to store 1 or 2 (or some other number of) items.
I am having trouble solving a particular problem in Java (which I did not find by search). I do not know how to create a nested lists of objects - with a different type of object/primitive type at the end. For example:
*Note: only an example. I am actually doing this below with something other than Employee, but it serves as simple example.
I have an array of an object Employee. It contains information on the Employee.
public class Employee {
int age
int salary
int yearsWorking
public Employee () {
// constructor...
}
// Accessors
}
What I need to do is organize the Employees by quantiles/percentiles. I have done so by the following:
import org.apache.commons.math.stat.descriptive.rank.Percentile;
public class EmployeeSort {
public void main(String args[]) {
Percentile p = new Percentile();
Employee[] employeeArray = new Employee[100];
// filled employeeArray
double[] ageArray = new double[100];
// filled ageArray with ages from employeeArray
int q = 25; // Percentile cutoff
for (int i = 1; i*q < 100; i++) {
// assign percentile cutoff to some array to contain the values
}
}
}
Now, the problem I have is that I need to organize the Employees first by the percentiles of age, then percentiles of yearsWorking, and finally by percentiles of salary. My Java knowledge is inadequate right now to solve this problem, but the project I was handed was in Java. I am primarily a python guy, so this problem would have been a lot easier in that language. No such luck.
Edit:
So I notice some confusion on whether I need ordering, and some people suggesting use of Comparator. I use Comparator because percentiles requires an ordered list. The problem I am having is how to store the binning of the Employee into their appropriate percentile. To clarify, I need the Employee object binned together into their appropriate percentile by age. Then, within that bin of age, I need to bin all those Employee objects within percentiles for Employee.yearsWorking. Following that, within a given percentile bin of yearsWorking which is within a given percentile bin of Employee.age, I need to create percentile bins of Employee.salary.
You should use ArrayList
in place of Arrays.
ArrayList<Employee> employeeList= new ArrayList<Employee>();
for (int i = 0, i <= employeeArray.length; i++)
employeeList.add(employeeArray[i]);
Now write down custom Comparator
public class EmployeeComparatorByAge<Employee>
{
public int compare(Object o1, Object o2)
{
if (o1 != null && o2!= null && o1 instanceof Employee && o2 instanceof Employee )
return ((Employee)o1).age - ((Employee)o2).age;
else
return -1;
}
}
Similarly you can write for other comparisions.
To sort them now, use:
Collections.sort(employeeList, new EmployeeComparatorByAge<Employee>());
This will solve your problem.
Check out java.util.Comparator<T> (the T in this case would be your Employee type)
You can create different Comparators and use Collections.sortList or Arrays.sort(...) (these methods are pseudo methods - look up the exact versions from the docs)
Instead of an array use an ArrayList to hold your Employees. You can then use Collections.sort() to sort that list. There are two versions of sort(), one of which takes a Comparator that will allow you to sort in your desired order.
You might want to read this link to understand Object Ordering in Java
The next thing that you want to do is use an ArrayList and add all your employees in this. You would then want to do something like this:
ArrayList<Employee> employeeList= new ArrayList<Employee>();
/**
* Add your employee objects to the list
*/
Collections.sort(contacts, new Comparator<Employee>() {
public int compare(Employee emp1, Employee emp2) {
int returnValue;
/**
* Your comparison logic
*/
return returnValue;
}
});
I hope this helps!
Use Arrays.sort() with different Comparator implementations as noted above. Keep in mind that this method (as well as Collections.sort()) operate on the data in place. So if you need to keep getting at different views of the data, you may want to duplicate the array and sort it different ways, and hold onto each view.
This would be more efficient (CPU-wise) than constantly re-sorting the array.
As the title suggests, I have a list consisting of pairs of integers (int ai and int bi). I want to sort this list based on only upon int a, while preserving the pairwise relationship. I was wondering if there was an efficient way to do this with some of the standard libraries Java has. Thanks in advance!
Edit:
My exact implementation is an ArrayList<ArrayList<Integer>> in which each ArrayList<Integer> has exactly two integers (ai and bi). Sorry for any confusion.
Use the Collections sort() or Arrays sort() method which takes a Comparator and use a custom comparator which only inspects the first integer in the pair.
Something like this (roughly, depending on your exact types):
Collections.sort(myList, new Comparator<IntegerPair>() {
#Override public int compare(IntegerPair x, IntegerPair y) {
return x.first - y.first;
}
});
Since the sorting algorithms are stable (per the Javadocs) your list will be sorted per your description.
Implement http://docs.oracle.com/javase/6/docs/api/java/lang/Comparable.html for your integer pairs and use sort() from http://docs.oracle.com/javase/6/docs/api/java/util/Collections.html
I would recommend to create a class that represents integer pair. This class should implement Comparable. The use sort() to sort it.
It may be a little safer to use the already-defined Integer compare:
Collections.sort(myList, new Comparator<IntegerPair>() {
#Override public int compare(IntegerPair x, IntegerPair y) {
return Integer.compare(x.first, y.first);
}
});