Using a comparator in Java - java

I am Having a tuple <Rank[0] , Rank[1]> and wanted to sort this in increasing order Rank[0] can be considered as first digit and Rank[2] as a second digit.
Here is my function:
Arrays.sort(S,new Comparator<Tuples>() {
public int compare(Tuples a, Tuples b) {
// TODO Auto-generated method stub
return (a.Rank[0]==b.Rank[0]) ? ((a.Rank[1]<b.Rank[1]) ? 1:0) :((a.Rank[0]<b.Rank[0])? 1:0);
}
});
The above thing is not giving be Sorted Array while it's C equivalent works i.e
int cmp(struct suffix a, struct suffix b)
{
return (a.rank[0] == b.rank[0])? (a.rank[1] < b.rank[1] ?1: 0):
(a.rank[0] < b.rank[0] ?1: 0);
}
Why My java Sorting is not working. Please Help
static class Tuples{
int[] Rank = new int[2];
}

What about something like this:
public int compare(Tuples a, Tuples b) {
int index = a.Rank[0] == b.Rank[0] ? 1: 0;
return a.Rank[index] - b.Rank[index];
}
A little easier to read in my opinion.

According to the documentation of the Comparator interface, the compare method must return 1, 0 or -1, that are:
0 = the objects are equal
-1 (or any negative integer) = the
object a is less than object b
1 (or any positive integer) = the
object a is greater than object b
So your method must be something like below:
public int compare(Tuples a, Tuples b) {
if(a.Rank[0]==b.Rank[0]){
if(a.Rank[1]==b.Rank[1]){ // a == b
return 0;
}else if(a.Rank[1]<b.Rank[1]){ // a < b
return -1;
}else{ // a > b
return 1;
}
}else{ // a != b
if(a.Rank[0]<b.Rank[0]){ // a < b
return -1;
}else{ //a > b
return 1;
}
}
}
Or in short (and ugly way) it would be like this:
public int compare(Tuples a, Tuples b) {
return (a.Rank[0]==b.Rank[0])?((a.Rank[1]==b.Rank[1])?0:((a.Rank[1]<b.Rank[1])?-1:1)):((a.Rank[0]<b.Rank[0])?-1:1);
}

As SqueezyMo stated in his answer case less and negative integer is missing. One can utilize subtraction to get compact code.
Arrays.sort(arr, new Comparator<Tuples>() {
public int compare(Tuples a, Tuples b) {
return a.Rank[0] == b.Rank[0] ? a.Rank[1] - b.Rank[1] : a.Rank[0] - b.Rank[0];
}
});
Naturally everything can be done using ternary operators, it drives maintainers crazy.
public static void main(String[] args) {
Tuples a = new Tuples();
a.Rank = new int[]{1, 2};
Tuples b = new Tuples();
b.Rank = new int[]{0, 1};
Tuples c = new Tuples();
c.Rank = new int[]{1, 3};
Tuples[] arr = {a, b, c};
Arrays.sort(arr, new Comparator<Tuples>() {
#Override
public int compare(Tuples a, Tuples b) {
return a.Rank[0] == b.Rank[0]
? a.Rank[1] == b.Rank[1]
? 0 : a.Rank[1] < b.Rank[1]
? -1 : 1 : a.Rank[0] > b.Rank[0]
? 1 : -1;
}
});
for (int i = 0; i < 3; i++) {
System.out.println(arr[i].Rank[0] + ":" + arr[i].Rank[1]);
}
}
static class Tuples {
public int[] Rank;
}

Related

Find the maximum length of contagious subarray with repeated element using recursive method with only list as the parameter

