Computed hashcode to lie within a particular range of values? - java

I have a function which looks like this:
public int getHashcode(int shardCount){
String personid = "<some long string value>";
String servicedate = "2019-12-22T01:31:30.000Z";
HashCodeBuilder hashCodeBuilder = new HashCodeBuilder();
return hashCodeBuilder.append(personid).append(servicedate).toHashCode() % shardCount;
//the shard count key comes in from a config file and has various values
// like 2,5,15,25 etc depending on some criteria
}
Now, the requirement is that I want this method to return the hashcode such that it falls in the range of 0-10 and should not exceed 10. Simplest way according to me, is adding a conditional check before returning the value and then return a random value as per my wish, but is that an optimal solution to this, or should I put a fixed "shardCount" value to achieve the result?

The simplest way is to return the remainder when divided by 10.
Replace
return hashCodeBuilder.append(personid).append(servicedate).toHashCode() % shardCount;
with
return (hashCodeBuilder.append(personid).append(servicedate).toHashCode() % shardCount) % 10;

Related

Which string will always have a positive compareTo return value, regardless to which other string it is compared?

I would like to know biggest possible string in the sort system. When I sort in increasing order, it will be guarenteed that this item is going to position itself at the bottom. I will use this string to position empty cells at the bottom.
I tried "zzzzzzzzzzz" string , but it does not work in some cases.
mainPersonnelList.sort((Personnel o1, Personnel o2) -> {
String o1Str = o1.getPersonnelName();
String o2Str = o2.getPersonnelName();
if(o1Str.isEmpty()){o1Str = "zzzzzzzzzzz";}
if(o2Str.isEmpty()){o2Str = "zzzzzzzzzzz";}
return o1Str.compareTo(o2Str);
});
Which string should I use?
There is no limit to the size of a string as far as you're concerned. The limit is defined by the size of a pointer and the amount of available memory, neither of which will help you make a working program. And don't forget, not only do you want the longest string, but it must be filled with the maximum character as well. There are characters beyond z out there, making this a fine example of an XY problem.
Just remember what a comparator returns: an integer that indicates the direction of the comparison. You are already testing for empty elements, so always moving them down is trivial:
mainPersonnelList.sort((Personnel o1, Personnel o2) -> {
String o1Str = o1.getPersonnelName();
String o2Str = o2.getPersonnelName();
if(o1Str.isEmpty()){
return o2Str.isEmpty() ? 0 : -1;
}
if(o2Str.isEmpty()){return 1;}
return o1Str.compareTo(o2Str);
});
The ternary check is there to make sure the sort stays consistent, and stable.

Long values are concatenating instead of adding

I have this method:
public NumPal next(){
stringRev = reverseString(stringCur);
numRev = Long.parseLong(stringRev);
numCur = Long.parseLong(stringCur);
numCur = (numCur + numRev);
stringCur = Long.toString(numCur);
NumPal n = new NumPal(stringCur);
return n;
}
When i try to add numCur and numRev it for some reason concatenates them. Are they staying as strings? I believe I'm using Long.ParseLong correctly but im not sure.
Check whether the addition is overflowing long size. long size range is 2^63 to 2^63–1. If you want to addition of big numbers which cannot be accommodated in long, try the method present in this link. https://www.geeksforgeeks.org/sum-two-large-numbers/

Combination Java Performance

I want to use this function with a large amount of possibility like 700 integer but the function make too much time to execute. Does someone have an idea to increase the performance? Thank you :)
public static Set<Set<Integer>> combinations(List<Integer> groupSize, int k) {
Set<Set<Integer>> allCombos = new HashSet<Set<Integer>> ();
// base cases for recursion
if (k == 0) {
// There is only one combination of size 0, the empty team.
allCombos.add(new HashSet<Integer>());
return allCombos;
}
if (k > groupSize.size()) {
// There can be no teams with size larger than the group size,
// so return allCombos without putting any teams in it.
return allCombos;
}
// Create a copy of the group with one item removed.
List<Integer> groupWithoutX = new ArrayList<Integer> (groupSize);
Integer x = groupWithoutX.remove(groupWithoutX.size() - 1);
Set<Set<Integer>> combosWithoutX = combinations(groupWithoutX, k);
Set<Set<Integer>> combosWithX = combinations(groupWithoutX, k - 1);
for (Set<Integer> combo : combosWithX) {
combo.add(x);
}
allCombos.addAll(combosWithoutX);
allCombos.addAll(combosWithX);
return allCombos;
}
What features of Set are you going to need to use on the returned value?
If you only need some of them - perhaps just iterator() or contains(...) - then you could consider returning an Iterator which calculates the combinations on the fly.
There's an interesting mechanism to generate the nth combination of a lexicographically ordered set here.
Other data structure. You could try a BitSet instead of the Set<Integer>. If the integer values have a wild range (negative, larger gaps), use an index in groupSize.
Using indices instead of integer values has other advantages: all subsets as bits can be done in a for-loop (BigInteger as set).
No data. Or make an iterator (Stream) of all combinations to repeatedly apply to your processing methods.
Concurrency.
Paralellism would would only mean a factor 4/8. ThreadPoolExecutor and Future maybe.
OPTIMIZING THE ALGORITHM ITSELF
The set of sets could better be a List. That tremendously improves adding a set.
And shows whether the algorithm does not erroneously create identical sets.

