This has been asked several times, i know, but help me understand something.
You have a map you need sorted by Value
Map<String, Integer> m = new HashMap<String, Integer>();
m.put("a", 1);
m.put("b", 13);
m.put("c", 22);
m.put("d", 2);
You call a method to make it happen
public static List<String> sortByValue(final Map<String, Integer> unsortedMap) {
List<String> sortedKeys = new ArrayList<String>();
sortedKeys.addAll(unsortedMap.keySet());
Collections.sort(sortedKeys, new MapComparator(unsortedMap));
return sortedKeys;
}
You have a comparator class
public MapComparator(Map<String, Integer> m) {
this.m = m;
}
#Override
public int compare(String a, String b) {
int x = m.get(a);
int y = m.get(b);
if (x > y)
return x;
if (y > x)
return y;
return 0;
}
This code, obviously is flawed. Please help me understand why?
if (x > y)
return x;
if (y > x)
return y;
return 0;
You should be returning 1 if x > y and -1 if y > x. The Comparator contract specifies that you return a negative number if the first value is less than the second, a positive number if the first is greater than the second, and zero if they're equal.
(Mind you, as it stands, this Comparator implementation will break in very confusing ways if you ever happen to use values that aren't in the original map.)
Better yet, just return Integer.compare(x, y), which does all that for you. (Only in Java 7, though.)
#Override
public int compare(String a, String b) {
Integer x = m.get(a);
Integer y = m.get(b);
return x.compareTo(y);
}
Since you have Integer objects as values, you can use the implicit method to compare the objects and return 1, 0 or -1.
Comparators don't return the greater or lesser value. They return a negative value to indicate less-than or a positive value to indicate greater than.
if (x > y)
return x;
if (y > x)
return y;
return 0;
should probably be
if (x > y)
return -1;
if (y > x)
return 1;
return 0;
Your comparator only ever indicates that the values are equal or that the left is greater than the right.
Consider the case where x is 1 and y is 2. Your comparator will return 2—a positive number—when it should have returned a negative number.
I recommend that you study the Comparator interface documentation again to see which part of the contract you're missing out on here.
public static List<String> sortByValue(final Map<String, Integer> unsortedMap) {
List<String> sortedKeys = new ArrayList<String>();
sortedKeys.addAll(unsortedMap.keySet());
Collections.sort(sortedKeys, new Comparator<String>(){
public int compare(String s1, String s2) {
return unsortedMap.get(s1).compareTo(unsortedMap.get(s2));
}});
return sortedKeys;
}
Related
This is basically to avoid redundant code. I have two different arrays, one of Float type and one Integer type. I need to find index of maximum element in both the arrays which is easy to do as I can write two different methods, one for comparing float and one for comparing Integers.
What am trying to do improve is to write just one common method which can take in either of the array as argument and can return me the max index. What I have tried unsuccessfully so far is:
private static int findMaxIndex(Object [] arr){
int maxIndex =(int) IntStream.range(0,arr.length)
.boxed()
.max(Comparator.comparingInt(i -> arr[i])) // getting compiler error here
.map(max->arr[max])
.orElse(-1);
return maxIndex;
}
and am looking to call this method like this:
Float [] a = {0.3f, 0.5f, 0.9f, 0.7f, 0.1f};
Integer []b = {3000, 250, 100, 2000, 2000, 10246};
int maxIndexFloatArray = findMaxIndex(a);
int maxIndexIntegerArray = findMaxIndex(b);
Am pretty sure there are easier ways to do this, but am a bit rusty now in hands on java code. Hope this explains the question correctly.
lambda with reduce comparing Comparables
private static <T extends Comparable<? super T>> int findMaxIndex(T[] arr) {
return IntStream.range(0, arr.length)
.reduce((l, r) -> arr[l].compareTo(arr[r]) < 0 ? r : l).orElse(-1);
}
for multiple max values the index of the first is returned
if You need the index of the last max value change the < to <=
arr can be empty but may not contain null values
You could do it old fashioned:
private <T> int findMaxIndex(T[] arr, Comparator<T> comparator){
int maxIndex= 0;
T currMax = arr[0];
for (int i=1;i<arr.length;i++){
if (comparator.compare(currMax,arr[i])<0){
currMax = arr[i];
maxIndex = i;
}
}
return maxIndex;
}
And then call it like:
private int getMaxFloatIndex(Float[] floatArr){
return findMaxIndex(floatArr,Float::compareTo);
}
Grabbing the inheritance hierarchy "from top", I would propose Comparable<X> as the input type for findMaxIndex. It is the most general type of object, of which you can distinguish a "max element":
private static <X extends Comparable<X>> int findMaxIndex(final X[] arr) {
return IntStream.range(0, arr.length)
.boxed()
.max(
(Integer idx1, Integer idx2) -> arr[idx1].compareTo(arr[idx2])
)
.orElse(-1);
}
For simplicity: Hoping/assuming arr is nor null nor contains null elements! ;) (otherwise: NPE!)
...to use it like:
Float[] a = { 0.3f, 0.5f, 0.9f, 0.7f, 0.1f };
Integer[] b = { 3000, 250, 100, 2000, 2000, 10246 };
System.out.println(findMaxIndex(a));
System.out.println(findMaxIndex(b));
Prints:
2
5
This one should do the trick:
private static <T extends Number & Comparable<T>> int findMaxIndex(T[] array) {
if (array == null || array.length == 0) return -1;
int largest = 0;
for (int i = 1; i < array.length; i++) {
if (array[i].compareTo(array[largest]) > 0) largest = i;
}
return largest;
}
You literally tell the compiler that your generic parameter T should be both a Number and Comparable to the same type.
<T extends Number & Comparable<T>> int findMaxIndex(T[] arr)
This can find the index of the maximal value based on Number, the interface of all numeric types, wrapper classes and atomic wrappers.
Also a findMax might so be made. Without the numeric aspect, just Comparable suffices, say for a String[].
I have a class with two float variables and hashCode method (without equals in current code snippet):
public class TestPoint2D {
private float x;
private float z;
public TestPoint2D(float x, float z) {
this.x = x;
this.z = z;
}
#Override
public int hashCode() {
int result = (x != +0.0f ? Float.floatToIntBits(x) : 0);
result = 31 * result + (z != +0.0f ? Float.floatToIntBits(z) : 0);
return result;
}
}
The following test
#Test
public void tempTest() {
TestPoint2D p1 = new TestPoint2D(3, -1);
TestPoint2D p2 = new TestPoint2D(-3, 1);
System.out.println(p1.hashCode());
System.out.println(p2.hashCode());
}
returns same values:
-2025848832
In this case I can't use my TestPoint2D within HashSet / HashMap
Can anyone suggest how to implement hashCode in this case or workarounds related to this?
P.S.
Added one more test:
#Test
public void hashCodeTest() {
for (float a = 5; a < 100000; a += 1.5f) {
float b = a + 1000 / a; // negative value depends on a
TestPoint3D p1 = new TestPoint3D(a, -b);
TestPoint3D p2 = new TestPoint3D(-a, b);
Assert.assertEquals(p1.hashCode(), p2.hashCode());
}
}
And it is passed that proves that
TestPoint2D(a, -b).hashCode() == TestPoint2D(-a, b).hashCode()
I would use Objects.hash():
public int hashCode() {
return Objects.hash(x, z);
}
From the Javadoc:
public static int hash(Object... values)
Generates a hash code for a sequence of input values. The hash code is generated as if all the input values were placed into an array, and that array were hashed by calling Arrays.hashCode(Object[]).
This method is useful for implementing Object.hashCode() on objects containing multiple fields. For example, if an object that has three fields, x, y, and z, one could write:
These auto-generated hashcode functions are not very good.
The problem is that small integers cause very "sparse" and similar bitcodes.
To understand the problem, look at the actual computation.
System.out.format("%x\n", Float.floatToIntBits(1));
System.out.format("%x\n", Float.floatToIntBits(-1));
System.out.format("%x\n", Float.floatToIntBits(3));
System.out.format("%x\n", Float.floatToIntBits(-3));
gives:
3f800000
bf800000
40400000
c0400000
As you can see, the - is the most significant bit in IEEE floats. Multiplication with 31 changes them not substantially:
b0800000
30800000
c7c00000
47c00000
The problem are all the 0s at the end. They get preserved by integer multiplication with any prime (because they are base-2 0s, not base-10!).
So IMHO, the best strategy is to employ bit shifts, e.g.:
final int h1 = Float.floatToIntBits(x);
final int h2 = Float.floatToIntBits(z);
return h1 ^ ((h2 >>> 16) | (h2 << 16));
But you may want to look at Which hashing algorithm is best for uniqueness and speed? and test for your particular case of integers-as-float.
according to the java specification, 2 objects can have the same hashCode and this doesnt mean they are equal...
the probability is small but exist...
on the other hand is always a good practice to override both equals and hashcode...
As I understand the problem, you expect a lot of symmetrical pairs of points among your keys, so you need a hashCode method that does not tend to give them the same code.
I did some tests, and deliberately giving extra significance to the sign of x tends to map symmetrical points away from each other. See this test program:
public class Test {
private float x;
private float y;
public static void main(String[] args) {
int collisions = 0;
for (int ix = 0; ix < 100; ix++) {
for (int iz = 0; iz < 100; iz++) {
Test t1 = new Test(ix, -iz);
Test t2 = new Test(-ix, iz);
if (t1.hashCode() == t2.hashCode()) {
collisions++;
}
}
}
System.out.println(collisions);
}
public Test(float x, float y) {
super();
this.x = x;
this.y = y;
}
#Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = (x >= 0) ? 1 : -1;
result = prime * result + Float.floatToIntBits(x);
result = prime * result + Float.floatToIntBits(y);
return result;
}
// Equals omitted for compactness
}
Without the result = (x >= 0) ? 1 : -1; line it is the hashCode() generated by Eclipse, and counts 9802 symmetrical point collisions. With that line, it counts one symmetrical point collision.
There's a group:
S = {(xi,yi)|1 ≤ i ≤ n}
of n points. There are no 2 points (xi,yi) (xj,yj) where xi = xj and yi = yj.
It means the x and y values are unique. I need to find a data structure that supports the functions:
Given x, return the value of y where (x,y) is in S. If it doesn't exist return "not exist".
Given y, return the value x where (x,y) is in S. If it doesn't exist return "not exist".
A simple solution will be to create two sorted arrays (one sorted according to the x values and the second sorted according to the y values). To find y with a given x will take O(logn), by using binary search. The same for finding x.
I can't use more than one array (of n elements) and each element is a point.
I need to find an efficient data structure that can do those actions in an optimal time. I need to find:
T(first function)+T(second action).
Which data structure is the most efficient in this case?
Thank you very much.
Fundamentally, you just need a pair of maps:
Map<TypeOfX, TypeOfY> mapXtoY;
Map<TypeOfY, TypeOfX> mapYtoX;
You can use any concrete implementation of Map, e.g. HashMap, TreeMap, LinkedHashMap...
To add a point, you simply add it to both:
void addPoint(TypeOfX x, TypeOfY y) {
mapXtoY.put(x, y);
mapYtoX.put(y, x);
}
And you can get the y for an x by using:
TypeOfY y = mapXtoY.get(x);
and vice versa.
Libraries such as Guava provide BiMap implementations, which maintain this two-directional mapping for you.
Note: I dont read your condition '(xi, yi), (xj, yj) => xi != xj && yi != yj' as you do, to me this only means that the coordinates are unique (not each x and each y).
So you first must create a Point object
public class Point {
public int x;
public int y;
public Point(int x, int y) { this.x = x; this.y = y; }
}
Then store all your points into a unique array (you said you need it)
Point[] POINTS = ... // fill your array depending on your input
Finally wrap ths array into a class that provides the methods you need
public class PointCollection {
public Point[] points;
public Map<Integer, List<Integer>> mapX = new HashMap<Integer; List<Integer>>();
public Map<Integer, List<Integer>> mapY = new HashMap<Integer; List<Integer>>();
public PointCollection(Points[] points) {
this.points = points;
for (Point p : points) {
mapX.getOrDefault(p.x, new ArrayList<Integer>()).add(p.y);
mapY.getOrDefault(p.y, new ArrayList<Integer>()).add(p.x);
}
}
public int[] getMatchingY(int x) {
List<Integer> result = new ArrayList<Integer>();
for (Point p : this.points)) {
if (p.x == x) result.add(p.y);
}
return result.toArray(new int[result.size()]);
}
public int[] getMatchingX(int y) {
List<Integer> result = new ArrayList<Integer>();
for (Point p : this.points)) {
if (p.y == y) result.add(p.x);
}
return result.toArray(new int[result.size()]);
}
public int[] getMatchingYFromMap(int x) {
List<Integer> result = mapX.getOrDefault(x, new ArrayList<Integer>());
return result.toArray(new int[result.size()]);
}
public int[] getMatchingXFromMap(int y) {
List<Integer> result = mapY.getOrDefault(y, new ArrayList<Integer>());
return result.toArray(new int[result.size()]);
}
}
edit: added solution based on map
So, I am writing a Befunge Interpreter in Java. I have almost all of it down, except I can't figure out a good solution to the problem of Funge Space. Currently I'm using the style stated in the Befunge 93 specs, which is a 80x25 array to hold the code.
In Funge, though, I'm supposed to have an "infinite" array of code (or 4,294,967,296 x 4,294,967,296, which is -2,147,483,648 to 2,147,483,648 in both dimensions), but obviously it's never a good idea to have that much space allocated. But as well as this, it doesn't seem like a good idea to create a new array and copy every character into it every time the program steps out of bounds. Is there a solution to this problem that I'm missing?
So basically, my problem is that I need to somehow expand the array every time I reach out of bounds, or use some sort of other data structure. Any suggestions?
Funge 98 specs
Also, by the way, I still have never figure out how to pronounce Befunge or Funge, I always just say it like "Bee-funj" and "funj"
Without having read the specs (no - I mean, just NO!): A 4,294,967,296 x 4,294,967,296 array is obviously a highly theoretical construct, and only a tiny fraction of these "array entries" can and will ever be used.
Apart from that: Regardless of whether you use an array or any other collection, you'll have a problem with indexing: Array indices can only be int values, but 4,294,967,296 is twice as large as Integer.MAX_VALUE (there are no unsigned ints in Java).
However, one way of representing such an "infinitely large" sparse 2D array would be a map that maps pairs of long values (the x and y coordinates) to the array entries. Roughly like this:
import java.util.HashMap;
import java.util.Map;
interface Space<T>
{
void set(long x, long y, T value);
T get(long x, long y);
}
class DefaultSpace<T> implements Space<T>
{
private final Map<LongPair, T> map = new HashMap<LongPair, T>();
#Override
public void set(long x, long y, T value)
{
LongPair key = new LongPair(x,y);
if (value == null)
{
map.remove(key);
}
else
{
map.put(key, value);
}
}
#Override
public T get(long x, long y)
{
return map.get(new LongPair(x,y));
}
}
class LongPair
{
private final long x;
private final long y;
LongPair(long x, long y)
{
this.x = x;
this.y = y;
}
#Override
public String toString()
{
return "("+x+","+y+")";
}
#Override
public int hashCode()
{
final int prime = 31;
int result = 1;
result = prime * result + (int) (x ^ (x >>> 32));
result = prime * result + (int) (y ^ (y >>> 32));
return result;
}
#Override
public boolean equals(Object obj)
{
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
LongPair other = (LongPair) obj;
if (x != other.x)
return false;
if (y != other.y)
return false;
return true;
}
}
my simple example (compiled working code) just does not sort fruits by their weight.
import java.util.Arrays;
public class Test {
public static class Fruit implements Comparable<Fruit> {
public int weight = 0;
public Fruit(int w) { weight = w; }
// compare this fruit to a given fruit f
public int compareTo(Fruit f) {
return (weight > f.weight) ? 1 : 0;
}
}
public static void main(String[] args) {
// get some fruits (we intentionally create a box for 100 fruits)
Fruit[] fruits = new Fruit[100];
for (int i = 0; i < 10; i++) {
fruits[i] = new Fruit((int)(Math.random() * 50 + 1));
}
// sort fruits by weight
Arrays.sort(fruits, 0, 10);
// print fruit weights
for (int i = 0; i < 10; i++) {
System.out.print(fruits[i].weight + " ");
}
}
}
Why it is so?
Alright, in my problem (not about fruits), I have objects that are never pairwise equal, that is why I thought one object is either bigger or smaller than another. So how can I handle this situation when I know that 0 (objects are equal) will never happen?
compareTo must return one of 3 values:
>0 --> Bigger than
0 --> Equal
<0 --> Less than
Your compareTo method only returns 0 or 1; fix that.
Use the method public static int compare(int x, int y) from the class java.lang.Integer (since Java 7).
public int compareTo(Fruit f) {
return Integer.compare(weight, f.weight);
}
If weight is never negative then you can try
return weight - f.weight;
instead of
return (weight > f.weight) ? 1 : 0;
to sort from lowest to highest value.
The best approach is to use the JDK-supplied method for comparing int values, which also makes it crystal clear what the code is doing
public int compareTo(Fruit f) {
return Integer.compare(weight, f.weight);
}
Prior to version 7 java, you have two choices:
public int compareTo(Fruit f) {
return weight - f.weight; // terse, but slightly obtuse
}
public int compareTo(Fruit f) {
return new Integer(weight).compareTo(f.weight); // ugly, but supposedly clear
}
My preference is the subtraction, because once you understand it, it's clear from then on.
Your compareTo method should return -1, 0, 1
LESSER = -1;
EQUAL = 0;
BIGGER = 1;