junit testing equality of an Iterable - java

I am trying to write unit tests for a BinarySearchTree class
The keys() return an Iterable.It uses another class called Queue in which the keys are enqueued and returned..
The Queue (third party class) however doesn't have any equals() defined.
public class BinarySearchTree<Key extends Comparable<Key>,Value> {
Node root ;
private class Node{
private Key key;
private Value val;
private Node left;
private Node right;
private int N;
public Node(Key k, Value v,int N) {
super();
this.key = k;
this.val = v;
this.N = N;
}
}
public Iterable<Key> keys(){
Queue<Key> q = new Queue<Key>();
inOrder(root,q);
return q;
}
private void inOrder(Node x,Queue q){
if(x == null)return;
inOrder(x.left,q);
q.enqueue(x.key);
inOrder(x.right,q);
}
...
}
trying to write unit test
#Test
public void testKeys(){
MyBST<String, Integer> st = new MyBST<String, Integer>();
st.put("S",7);
st.put("E",2);
st.put("X",8);
st.put("A",3);
st.put("R",4);
st.put("C",1);
st.put("H",5);
st.put("M",6);
Queue<String> q = new Queue<String>();
q.enqueue("A");
q.enqueue("C");
q.enqueue("E");
q.enqueue("H");
q.enqueue("M");
q.enqueue("R");
q.enqueue("S");
q.enqueue("X");
Iterable<String> actual = st.keys();
assertEquals(q,actual);
}
This fails
java.lang.AssertionError: expected: std.Queue<A C E H M R S X > but was: std.Queue<A C E H M R S X >
at org.junit.Assert.fail(Assert.java:93)
at org.junit.Assert.failNotEquals(Assert.java:647)
at org.junit.Assert.assertEquals(Assert.java:128)
at org.junit.Assert.assertEquals(Assert.java:147)
at week4.MyBSTTests.testKeys(BSTTests.java:304)
Do I have to implement an equals() in the third party class or is there any other way to do this to check equality? All I could think of was running a loop dequeueing from queue q and comparing it with what the iterator returned.I am not sure if there is a better way.. Please advise..
Iterable<String> actual = st.keys();
Iterator<String> actualit = actual.iterator();
while(actualit.hasNext()){
String actualkey = actualit.next();
String exp = q.dequeue();
assertEquals(actualkey,exp);
}

Use Hamcrest's Matchers.contains (described here). For example:
assertThat(queue1.keys(), Matchers.contains("A", "C", "E", "H", "M", "R", "S", "X"));
This will check the elements that the Iterable returns without needing equality implemented on your queue class.

you can use the utility class java.util.Arrays.
From what I remember the Queue interface has a toArray method. So it would be something like this:
assertTrue(Arrays.equals(queue1.toArray(),queue2.toArray()));
As it is a third party library, you could use apache commons:
Object[] o = IteratorUtils.toArray(queue1.iterator());
Object[] o2 = IteratorUtils.toArray(queue1.iterator());
assertTrue(Arrays.equals(o,o2));

This is how I did this.
I converted the Iterable to the ArrayList. Then I made another arraylist of expected key values. That way I am able to check if two arrayLists are equal using assertEquals(arrayList1, arrayList2).
Here is the code I wrote for testing my preOrder traversal method.
import static org.junit.Assert.*;
import java.util.ArrayList;
import org.junit.Test;
public class BSTTest
{
BST<Integer, String> binaryTree = new BST<Integer, String>();
#Test
public void preOrdertest()
{
binaryTree.put(87, "Orange");
binaryTree.put(77, "Black");
binaryTree.put(81, "Green");
binaryTree.put(89, "Blue");
binaryTree.put(4, "Yellow");
binaryTree.put(26, "white");
binaryTree.put(23, "Purple");
binaryTree.put(27, "Violet");
binaryTree.put(57, "red");
binaryTree.put(1, "crimson");
ArrayList<Integer> testList = new ArrayList<>();
testList.add(87);
testList.add(77);
testList.add(4);
testList.add(1);
testList.add(26);
testList.add(23);
testList.add(27);
testList.add(57);
testList.add(81);
testList.add(89);
Iterable<Integer> actual = binaryTree.preOrder();
ArrayList<Integer> actualList = new ArrayList<>();
if (actual != null)
{
for (Integer e : actual)
actualList.add(e);
}
assertEquals(testList, actualList);
}
}