Sorting an array according to its Geolocation positions

I have an array with lat and lng in the custom model . i want to sort the array so that minimum distance from my location comes at the top position and so on.
Here is what i have tried
myLocation = new Location("");
myLocation.setLatitude(Double.valueOf(MyApplication.getInstance().getLatitude()));
myLocation.setLongitude(Double.valueOf(MyApplication.getInstance().getLongitude()));
Collections.sort(pings, new DistanceComparator());
private class DistanceComparator implements java.util.Comparator<PingModel>
{
#Override
public int compare(PingModel lhs, PingModel rhs)
{
Location lhsLocation = new Location("");
lhsLocation.setLatitude(Double.valueOf(lhs.latloc));
lhsLocation.setLongitude(Double.valueOf(lhs.lngloc));
Location rhsLocation = new Location("");
rhsLocation.setLatitude(Double.valueOf(lhs.latloc));
rhsLocation.setLongitude(Double.valueOf(lhs.lngloc));
return (int)rhsLocation.distanceTo(myLocation) - (int)lhsLocation.distanceTo(myLocation);
}
}
The result is not sure what kind of sorting it is doing but its not according to distance.
You have a copy-paste error. Change these 2 lines:
rhsLocation.setLatitude(Double.valueOf(lhs.latloc));
rhsLocation.setLongitude(Double.valueOf(lhs.lngloc));
to:
rhsLocation.setLatitude(Double.valueOf(rhs.latloc)); // It's rhs!
rhsLocation.setLongitude(Double.valueOf(rhs.lngloc)); // It's rhs!
Apart from this, you shouldn't convert to int before subtracting the distances. In fact, you should avoid using subtraction as the return value of a comparator. This has some well-known flaws, in particular, as distances are float values, they might not fit into an int. And what is more important, the result of the subtraction might not fit into an int. This means that the int you'd be returning might overflow, leading to unexpected results.
I'd recommend you to use clear, understandable code, instead of smartish, tricky code. Consider changing the last line of your comparator to a common tri-state if:
float lhsDistance = lhsLocation.distanceTo(myLocation);
float rhsDistance = rhsLocation.distanceTo(myLocation);
if (lhsDistance < rhsDistance) {
return -1;
} else if (lhsDistance > rhsDistance) {
return 1;
} else {
return 0;
}
Note: if the values you're comparing are in fact equal, then you must return 0 in your comparator. Otherwise, you might experience subtle, nasty bugs, as explained in this answer.
Not sure if this will help, but I was working on a similar project and found this link to be very helpful : http://www.geodatasource.com/developers/java .
Basically if you have you location; use the distance function to calculate new position - your position, and then sort based on this. Loop through the array of locations, and sort based on results.
Hope it helps.
Dan.
Can you try following
return Float.compare(lhsLocation.distanceTo(myLocation), rhsLocation.distanceTo(myLocation))
Converting to int before substraction might not always work. For example, if your distanceTo() function return km and the distance from your point and the data points is within 1 km then the result of subtraction may be 0.
Instead of
return (int)rhsLocation.distanceTo(myLocation) - (int)lhsLocation.distanceTo(myLocation);
Try
return (rhsLocation.distanceTo(myLocation) - lhsLocation.distanceTo(myLocation)) > 0 ? 1 : -1;

Java convert float to integer

I want to do an operation like this : if the given float numbers are like 1.0 , 2.0 , 3.0 , I want to save them to database as integer (1,2,3 ), if they are like 1.1 , 2.1 , ,3.44 , I save them as float. what's the best solution for this problem using java ? The corresponding field in database is type of varchar.
Just try int i = (int) f;.
EDIT : I see the point in the question. This code might work :
int i = (int) f;
String valToStore = (i == f) ? String.valueOf(i) : String.valueOf(f);
String result = "0";
if (floatVar == Math.floor(floatVar)) {
result = Integer.toString((int) floatVar);
} else {
result = Float.toString(floatVar);
}
The if-clause checks whether the number is a whole number - i.e. if it is equal to the result of rounding it down to the closest whole value.
But this is very odd requirement indeed, and perhaps you should reconsider the need for such a thing.
Seems like you want to save Floats with no trailing numbers as Integers, while saving those with significant trailing numbers as Floats. I would rather just save it all as Float to the DB, but it's your question so here's my answer:
/**
* Method to determine if trailing numbers are significant or not. Significant
* here means larger than 0
*
* #param fFloat
* #return
*/
public static boolean isTrailingSignificant(Float fFloat)
{
int iConvertedFloat = fFloat.intValue();// this drops trailing numbers
// checks if difference is 0
return ((fFloat - iConvertedFloat) > 0);
}
This is how you would use this method:
Number oNumToSave = null;
if (isTrailingSignificant(fFloat))
{
// save float value as is
oNumToSave = fFloat;
}
else
{
// save as int
oNumToSave = fFloat.intValue();// drops trailing numbers
}
After that, you can do the database operation using the variable oNumToSave.
Not sure this is the best solution, but you can try to write a method like this :
String convertToString(Float f) {
if (f.toString().endsWith(".0"))
return f.intValue().toString();
else
return f.toString();
}
Kotlin:
val mAmount = 3.0
val intAmount = mAmount.toInt()
val amountToDisplay = if (intAmount.compareTo(mAmount) == 0) intAmount.toString() else java.lang.String.valueOf(mAmount)

Categories