Problem:
Find the maximum length of contagious subarray with repeated elements.
eg:
[1 2 2 2 3 3 5 1 8] - answer is 3 since 2 repeated 3 times is the max repeated times.
[1 2] - answer is 1
[1 2 2 3 3] - answer is 2
But the recursive function should only have list as the argument. int findMaxContagiousRepeatedLength(List<Integer> list)
What I've tried:
class Answer
{
public static int findMaxContagiousRepeatedLength(List<Integer> nums, int currentCount, int latestNumber)
{
if (nums.isEmpty())
return 0;
if (nums.get(0) == latestNumber) {
return Math.max(currentCount+1, findMaxContagiousRepeatedLength(nums.subList(1, nums.size()), currentCount+1, nums.get(0)));
} else {
return findMaxContagiousRepeatedLength(nums.subList(1, nums.size()), 1, nums.get(0));
}
}
public static void main(String[] args)
{
Integer[] nums = { 1,2,1,1,1,1,1,2,3,2,3,1,2,2};
System.out.println("Max length: " +
findMaxContagiousRepeatedLength(Arrays.asList(nums), 0, nums.length == 0 ? -1 : nums[0]));
}
}
The above does work, but doesn't meet the requirement of argument restriction.
Please help me figure out if it's possible to have a solution where recursive function only have list as the argument.
Best solution
Use your Function
public static int findMaxContagiousRepeatedLength(List<Integer> nums, int currentCount, int latestNumber)
{
if (nums.isEmpty())
return 0;
if (nums.get(0) == latestNumber) {
return Math.max(currentCount+1, findMaxContagiousRepeatedLength(nums.subList(1, nums.size()), currentCount+1, nums.get(0)));
} else {
return findMaxContagiousRepeatedLength(nums.subList(1, nums.size()), 1, nums.get(0));
}
}
and make a second Function which calls your function with default parameters
public static int findMaxContagiousRepeatedLength(List<Integer> nums)
{
return findMaxContagiousRepeatedLength(Arrays.asList(nums), 0, nums.length == 0 ? -1 : nums[0]);
}
Now you can call the second function which calls the first function with default parameters!
First, this problem is best solved by just going through the list.
But if you must use recursion with List<Integer> as the only parameter you may use the below:
public static int findMaxContiguousRepeatedLength(List<Integer> nums) {
if (nums.isEmpty()) {
return 0;
}
Iterator<Integer> it = nums.iterator();
Integer start = it.next();
int len = 1, pos = 1;
while (it.hasNext()) {
Integer curr = it.next();
if (curr == start) {
pos++;
len++;
} else {
break;
}
}
return Math.max(len, findMaxContiguousRepeatedLength(nums.subList(pos,nums.size())));
}
If you're allowed to (temporarily) modify the list, the below approach would also work:
public static int findMaxContiguousRepeatedLength(List<Integer> nums) {
if (nums.isEmpty()) {
return 0;
}
// carve out repeated chunk from back
Integer back = nums.remove(nums.size() - 1);
int repeats = 1;
while(!nums.isEmpty() && nums.get(nums.size() - 1) == back) {
nums.remove(nums.size() - 1);
repeats++;
}
int res = Math.max(repeats, findMaxContiguousRepeatedLength(List<Integer> nums));
while(repeats) { // restore
repeats--;
nums.add(back);
}
return res;
}

Get a boolean answer from a custom Comparator