Related

Sorting a list of Generics in Java?

I'm trying to implement a sorting for Generics in Java.
Here is the abstract class Function (T is my "key" in order to sort):
public abstract class Function<T extends Comparable<T>, S> {
abstract public T compute(S o);
}
Here is class Applier, whose method "apply" sorts the list according on the result of "compute":
import java.util.ArrayList;
import java.util.Iterator;
public class Applier<T extends Comparable<T>, S> {
ArrayList<S> apply(ArrayList<S> input, Function<T, S> function) {
ArrayList<T> output = new ArrayList<>();
for(Iterator<S> it = input.iterator(); it.hasNext(); ){
output.add(function.compute(it.next()));
}
T tmpTi, tmpTj;
S tmpSi, tmpSj;
for(int i=0; i<input.size(); i++) {
for(int j=i+1; j<input.size(); j++) {
if(output.get(i).compareTo(output.get(j))>0) {
tmpTi = output.get(i);
tmpTj = output.get(j);
output.remove(j);
output.remove(i);
output.add(i, tmpTi);
output.add(i, tmpTj);
tmpSi = input.get(i);
tmpSj = input.get(j);
input.remove(j);
input.remove(i);
input.add(i, tmpSj);
input.add(j, tmpSi);
}
}
}
return input;
}
}
My question is: is there a smarter way to do this sorting, maybe not with a bubblesort?
Here is also the main class:
public static void main(String[] args) {
Applier a = new Applier<>();
StringLength strlen = new StringLength();
ArrayList<String> array = new ArrayList<>();
array.add("Hola");
array.add("Man");
array.add("randomstufff");
array.add("Zerrone");
array.add("Info3a");
System.out.println("Order by length");
System.out.print("before: ");
System.out.println(array);
a.apply(array, strlen); //works on original object
System.out.print("After: ");
System.out.println(array);
Basically you want to sort an array based on some other array. You will be able to use Collections.sort if you introduce a wrapper object that contains both the values and the function results, and sort that one.
Here's a solution using Java 8 streaming API:
public class Applier<T extends Comparable<T>, S> {
static class Wrapper<T extends Comparable<T>,S> implements Comparable<Wrapper<T,S>> {
T key;
S value;
Wrapper(S s, Function<T, S> function) {
this.key = function.compute(s);
this.value = s;
}
public int compareTo(Wrapper<T,S> that) {
return key.compareTo(that.key);
}
}
ArrayList<S> apply(ArrayList<S> input, Function<T, S> function) {
S[] sorted = (S[]) IntStream.range(0, input.size())
.mapToObj(i -> new Wrapper<T,S>(input.get(i), function))
.sorted()
.map(b -> b.value).toArray();
input.clear();
input.addAll(Arrays.asList(sorted));
return input;
}
}
Note that there's an error in the way you swap elements in your Bubble Sort: When re-inserting the elements into output, you misplaced i and j. Also, instead of removing and re-inserting the elements, just use set(index, element) to overwrite the previous entry.
Also, instead of using two lists and keeping those lists in synch, better just use a Map.
public static class Applier<T extends Comparable<T>, S> {
ArrayList<S> apply(ArrayList<S> input, Function<T, S> function) {
Map<S, T> compareBy = new HashMap<>();
for (S s : input) {
compareBy.put(s, function.compute(s));
}
for(int i=0; i<input.size(); i++) {
for(int j=i+1; j<input.size(); j++) {
if (compareBy.get(input.get(i)).compareTo(compareBy.get(input.get(j))) > 0) {
S tmpS = input.get(j);
input.set(j, input.get(i));
input.set(i, tmpS);
}
}
}
return input;
}
}
And of course, sorting is already implemented in Java. So other than for learning how to code, you should always use the builtin functions. In Java 8, it's just a single line:
Collections.sort(array, Comparator.comparing(String::length));
Note, however, that Comparator.comparing will call the comparator function for each pairwise comparison (i.e. on the order of 2nlogn times for a decent sorting algorithm). If that function is computationally very expensive, you might want to cache it yourself, using a Map.
Map<String, Integer> compareBy = array.stream().collect(Collectors.toMap(s -> s, s -> s.length()));
Collections.sort(array, Comparator.comparing((String s) -> compareBy.get(s)));

Implementing the difference between two sorted Lists of comparable items in java

Implement a method in Java to compute the difference () between L1 and L2. L1 \ L2 = { x | x ∈ L1 and x ∉ L2 }.
This is my implementation so far:
public static <AnyType extends Comparable<? super AnyType>>
void difference(List<AnyType> L1, List<AnyType> L2, List<AnyType> Difference){
if(L1 == null){
Difference = null;
}
else if(L2 == null){
Difference = L1;
}
else if(L1.size()==0 || L2.size()==0){
Difference = L1;
}
else{
Iterator<AnyType> it1 =L1.listIterator();
Iterator<AnyType> it2 =L2.listIterator();
AnyType a = it1.next();
AnyType b = it2.next();
while(true){
if(a.compareTo(b)>0){
if(it2.hasNext()){
b = it2.next();
}
else{
Difference.add(a);
while(it1.hasNext()){
a = it1.next();
Difference.add(a);
}
break;
}
}
else if(a.compareTo(b)<0){
Difference.add(a);
if(it1.hasNext()){
a = it1.next();
}
else break;
}
else {
if(it1.hasNext()){
a =it1.next();
}
else break;
}
}
}
System.out.println("Difference Set: " + Arrays.toString(Difference.toArray()));
}
This is not the trivial solution which would be to implement two nested for loops and save to the result list the right elements, that solution is O(n^2).
Another possible solution is to search the second list using binary search, that algorithm would be O(n*Log(n))
The solution here implemented, attempts to go through the lists only once and finish in the first pass, this will be O(n) linear.
The algorithm works fine, however it feels like it could use some optimization still, it feels like spaghetti code lol. Any pointers that could help me to optimize this?
The first thing I see is that you perform a.compareTo(b) twice for each iteration through the loop. Instead, use compareTo once and store the result for use in both if statements.
Secondly, use for a consistent naming scheme like objA and iterA instead of a and it1. It'll just make it a little easier to follow. For that matter, don't be afraid of longer names. listA than l1 might be a couple extra characters, but it's worth it for readability. (Also, don't forget that you shouldn't start a variable with a capital letter, so L1 is doubly-uncool.)
Finally, comment comment comment. I know this algorithm, so I can follow the code pretty well, but it's far from self-documenting. Comment each if statement and loop to document what the condition is, why you're checking, and what you're doing with the results.
EDIT: I thought about this some more and as another alternative approach that is probably more optimal than my initial post you could take advantage of the hashCode method and HashMap implementation as follows:
public static <AnyType extends Comparable<? super AnyType>>
void difference(List<AnyType> L1, List<AnyType> L2, List<AnyType> Difference){
HashMap<AnyType,Boolean> map = new HashMap<AnyType,Boolean>();
for(AnyType item: L1){
map.put(item, true);
}
for(AnyType item: L2){
map.put(item, false);
}
Difference.clear();
for(AnyType item: map.keySet()){
if(map.get(item)){
Difference.add(item);
}
}
}
END EDIT
Not sure how optimized this is, but another approach would be to take advantage of the collections framework to do the heavy lifting for you if you create a wrapper class to define the equals method. I left in some System.out.println calls in case anyone wants to trace the logic.
import java.util.ArrayList;
import java.util.List;
public class ListDiff {
public static void main(String[] args) {
List<String> L1 = new ArrayList<String>();
L1.add("item1");
L1.add("item2");
L1.add("item3");
L1.add("item3"); //duplicate item intentional for demonstration
L1.add("item5");
List<String> L2 = new ArrayList<String>();
L2.add("item1");
L2.add("item3");
L2.add("item4");
List<String> strDiff = new ArrayList<String>();
difference(L1,L2,strDiff);
System.out.println("strDiff is: "+strDiff);
List<Integer> list3 = new ArrayList<Integer>();
list3.add(1);
list3.add(2);
list3.add(3);
list3.add(3); //duplicate item intentional for demonstration
list3.add(5);
List<Integer> list4 = new ArrayList<Integer>();
list4.add(1);
list4.add(3);
list4.add(4);
List<Integer> intDiff = new ArrayList<Integer>();
difference(list3,list4,intDiff);
System.out.println("intDiff is: "+intDiff);
}
public static <AnyType extends Comparable<? super AnyType>>
void difference(List<AnyType> L1, List<AnyType> L2, List<AnyType> Difference){
List<EqualityWrapper<AnyType>> list1 = new ArrayList<EqualityWrapper<AnyType>>();
for(AnyType item: L1){
EqualityWrapper<AnyType> wrappedItem = new EqualityWrapper<AnyType>(item);
list1.add(wrappedItem);
}
List<EqualityWrapper<AnyType>> list2 = new ArrayList<EqualityWrapper<AnyType>>();
for(AnyType item: L2){
EqualityWrapper<AnyType> wrappedItem = new EqualityWrapper<AnyType>(item);
list2.add(wrappedItem);
}
// System.out.println("list1: "+list1);
List<EqualityWrapper<AnyType>> diff = new ArrayList<EqualityWrapper<AnyType>>(list1);
// System.out.println("diff: "+diff);
// System.out.println("list2: "+list2);
diff.removeAll(list2);
// System.out.println("diff: "+diff);
Difference.clear();
for(EqualityWrapper<AnyType> item: diff){
AnyType unwrapped = item.getOrig();
Difference.add(unwrapped);
}
}
public static class EqualityWrapper<AnyType extends Comparable<? super AnyType>> {
private AnyType orig;
public EqualityWrapper(AnyType comparable){
orig = comparable;
}
#Override
public boolean equals(Object other){
if(other instanceof EqualityWrapper){
EqualityWrapper<AnyType> otherEqualityWrapper = (EqualityWrapper<AnyType>)other;
// System.out.println("Comparing "+orig+" with "+otherEqualityWrapper.getOrig());
return orig.compareTo(otherEqualityWrapper.getOrig()) == 0;
}
// System.out.println("returning false");
return false;
}
public AnyType getOrig(){
return orig;
}
#Override
public String toString(){
return orig.toString();
}
}
}
OUTPUT:
strDiff is: [item2, item5]
intDiff is: [2, 5]

Combine two sorted iterators in O(1) time

I was asked the following question in an interview:
Combine two iterators over their sorted contents such that the
resulting iterator should iterate over the combination of these 2
iterators in sorted order in O(1) time (these iterators iterate over a
String).
I wrote the below code but I'm sure it doesn't perform in O(1) time. What advice do you have for matching the constraints set by the interview question?
import java.util.Iterator;
import java.util.Set;
import java.util.TreeSet;
public class iteratorCombine {
// assumption1: elements are hardcoded
// assumption2: both iterators have equal number of elements
public static void main(String[] args) {
iteratorCombine testObj = new iteratorCombine();
Set<String> firstSet = new TreeSet<String>();
Set<String> secondSet = new TreeSet<String>();
Set<String> combinedSet;
firstSet = testObj.storeElements1(firstSet);
secondSet = testObj.storeElements2(secondSet);
Iterator<String> it1 = firstSet.iterator();
Iterator<String> it2 = secondSet.iterator();
combinedSet = testObj.combine(it1, it2);
// output
Iterator<String> itComb = combinedSet.iterator();
while(itComb.hasNext()){
System.out.println(itComb.next());
}
}
public Set<String> storeElements1(Set<String> firstSet){
firstSet.add("first3");
firstSet.add("first1");
firstSet.add("first2");
return firstSet;
}
public Set<String> storeElements2(Set<String> secondSet){
secondSet.add("second3");
secondSet.add("second1");
secondSet.add("second2");
return secondSet;
}
public Set<String> combine(Iterator<String> it1, Iterator<String>it2){
String firstEle, secondEle;
Set<String> combinedSet = new TreeSet<String>();
while (it1.hasNext() && it2.hasNext()) {
firstEle = it1.next();
secondEle = it2.next();
combinedSet.add(firstEle+secondEle);
}
return combinedSet;
}
}
I believe that you can't do it if you don't extend iterator and support a peek function. Such an iterator is not that hard. Here is a way for doing it.
static class PeekingIterator<T> implements Iterator<T> {
private final Iterator<T> iterator;
private T temp;
public PeekingIterator(Iterator<T> iterator) {
this.iterator = iterator;
}
public T peek() {
//if there is no peek, advance the iterator and store its value, return the peek otherwise
if(temp==null){
temp = this.iterator.next();
}
return temp;
}
#Override
public T next() {
//if we already have a peek,return it and nullify it, otherwise do normal next()
if(temp!=null){
T t = temp;
temp = null;
return t;
}else{
return this.iterator.next();
}
}
#Override
public boolean hasNext() {
return this.iterator.hasNext() || temp!=null;
}
}
Once you can peek, the rest is easy, you can build SortedIterator using two peeking iterators, peek both iterators and advance the iterator that has the smaller element.
static class SortedIterator<T extends Comparable<T>> implements Iterator<T>{
private final PeekingIterator<T> peekingIterator1;
private final PeekingIterator<T> peekingIterator2;
SortedIterator(Iterator<T> source1, Iterator<T> source2){
peekingIterator1 = new PeekingIterator<>(source1);
peekingIterator2 = new PeekingIterator<>(source2);
}
#Override
public boolean hasNext() {
return peekingIterator1.hasNext() || peekingIterator2.hasNext();
}
#Override
public T next() {
if(!peekingIterator1.hasNext()){
return peekingIterator2.next();
}
if(!peekingIterator2.hasNext()){
return peekingIterator1.next();
}
T peek1 = peekingIterator1.peek();
T peek2 = peekingIterator2.peek();
if(peek1.compareTo(peek2)<0){
return peekingIterator1.next();
}
return peekingIterator2.next();
}
}
The analysis are obvious here, SortedIterator.next and SortedIterator.hasNext run in constant time.
I had a similar use case but instead of only 2 iterators, I had to merge a dynamic number of iterators. The number of iterators can be more than 2. e.g., 3 iterators, 4 iterators, or more.
I used the same solution as Sleiman Jneidi suggested. I modified the SortedIterator to support multiple iterators and also support sorting in ascending or descending order based on need.
For the PeekingIterator, I used Apache commons collection's Peeking iterator.
Here is my sorted iterator if someone may need to merge multiple sorted iterators, they can refer to this:
import java.util.Comparator;
import java.util.Iterator;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;
import org.apache.commons.collections4.iterators.PeekingIterator;
/**
* This class is special implementation of Iterator.
* It lets multiple sorted iterators to be merged to a single sorted iterator.
* It will use given comparator to compare values from multiple iterators.
*
*/
public class SortedMergedIterator<T> implements Iterator<T> {
/**
* Comparator that will be used to compare values from across the iterators.
*/
private final Comparator<? super T> comparator;
/**
* List of sorted iterators which are required to be merged to a single sorted iterator.
*/
private final List<PeekingIterator<T>> peekingIterators;
/**
* By default the sort order will be considered as ascending order.
*
* It this flag is set to true, the elements will be sorted in descending order.
* In this case, it is pre-requisite that all the iterators being passed should be sorted in ascending order.
*/
private final boolean sortOrderDescending;
public SortedMergedIterator(final Comparator<? super T> comparator, final List<Iterator<T>> iterators) {
this(comparator, iterators, false);
}
public SortedMergedIterator(final Comparator<? super T> comparator, final List<Iterator<T>> iterators, final boolean sortOrderDescending) {
this.comparator = comparator;
this.peekingIterators = iterators.stream().map(iterator -> new PeekingIterator<>(iterator)).collect(Collectors.toList());
this.sortOrderDescending = sortOrderDescending;
}
#Override
public boolean hasNext() {
// If at least one of the child iterator has next element.
return this.peekingIterators.stream().anyMatch(Iterator::hasNext);
}
#Override
public T next() {
// Peek next value from all the iterators.
final List<T> peekedValues = this.peekingIterators.stream().map(PeekingIterator::peek).collect(Collectors.toList());
// Find the minimum value from all the peeked values.
final T minElement = peekedValues
.stream()
.filter(Objects::nonNull)
.min(this.sortOrderDescending ? this.comparator.reversed() : this.comparator)
.orElse(null);
// Return the next element from an iterator for which minimum value is found.
return this.peekingIterators.get(peekedValues.indexOf(minElement)).next();
}
}
Example of using this iterator:
public static void main(String[] args) {
// Example of ascending order sorted iterators.
final List<Integer> list1 = Lists.newArrayList(4,7,11,12,16);
final List<Integer> list2 = Lists.newArrayList(1,3,5,10,15);
final List<Integer> list3 = Lists.newArrayList(6,8,13,18,20);
final List<Integer> list4 = Lists.newArrayList(2,9,14,17,19);
final SortedMergedIterator<Integer> sortedIterator =
new SortedMergedIterator<>(Comparator.comparingInt(a -> a), Arrays.asList(list1.iterator(), list2.iterator(), list3.iterator(), list4.iterator()));
while (sortedIterator.hasNext()) {
System.out.println(sortedIterator.next());
}
System.out.println();
// Example of descending order sorted iterators.
final List<Integer> list5 = Lists.newArrayList(16,12,11,7,4);
final List<Integer> list6 = Lists.newArrayList(15,10,5,3,1);
final List<Integer> list7 = Lists.newArrayList(20,18,13,8,6);
final List<Integer> list8 = Lists.newArrayList(19,17,14,9,2);
final SortedMergedIterator<Integer> descSortedIterator =
new SortedMergedIterator<>(Comparator.comparingInt(a -> a), Arrays.asList(list5.iterator(), list6.iterator(), list7.iterator(), list8.iterator()), true);
while (descSortedIterator.hasNext()) {
System.out.println(descSortedIterator.next());
}
}

Java - Sorting Grouped by Ties

I'm writing a Java program in which I want to sort a set of items and get the N-highest elements of the set. The thing is, though, that I want the elements to be returned grouped by their rank -- so if I want the 3 highest elements, but there is a tie between two elements for third place, then the third result is a collection that contains the two tied elements.
I know I could write this myself, but I'm wondering if it's already been implemented somewhere else. Does anybody know of anything like this?
Sounds like the Google Collection's MultiMap might be what you're after.
Use the "rank" as your key when inserting your elements. Then sort the keys.
This is what I ended up going with:
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import com.google.common.collect.Ordering;
public final class Sorting {
private Sorting() {}
public static <T extends Comparable<? super T>> List<List<T>> rank(
Iterable<T> iterable, int nRanks) {
if (nRanks < 0) {
throw new IllegalArgumentException(Integer.toString(nRanks));
}
if (nRanks == 0) {
return new ArrayList<List<T>>();
}
Iterator<T> iter = Ordering.natural().sortedCopy(iterable).iterator();
List<List<T>> ret = new ArrayList<List<T>>();
if (iter.hasNext()) {
T prev = iter.next();
List<T> group = new ArrayList<T>();
group.add(prev);
ret.add(group);
int rank = 1;
while (iter.hasNext()) {
T next = iter.next();
if (prev.compareTo(next) > 0) {
rank++;
if (rank > nRanks) {
break;
}
group = new ArrayList<T>();
ret.add(group);
}
group.add(next);
prev = next;
}
}
return ret;
}
}

Comparator interface

ok I was going to edit my previous question but i wasnt sure if it was the right way to do it so i'll just give another question about Comparator, now i want to be able to sort with different ways. I have a bank checks and i want to sort with checkNumber then checkAmount
i managed to do it with checkNumber but couldnt figure out how with checkAmount
here is how i did it for checkNumber:
import java.util.Comparator;
public class Check implements Comparator {
private int checkNumber;
private String description;
private double checkAmount;
public Check() {
}
public Check(int newCheckNumber, double newAmountNumber) {
setCheckNumber(newCheckNumber);
setAmountNumber(newAmountNumber);
}
public String toString() {
return checkNumber + "\t\t" + checkAmount;
}
public void setCheckNumber(int checkNumber) {
this.checkNumber = checkNumber;
}
public int getCheckNumber() {
return checkNumber;
}
public void setAmountNumber(double amountNumber) {
this.checkAmount = amountNumber;
}
public double getAmountNumber() {
return checkAmount;
}
#Override
public int compare(Object obj1, Object obj2) {
int value1 = ((Check) obj1).getCheckNumber();
int value2 = ((Check) obj2).getCheckNumber();
int result = 0;
if (value1 > value2){
result = 1;
}
else if(value1 < value2){
result = -1;
}
return result;
}
}
import java.util.ArrayList;
import java.util.Collections;
import test.CheckValue;
public class TestCheck {
public static void main(String[] args) {
ArrayList List = new ArrayList();
List.add(new Check(445, 55.0));
List.add(new Check(101,43.12));
List.add(new Check(110,101.0));
List.add(new Check(553,300.21));
List.add(new Check(123,32.1));
Collections.sort(List, new Check());
System.out.println("Check Number - Check Amount");
for (int i = 0; i < List.size(); i++){
System.out.println(List.get(i));
}
}
}
thank you very much in advance and please tell me if im submiting things in the wrong way.
What you really want to do is define a separate class to act as the Comparator object - don't make your actual Check class the comparator, but instead have 3 classes:
the Check class itself
a CheckAmountComparator class (or something similar) that implements Comparator<Check>
a CheckNumberComparator class (or something similar) that implements Comparator<Check>
Then when you want to sort one way or another, you simply pass an instance of the Comparator-implementing class corresponding to the type of sorting you want to do. For instance, to sort by amount, it'd then become...
Collections.sort(yourListVariable, new CheckAmountComparator());
Also - I'd highly suggest naming your variable something other than List, since List is used as a type name in Java.
You should make Check implements Comparable<Check>, but not itself implements Comparator.
A Comparable type defines the natural ordering for the type, and a Comparator for a type is usually not the type itself, and defines their own custom ordering of that type.
Related questions
When to use Comparable vs Comparator
Java: What is the difference between implementing Comparable and Comparator?
Can I use a Comparator without implementing Comparable?
Also, you shouldn't use raw type. You need to use parameterized generic types, Comparable<Check>, Comparator<Check>, List<Check>, etc.
Related questions
What is a raw type and why shouldn’t we use it?
A String example
Let's take a look at what String has:
public final class String implements Comparable<String>
String defines its natural ordering as case-sensitive
It has a field
public static final Comparator<String> CASE_INSENSITIVE_ORDER
Here we have a case-insensitive custom Comparator<String>
An example of using this is the following:
List<String> list = new ArrayList<String>(
Arrays.asList("A", "B", "C", "aa", "bb", "cc")
);
Collections.sort(list);
System.out.println(list);
// prints "[A, B, C, aa, bb, cc]"
Collections.sort(list, String.CASE_INSENSITIVE_ORDER);
System.out.println(list);
// prints "[A, aa, B, bb, C, cc]"
Here's an example of sorting List<String> using both its natural ordering and your own custom Comparator<String>. Note that we've defined our own Comparator<String> without even changing the final class String itself.
List<String> list = new ArrayList<String>(
Arrays.asList("1", "000000", "22", "100")
);
Collections.sort(list);
System.out.println(list);
// prints "[000000, 1, 100, 22]" natural lexicographical ordering
Comparator<String> lengthComparator = new Comparator<String>() {
#Override public int compare(String s1, String s2) {
return Integer.valueOf(s1.length())
.compareTo(s2.length());
}
};
Collections.sort(list, lengthComparator);
System.out.println(list);
// prints "[1, 22, 100, 000000]" ordered by length
Comparator<String> integerParseComparator = new Comparator<String>() {
#Override public int compare(String s1, String s2) {
return Integer.valueOf(Integer.parseInt(s1))
.compareTo(Integer.parseInt(s2));
}
};
Collections.sort(list, integerParseComparator);
System.out.println(list);
// prints "[000000, 1, 22, 100]" ordered by their values as integers
Conclusion
You can follow the example set by String, and do something like this:
public class Check implements Comparable<Check> {
public static final Comparator<Check> NUMBER_ORDER = ...
public static final Comparator<Check> AMOUNT_ORDER = ...
public static final Comparator<Check> SOMETHING_ELSE_ORDER = ...
}
Then you can sort a List<Check> as follows:
List<Check> checks = ...;
Collections.sort(checks, Check.AMOUNT_ORDER);

Categories

Resources