I am new to Java, and I am trying to implement a sort algorithm which may use the natural order or a given comparator argument.
Say I have a comparable class C with some natural order compareTo, a Comparator subclass ByAltOrder, And I have a Comparator<C> method which returns a new ByAltOrder.
public class C implements Comparable<C> {
... //fields and constructor
public int compareTo(C that) { ... } //natural order
public Comparator<C> altOrder() { //some alternative order
return new ByAltOrder();
}
public class ByAltOrder implements Comparator<C>{
public int compare(C x, C y) { ... }
}
}
I want to write a function which may use the natural order or the alternative order. I know how to write a function that uses either the natural order or the alternative order, but I do not want to write the same code twice with minor differences. Is that possible?
Say I want to write a function returning maximum of a non-empty Array. With natural order it looks like this:
public C max(C[] xs){
res = xs[0];
for (i = 1; i < xs.length; i++) {
if (xs[i].compareTo(res) > 0) {
res = points[i];
}
}
return res;
}
And with Comparator it looks like this and I can pass x.altOrder() as the second argument:
public C max(C[] xs, Comparator c){
res = xs[0];
for (i = 1; i < xs.length; i++) {
if (c.compare(xs[i], res) > 0) {
res = points[i];
}
}
return res;
}
But how I do write a function that incorporates both?
Edit: I got that there is an Arrays.sort in Java, but implementing sort or max is just a toy example for my question about passing Comparators / code reuse / java practice. Perhaps I didn't make it clear about this.
If you truly want to avoid code duplication, you should not implement that operation at all.
Comparator<C> altOrder = …;
C[] array = …;
C naturalMax = Collections.max(Arrays.asList(array));// natural order
C altMax = Collections.max(Arrays.asList(array), altOrder); // alternative order
Note that Arrays.asList does not copy but only wraps the array, so there is no performance consideration preventing to use these methods.
By the way, ByAltOrder and altOrder() should both be static, as they don’t depend on a specific instance of C.
If you want to implement these methods as an exercise, other answers already pointed to it, use delegation and Comparator.naturalOrder().
If you are not using Java 8 or newer, this builtin comparator is not available, but you could work-around it using Collections.reverseOrder(Collections.reverseOrder()) to get a comparator with the same behavior, but, of course, you should replace that with Comparator.naturalOrder() as soon as you migrate to Java 8 or newer.
Technically JB Nizet is right.
This is enough :
public C max(C[] xs){
return max(xs, Comparator.naturalOrder());
}
public C max(C[] xs, Comparator<? super C> c){
C res = xs[0];
for (int i = 1; i < xs.length; i++) {
if (c.compare(xs[i], res) > 0) {
res = points[i];
}
}
return res;
}
Now, concretely, writing these processings seem not relevant
To find the max element (in terms of Comparable/Comparator) of an array, you could just use Arrays.stream().max :
C max = Arrays.stream(xs).max(c);
or
C max = Arrays.stream(xs).max(new ByAltOrder());
By handling the null case if the array is empty (thanks dear Holger), your methods could be as simple as :
public C findMax(C[] xs){
return findMax(xs, Comparator.naturalOrder());
}
public C findMax(C[] xs, Comparator<? super C> c){
return Arrays.stream(xs).max(c).orElse(null);
}
You could do something like this:
public <C extends Comparable<? super C>> C max(C[] xs){
return max(xs, Comparator.naturalOrder());
}
public <C> C max(C[] xs, Comparator<C> c){
C res = xs[0];
for (C x: xs) {
if (c.compare(x, res) > 0) {
res = x;
}
}
return res;
}
Related
With the use of below code, I am finding out which datacenter I am in and it is working fine..
public enum DatacenterEnum {
DEV, DC1, DC2, DC3;
private static DatacenterEnum compareLocation() {
String ourhost = getHostName();
for (DatacenterEnum dc : values()) {
String namepart = "." + dc.name().toLowerCase() + ".";
if (ourhost.indexOf(namepart) >= 0) {
return dc;
}
}
return null;// I don't want to do this now.
}
}
But it might be possible that it is not able to find any datacenter, so currently I am returning null.
Is there any direct way or a single line command by which I can return randomly either DC1 or DC2 or DC3 in the ENUM instead of returning null?
I know one way is to make a list of string and then randomnly select any integer between 0 to 2 inclusive and then find the string. But it is too much code, actually it's not but just trying to see is there any other way we can do this?
Any simple and direct way which I can use in the ENUM directly?
Here's the one line:
return DataCenterEnum.values()[new Random().nextInt(3) + 1)];
For those who require tighter control on their code, here's a safer version, which does not depend on the order of the enum instances:
return new DataCenterEnum[]{DC1, DC2, DC3}[new Random().nextInt(3)];
Here is a generic solution that will work for any enumeration.
Convenience method for single exclusion:
public static <E extends Enum<E>> E getRandom(Class<E> aEnum, E exclude) {
return getRandom(aEnum, Collections.singletonList(exclude));
}
Generic method that works with one or more exclusions:
public static <E extends Enum<E>> E getRandom(Class<E> aEnum, List<E> exclude){
//Convert set of enums into a list
List<E> enums = new ArrayList<E>(EnumSet.allOf(aEnum));
//Remove items from the list that you want to exclude
enums.removeAll(exclude);
int size = enums.size();
if(size != 0){
//Get random enum
int randomIndex = new Random().nextInt(size);
return enums.get(randomIndex);
} else {
throw new IllegalArgumentException("Empty Enumeration after excludes");
}
}
For your example you could call
EnumUtil.getRandom(DatacenterEnum.class, DatacenterEnum.DEV);
You could use the values() method, which returns an array. Then just use Math.random() to return a random instance.
Here is an example:
public static void main (String[] args) {
String[] arr = {"DEV","DC1","DC2","DC3"}; //returned by Enum.values(), you get the idea
String randElement = arr[(int) ((Math.random() * 3) +1)];
System.out.println(randElement);
}
Basically it boils down to generating a random number between 1 and n :)
I am trying to sort an arraylist by string length, i know of implementing Comparator, but i was wondering if this could be done within my function, without adding any extra classes or methods? Ideally I want to output them shortest to longest, but that I can do!
Here is a snippet of the method i would like to implement the comparator with.
public static void sCompare(BufferedReader r, PrintWriter w) throws IOException {
ArrayList<String> s= new ArrayList<String>();
String line;
int n = 0;
while ((line = r.readLine()) != null) {
s.add(line);
n++;
}
//Collections.sort(s);
Iterator<String> i = s.iterator();
while (i.hasNext()) {
w.println(i.next());
}
}
Thanks in advance for any input!
I don't see anything wrong with implementing the Comparator interface.
If your only concern is doing everything in the function, you could use an anonymous implementation. Something along the lines of :
Collections.sort(s, new Comparator<String>() {
#Override
public int compare(String o1, String o2) {
return o1.length() - o2.length();
}
});
(that would replace you current line //Collections.sort(s);)
PS : you never use the value of n.
PPS: You may have to invert o1 and o2 depending of the order you want in the return statement.
Another example of implementing an interface with an anonymous class
I'm going to assume by "class" you mean "top level class", thus allowing the use of an anonymous class:
Collections.sort(s, new Comparator<String>() {
public int compare(String a, String b) {
// java 1.7:
return Integer.compare(a.length(), b.length());
// java 1.6
return a.length() - b.length();
}
});
I have some code that sorts a stack using only another stack (it's an interview question). The code itself seems to work. I'd like to implement it using generics, so that any kind of stack is sortable, under the following conditions:
The sort method remains static (I'd like to avoid parameterizing the entire class)
I can use native comparator operators (like <) - I guess the parameterized type needs to implement Comparable.
Is this possible?
Here's the code.
import java.util.Stack;
public class StackSort {
static void sort(Stack<Integer> stack) {
Stack<Integer> tmp = new Stack<Integer>();
for (;;) {
int nswaps = 0;
while (!stack.isEmpty()) {
Integer curr = stack.pop();
if (!stack.isEmpty() && curr < stack.peek()) {
Integer next = stack.pop();
tmp.push(next);
tmp.push(curr);
++nswaps;
} else {
tmp.push(curr);
}
}
while (!tmp.isEmpty()) {
stack.push(tmp.pop());
}
if (nswaps == 0) {
break;
}
}
}
public static void main(String[] args) {
Stack<Integer> stack = new Stack<Integer>();
stack.push(6);
stack.push(4);
stack.push(11);
stack.push(8);
stack.push(7);
stack.push(3);
stack.push(5);
System.out.println(stack);
StackSort.sort(stack);
System.out.println(stack);
}
}
You are on the right way by mentioning Comparable.
Your method can be
static <T extends Comparable<T>>void sort(Stack<T> stack) {
And the comparison curr < stack.peek() replace by
curr.compareTo(stack.peek()) < 0
Using comparator operators on Objects (wrapped primitives or not) is not possible in Java. C++ support such a possibility. However, you can create a workaround by forceing the parameter type to implement Comparable. Your signature should look like this:
public <T extends Comparable<? super T>> static void sort(Stack<T> stack)
And to compare, use compareTo instead of native operators (which is not possible in Java):
obj1.compareTo(obj2)
For my data structures class our homework is to create a generic heap ADT. In the siftUp() method I need to do comparison and if the parent is smaller I need to do a swap. The problem I am having is that the comparison operators are not valid on generic types. I believe I need to use the Comparable interface but from what I read it’s not a good idea to use with Arrays. I have also search this site and I have found good information that relates to this post none of them helped me find the solution
I removed some of the code that wasn’t relevant
Thanks
public class HeapQueue<E> implements Cloneable {
private int highest;
private Integer manyItems;
private E[] data;
public HeapQueue(int a_highest) {
data = (E[]) new Object[10];
highest = a_highest;
}
public void add(E item, int priority) {
// check to see is priority value is within range
if(priority < 0 || priority > highest) {
throw new IllegalArgumentException
("Priority value is out of range: " + priority);
}
// increase the heaps capacity if array is out of space
if(manyItems == data.length)
ensureCapacity();
manyItems++;
data[manyItems - 1] = item;
siftUp(manyItems - 1);
}
private void siftUp(int nodeIndex) {
int parentIndex;
E tmp;
if (nodeIndex != 0) {
parentIndex = parent(nodeIndex);
if (data[parentIndex] < data[nodeIndex]) { <-- problem ****
tmp = data[parentIndex];
data[parentIndex] = data[nodeIndex];
data[nodeIndex] = tmp;
siftUp(parentIndex);
}
}
}
private int parent(int nodeIndex) {
return (nodeIndex - 1) / 2;
}
}
Technically you're using the comparable interface on on item, not an array. One item in the array specifically. I think the best solution here is to accept, in the constructor, a Comparator that the user can pass to compare his generic objects.
Comparator<E> comparator;
public HeapQueue(int a_highest, Comparator<E> compare)
{
this.comparator = compare;
Then, you would store that comparator in a member function and use
if (comparator.compare(data[parentIndex],data[nodeIndex]) < 0)
In place of the less than operator.
If I am reading this right, E simply needs to extend Comparable and then your problem line becomes...
if (data[parentIndex].compareTo(ata[nodeIndex]) < 0)
This is not breaking any bet-practice rules that I know of.
In this I am trying to sort out the intV and stringV using this getSmallestValue method. Tried different ideas but does not seems to be working. Anyone have any bright ideas how to implement this getSmallestValue method?
public class test {
public static Comparable getSmallestValue(Vector<Comparable> a) {
Comparator com = Collections.reverseOrder();
Collections.sort(a, com);
return (Comparable) a;
}
public static void main(String[] args) {
Vector<Comparable> intV = new Vector<Comparable>();
intV.add(new Integer(-1));
intV.add(new Integer(56));
intV.add(new Integer(-100));
int smallestInt = (Integer) getSmallestValue(intV);
System.out.println(smallestInt);
Vector<Comparable> stringV = new Vector<Comparable>();
stringV.add("testing");
stringV.add("Pti");
stringV.add("semesterGoes");
String smallestString = (String) getSmallestValue(stringV);
System.out.println(smallestString);
}
}
Welcome to StackOverflow.
Your basic problem is that you have tried to turn a Vector into an Integer which you cannot do.
What is likely to be more useful is to use the first element of the vector.
I would suggest you
use List instead of Vector.
I wouldn't use manual wrapping
define the getSmallestValue using generics to avoid confusion.
Here are two ways you could implement this method.
public static <N extends Comparable<N>> N getSmallestValue(List<N> a) {
Collections.sort(a);
return a.get(0);
}
public static <N extends Comparable<N>> N getSmallestValue2(List<N> a) {
return Collections.min(a);
}
List<Integer> ints = Arrays.asList(-1, 56, -100);
int min = getSmallestValue(ints);
// or
int min = Collections.min(ints);
Use Collections.min().You can check out the source if you you want to know how it's implemented.
Vector<Integer> v=new Vector<Integer>();
v.add(22);v.add(33);
System.out.println(Collections.min(v));