I have learned how to create my own Comparator, for example, create a simple one to compare based on absolute value
class absComparator implements Comparator<Integer> {
public int compare(Integer a, Integer b) {
return a * a - b * b;
}
}
And of course, this can be used for a customized sort:
List<Integer> list_1 = new ArrayList<>(Arrays.asList(-3, -2, -1, 0, 1, 2));
list_1.sort(new absComparator());
>>> [0, -1, 1, -2, 2, -3]
So this is all good, but what if I want to just compare two Integers based on this comparator to give a boolean value?
// Currently:
System.out.println(-2>1);
>>> false
So how do I get a true by comparing -2 and 1, using absComparator?
Call compare directly and check the result against 0 using the same relational operator. If you want to check -2 > 1, pass those two numbers in as parameters and check if the result is > 0.
Comparator<Integer> comparator = new absComparator();
System.out.println(comparator.compare(-2, 1) > 0);
IMO, method like isGreaterThan, isLessThan should be added to Comparator interface.
Since we don't have these in this moment, we can create our own interface extending Comparator, and add default method isGreaterThan, isLessThan, as follow:
public interface EnhancedComparator<T> extends Comparator<T> {
default boolean isGreaterThan(T target, T compareTo) {
return this.compare(target, compareTo) > 0;
}
default boolean isLessThan(T target, T compareTo) {
return this.compare(target, compareTo) < 0;
}
}
public class AbsoluteValueComparator implements EnhancedComparator<Integer> {
#Override
public int compare(Integer a, Integer b) {
a = Math.abs(a);
b = Math.abs(b);
return a.compareTo(b);
}
}
public class EnhancedComparatorTest {
public static void main(String[] args) {
EnhancedComparator<Integer> absoluteValueComparator = new AbsoluteValueComparator();
System.out.println("2 greater than 3 " + absoluteValueComparator.isGreaterThan(2, 3));
System.out.println("-3 greater than -2 " + absoluteValueComparator.isGreaterThan(-3, -2));
System.out.println("2 less than 3 " + absoluteValueComparator.isLessThan(2, 3));
System.out.println("-3 less than -2 " + absoluteValueComparator.isLessThan(-3, -2));
}
}
P.S.
a * a may overflow, you may refer to my example for more robust comparison.
References
The Java™ Tutorials Default Method
Java Doc Comparator
How does Java handle integer underflows and overflows and how would you check for it?
Java does not support operator overloading.
That being said, you can easily define your own static method for it:
private static final Comparator<Integer> ABS_CMP = new AbsComparator();
public static boolean gtAbs (int a, int b) {
return ABS_CMP.compare(a, b) > 0;
}
And then import it statically and use it operator-like:
import static your.UtilityClass.gteAbs;
[...]
int a = 5;
int b = -6;
if (gtAbs(a,b)) {
// do work
}
First, your problem is that you are not using your comparator.
class absComparator implements Comparator<Integer> {
public int compare(Integer a, Integer b) {
return a * a - b * b;
}
}
absComparator comp = new absComparator();
if (comp.compare(-2,1)) > 0) {
System.out.println(true);
}
But your comparator has a more fundamental problem. The following also
prints true. This is due to integer overflow when you subtract the products.
if (comp.compare(12345678, 123456789) > 0) {
System.out.println(true);
}
To correct the problem, write your comparator as follows:
class absComparator implements Comparator<Integer> {
public int compare(Integer a, Integer b) {
// eliminate the need for products by
// getting abs (Math.abs() also available);
int a1 = a >= 0 ? a : -a;
int b1 = b >= 0 ? b : -b;
// but you still should not subract as overflow can
// still happen for large values of a1 and b1
return a1 > b1 ? 1 : a1 < b1 ? -1 : 0;
// or return Integer.compare(a1,b1);
// or if (a1 > b1) {
// return 1;
// }
// if (a1 < b1) {
// return -1;
// }
// return 0;
}
}
Use an instance of your comparator:
absComparator comp = new absComparator();
int result = comp.compare(-2, 1);
if (result > 0) {
// -2 > 1 (according to your comparator)
}

Need to find position of maximum of three numbers

I am trying to find the position of the maximum of three numbers that the user inputs. I do not know how to find the position of this but I can find max of the numbers.
Here is the task:
Here is the method named getNumberOfMaxParam that takes three integer numbers and returns the position of the first maximum in the order of the method parameters.
UPDATE: I am trying to compare the int a.b.c but I get This method must return a result of type int error
Code:
import java.util.Scanner;
class App {
public static int getNumberOfMaxParam(int a, int b, int c) {
int firstMax = Math.max(a, b);
int highMax = Math.max(firstMax, c);
if (a == highMax) {
System.out.println("1");
} else if (b == highMax) {
System.out.println("2");
} else if (c == highMax) {
System.out.println("3");
} else {
return highMax;
}
}
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
final int a = scanner.nextInt();
final int b = scanner.nextInt();
final int c = scanner.nextInt();
System.out.print(getNumberOfMaxParam(a, b, c));
}
}
Now how do I find the position?
You can do this with the Stream api. You simply pass an array of values in the order you want. Then create an IntStream of the values and find the max. Then create an IntStream of the indices and find the first value in the array to see if it matches max, and return the index.
private static int getIndexOfMax(int... values) {
int max = IntStream.of(values).max().orElseThrow(IllegalStateException::new);
return IntStream.range(0, values.length)
.filter(index -> values[index] == max)
.findFirst().orElseThrow(IllegalStateException::new);
}
int index = getIndexOfMax(1, 2, 3);
assert index == 2;
**PS. It could be controversial if you supply same value for multiple inputs.**
public static int getNumberOfMaxParam(int a, int b, int c) {
int firstMax = Math.max(a, b);
int highMax = Math.max(firstMax, c);
return (highMax == a ? 1 : (highMax == b ? 2 : 3 );
}

list of integer arrays is changed java

I am using a list of integer arrays, which is a class variable, to hold the answers. The integer arrays are added to the list in a method, and the results are fine (has 1s). But when I fetch it in main method, the value in it is all 0s! I do not understand, where is the list changed?
public class test {
private static int sum=0;
static ArrayList<Integer[]> res = new ArrayList<Integer[]>();
private static double max=0;
public static void main(String[] args) {
int n = 6;
double B = 23.6;
double[] menu = { 1.2, 2, 2.5, 3.5, 3.2, 6.2, 7.8, 4.0, 5.6, 10, 6.5 };
Integer[] solution = new Integer[menu.length];
combinate(menu, 0, n,0, res, solution);
for(int i=0;i<res.size();i++) {
//not getting the element!!!!!!!!!!!!
//Integer[] sol = res.get(i);
System.out.println(i+" "+res.get(i));
System.out.println("Arraylist contains:"+Arrays.toString( res.get( i ) ) );
double sums = 0.0;
for (int j = 0; j < res.get(i).length; j++) {
if(res.get(i)[j]!=null)
sums += menu[j] * res.get(i)[j];
}
if (max < sums && sums < B) {
max = sums;
}
}
System.out.println(max + " max");
}
public static void combinate(double[] left, int n, int k,int sum,
ArrayList<Integer[]> res, Integer[] holder) {
if (n == left.length) {
if (sum == k) {
res.add(holder);
System.out.println(res.size()+" "+Arrays.toString(res.get(res.size()-1)));
}
sum = 0;
return;
}
{
holder[n] = 1;
sum++;
combinate(left, n + 1, k, sum,res, holder);
holder[n] = 0;
sum--;
combinate(left, n + 1, k, sum,res, holder);
}
}
}
}
The answers looks like this:
when print in method combinate, the list elements looks like [1111100000]
while in main method, there are all [000000000000]
what goes wrong here?
if (sum == k)
{
res.add(holder.clone()); // take copy of holder at that moment
System.out.println(res.size()+" "+Arrays.toString(res.get(res.size()-1)));
}
Will Help.
[See Experiment : http://rextester.com/DNNZ68674 ]
Have your method "combinate" return new res like public static ArrayList<Integer[]> combinate(double[] left, int n, int k,int sum,
ArrayList<Integer[]> res, Integer[] holder)
then in your main : res = combinate(...);
You have only a single Integer[] instance that you add to your result (res.add(holder)) and overwrite while unwinding the recursion.
You should add a clone of your array to the result:
res.add(holder.clone());
In the original code you're passing the "holder"-variable as a parameter. In Java parameters are passed by value.
This means, you can change the value inside of the combinate-function, but this will never be reflected back to the calling main-function - that's the nature of call by value.

Permutation of an array, with repetition, in Java

There are some similar questions on the site that have been of some help, but I can't quite nail down this problem, so I hope this is not repetitive.
This is a homework assignment where you have a set array of characters [A, B, C], and must use recursion to get all permutations (with repetition). The code I have sort of does this:
char[] c = {'A', 'B' , 'C'};
public void printAll(char[] c, int n, int k) {
if (k == n) {
System.out.print(c);
return;
}
else {
for (int j = 0; j<n; j++) {
for (int m = 0; m<n; m++) {
System.out.print(c[k]);
System.out.print(c[j]);
System.out.print(c[m] + "\r\n");
}
}
}
printAll(c, n, k+1);
}
However, the parameter n should define the length of the output, so while this function prints out all permutations of length 3, it cannot do them of length 2. I have tried everything I can think of, and have pored over Google search results, and I am aggravated with myself for not being able to solve what seems to be a rather simple problem.
If I understand correctly, you are given a set of characters c and the desired length n.
Technically, there's no such thing as a permutation with repetition. I assume you want all strings of length n with letters from c.
You can do it this way:
to generate all strings of length N with letters from C
-generate all strings of length N with letters from C
that start with the empty string.
to generate all strings of length N with letters from C
that start with a string S
-if the length of S is N
-print S
-else for each c in C
-generate all strings of length N with letters from C that start with S+c
In code:
printAll(char[] c, int n, String start){
if(start.length >= n){
System.out.println(start)
}else{
for(char x in c){ // not a valid syntax in Java
printAll(c, n, start+x);
}
}
}
I use this java realization of permutations with repetitions. A~(n,m): n = length of array, m = k. m can be greater or lesser then n.
public class Permutations {
static void permute(Object[] a, int k, PermuteCallback callback) {
int n = a.length;
int[] indexes = new int[k];
int total = (int) Math.pow(n, k);
Object[] snapshot = new Object[k];
while (total-- > 0) {
for (int i = 0; i < k; i++){
snapshot[i] = a[indexes[i]];
}
callback.handle(snapshot);
for (int i = 0; i < k; i++) {
if (indexes[i] >= n - 1) {
indexes[i] = 0;
} else {
indexes[i]++;
break;
}
}
}
}
public static interface PermuteCallback{
public void handle(Object[] snapshot);
};
public static void main(String[] args) {
Object[] chars = { 'a', 'b', 'c', 'd' };
PermuteCallback callback = new PermuteCallback() {
#Override
public void handle(Object[] snapshot) {
for(int i = 0; i < snapshot.length; i ++){
System.out.print(snapshot[i]);
}
System.out.println();
}
};
permute(chars, 8, callback);
}
}
Example output is
aaaaaaaa
baaaaaaa
caaaaaaa
daaaaaaa
abaaaaaa
bbaaaaaa
...
bcdddddd
ccdddddd
dcdddddd
addddddd
bddddddd
cddddddd
dddddddd
I just had an idea. What if you added a hidden character (H for hidden) [A, B, C, H], then did all the fixed length permutations of it (you said you know how to do that). Then when you read it off, you stop at the hidden character, e.g. [B,A,H,C] would become (B,A).
Hmm, the downside is that you would have to track which ones you created though [B,H,A,C] is the same as [B,H,C,A]
Here is c# version to generate the permutations of given string with repetitions:
(essential idea is - number of permutations of string of length 'n' with repetitions is n^n).
string[] GetPermutationsWithRepetition(string s)
{
s.ThrowIfNullOrWhiteSpace("s");
List<string> permutations = new List<string>();
this.GetPermutationsWithRepetitionRecursive(s, "",
permutations);
return permutations.ToArray();
}
void GetPermutationsWithRepetitionRecursive(string s, string permutation, List<string> permutations)
{
if(permutation.Length == s.Length)
{
permutations.Add(permutation);
return;
}
for(int i =0;i<s.Length;i++)
{
this.GetPermutationsWithRepetitionRecursive(s, permutation + s[i], permutations);
}
}
Below are the corresponding unit tests:
[TestMethod]
public void PermutationsWithRepetitionTests()
{
string s = "";
int[] output = { 1, 4, 27, 256, 3125 };
for(int i = 1; i<=5;i++)
{
s += i;
var p = this.GetPermutationsWithRepetition(s);
Assert.AreEqual(output[i - 1], p.Length);
}
}

Categories

Resources