A very good day to all of you.
I have code which does exactly what a Excel Pivot does in the matter of few seconds. Whereas, my code does the same thing in not less than 30 minutes. I am awestruck with the difference! I am pretty sure I can optimize my code to make much faster than currently. Any help will be highly appreciated.
Please have a quick look at the code. If necessary I will explain in detail what exactly it does. Thank you!
public void countImages(ArrayList<String> all) throws IOException {
HashSet<String> uStrings = new HashSet<>();
int Counter = 0;
int C500x500 = 0;
int C800x800 = 0;
int C1000x1000 = 0;
int G1000x1000 = 0;
write("Vendor ID, Count of Images, Less than 500 x 500, Less than 800 x 800, Less than 1000 x 1000, Greater than 1000 x 1000", "ImageCount_Data");
for (String single : all) {
String[] linearray = single.split(",");
uStrings.add(linearray[0]);
}
totallines = uStrings.size();
completedlines = 0;
percentage = 0;
setPercent(0);
for (String uString : uStrings) {
Counter = 0;
C500x500 = 0;
C800x800 = 0;
C1000x1000 = 0;
G1000x1000 = 0;
for (String single : all) {
String[] linearray = single.split(",");
if (linearray[0].equals(uString)) Counter++;
if ((linearray[1].equals("Less than 500 x 500")) && linearray[0].equals(uString)) C500x500++;
if ((linearray[1].equals("Less than 800 x 800")) && linearray[0].equals(uString)) C800x800++;
if ((linearray[1].equals("Less than 1000 x 1000")) && linearray[0].equals(uString)) C1000x1000++;
if ((linearray[1].equals("Greater than 1000 x 1000")) && linearray[0].equals(uString)) G1000x1000++;
} //END OF 2ND FOR LOOP
write(uString + "," + Counter + "," + C500x500 + "," + C800x800 + "," + C1000x1000 + "," + G1000x1000, "ImageCount_Data");
completedlines++;
percentage = (completedlines / totallines) * 100;
setPercent(Math.round(percentage));
Icwindow.frame.setTitle("Writing Image Count Data: " + getPercent() + "%");
} //END OF 1ST FOR LOOP
Icwindow.frame.setTitle("Process Cloudinary ImageCount Data");
}
You are iterating over all possible strings in column zero, then iterate over all strings again within that loop. Thus your algorithm is O(n²), where Excel gets away with a faster (likely O(n) amortized) algorithm.
You could use a HashMap<String, Counts> to keep track of counts with only one for loop instead of two nested loops.
The Counts object would then contain the counts for your classes, as in:
class Counts {
int c500;
int c800;
int c1000;
int cOther;
void count(String s) {
switch(s) {
case "Less than 500 x 500": c500++; break;
case "Less than 500 x 500": c800++; break;
case "Less than 500 x 500": c1000++; break;
case "Greater than 1000 x 1000": cOther++; break;
default: throw new AssertionError();
}
}
}
Another hint: You can get the global counter by adding c500 + c800 + c1000 + cOther.
Thank you so much!
Below is my new code which uses Hash Map and it is indeed much much faster than my previous code. However, there appears to be something incorrect in the code cause the count is correct only for the first Hash Map and rest 4 Has Maps have incorrect count. May I request you take a look and tell me if you notice anything odd in the new code?
EDIT - I missed adding breaks in switch case statements! This works perfectly & fast! :D
public void countImages(ArrayList<String> all) throws IOException {
HashMap<String, Integer> counter = new HashMap<>();
HashMap<String, Integer> c500 = new HashMap<>();
HashMap<String, Integer> c800 = new HashMap<>();
HashMap<String, Integer> c1000 = new HashMap<>();
HashMap<String, Integer> g1000 = new HashMap<>();
write("Vendor ID, Count of Images, Less than 500 x 500, Less than 800 x 800, Less than 1000 x 1000, Greater than 1000 x 1000", "ImageCount_Data");
for (String single : all) {
String[] linearray = single.split(",");
if (!counter.containsKey(linearray[0])) {
counter.put(linearray[0], 1);
} else {
counter.put(linearray[0], counter.get(linearray[0]) + 1);
}
switch (linearray[1]) {
case "Less than 500 x 500" :
if (!c500.containsKey(linearray[0])) {
c500.put(linearray[0], 1);
} else {
c500.put(linearray[0], c500.get(linearray[0]) + 1);
}
case "Less than 800 x 800" :
if (!c800.containsKey(linearray[0])) {
c800.put(linearray[0], 1);
} else {
c800.put(linearray[0], c800.get(linearray[0]) + 1);
}
case "Less than 1000 x 1000":
if (!c1000.containsKey(linearray[0])) {
c1000.put(linearray[0], 1);
} else {
c1000.put(linearray[0], c1000.get(linearray[0]) + 1);
}
case "Greater than 1000 x 1000" :
if (!g1000.containsKey(linearray[0])) {
g1000.put(linearray[0], 1);
} else {
g1000.put(linearray[0], g1000.get(linearray[0]) + 1);
}
}
}
for (String key : counter.keySet()) {
write(key + "," + counter.get(key) + "," + c500.get(key) + "," + c800.get(key) + "," + c1000.get(key) + "," + g1000.get(key), "ImageCount_Data");
}
}
Related
I have a problem statement as described below:
Write a function that takes this input as a parameter and returns a data structure containing the number of
clicks that were recorded on each domain AND each subdomain under it.
For example, a click on "mail.yahoo.com" counts toward the totals for "mail.yahoo.com", "yahoo.com", and "com".
(Subdomains are added to the left of their parent domain. So "mail" and "mail.yahoo" are not valid domains.
Note that "mobile.sports" appears as a separate domain near the bottom of the input.)
Below is the input data:
String[] counts = {
"900,google.com",
"60,mail.yahoo.com",
"10,mobile.sports.yahoo.com",
"40,sports.yahoo.com",
"300,yahoo.com",
"10,stackoverflow.com",
"20,overflow.com",
"5,com.com",
"2,en.wikipedia.org",
"1,m.wikipedia.org",
"1,mobile.sports",
"1,google.co.uk"
};
Below is the expected output:
calculateClicksByDomain(counts) =>
com: 1345
google.com: 900
stackoverflow.com: 10
overflow.com: 20
yahoo.com: 410
mail.yahoo.com: 60
mobile.sports.yahoo.com: 10
sports.yahoo.com: 50
com.com: 5
org: 3
wikipedia.org: 3
en.wikipedia.org: 2
m.wikipedia.org: 1
mobile.sports: 1
sports: 1
uk: 1
co.uk: 1
google.co.uk: 1
I tried to write a solution for above problem statement:
Map<String, Integer> calculateClicksByDomainMap = new HashMap<>();
for(int i = 0; i < counts.length; i++) {
String[] seperateClickCountsAtComma = counts[i].split("\\,");
for(int j = 0; j < seperateClickCountsAtComma.length; j += 2) {
String clickCounts = seperateClickCountsAtComma[j];
String domain = seperateClickCountsAtComma[j+1];
calculateClicksByDomainMap.put(domain, Integer.parseInt(clickCounts));
}
}
for(Entry<String, Integer> domainCounts : calculateClicksByDomainMap.entrySet()) {
String domainName = domainCounts.getKey();
Integer domainCount = domainCounts.getValue();
splitStringOnOccurenceOfDot(domainName);
//System.out.println(domainName + " " + domainCount);
//String test[] = domainName.split("\\.");
//System.out.println(test[0] + "=======" + test[1] + "-----");
}
public static String splitStringOnOccurenceOfDot(String domainName) {
if(!domainName.contains(".")) {
return domainName;
}
String[] subdomain = domainName.split("\\.");
domainName = subdomain[1];
System.out.println(domainName + "===============" );
return splitStringOnOccurenceOfDot(domainName);
}
However, I'm not sure how to split the string using recursion.
Can anyone help me what is the efficient way to write code in order to get the expected output?
I there a way to solve it using recursion?
Thank you for your time.
The Map needs to ConcurrentHashMap, so that it allows concurrent updates.
First for loop with nesting can call the recursive method like below, might not need another for loop:
Map<String, Integer> calculateClicksByDomainMap = new ConcurrentHashMap<>();
for (final String count : counts) {
String[] separateClickCountsAtComma = count.split("\\,");
for (int j = 0; j < separateClickCountsAtComma.length; j += 2) {
Integer clickCount = Integer.parseInt(separateClickCountsAtComma[j]);
String domain = separateClickCountsAtComma[j + 1];
calculateClicksByDomainMap.put(domain, clickCount);
splitStringOnOccurenceOfDot(domain.substring(domain.indexOf(".")+1), clickCount, calculateClicksByDomainMap);
}
}
Rather than returning a value, recursion add/update map itself.
public static void splitStringOnOccurenceOfDot(String domainName, Integer domainCount, Map<String, Integer> calculateClicksByDomainMap) {
if(calculateClicksByDomainMap.containsKey(domainName)) {
Integer newCount = calculateClicksByDomainMap.get(domainName) + domainCount;
calculateClicksByDomainMap.put(domainName, newCount);
} else {
calculateClicksByDomainMap.put(domainName, domainCount);
}
if(domainName.contains(".")) {
splitStringOnOccurenceOfDot(domainName.substring(domainName.indexOf(".")+1), domainCount, calculateClicksByDomainMap);
}
}
This is a probable answer of my question in stack overflow.Integer to word conversion
At first I have started with dictionary. Then I came to know it is obsolete. So now I use Map instead of dictionary. My code is work well for number till Millions. But the approach I take here is a naive approach. The main problem of this code is
First: Huge numbers of variable use
2nd: Redundant code block as per program requirement
3rd: Multiple if else statement
I am thinking about this problems
Solution for 2nd problem: using user define function or macros to eliminate redundant code block
Solution for 3rd problem: Using switch case
My code:
public class IntegerEnglish {
public static void main(String args[]){
Scanner in=new Scanner(System.in);
System.out.println("Enter the integer");
int input_number=in.nextInt();
Map<Integer,String> numbers_converter = new HashMap<Integer,String>();
Map<Integer,String> number_place = new HashMap<Integer,String>();
Map<Integer,String> number_2nd = new HashMap<Integer,String>();
numbers_converter.put(0,"Zero");
numbers_converter.put(1,"One");
numbers_converter.put(2,"Two");
numbers_converter.put(3,"Three");
numbers_converter.put(4,"Four");
numbers_converter.put(5,"Five");
numbers_converter.put(6,"Six");
numbers_converter.put(7,"Seven");
numbers_converter.put(8,"Eight");
numbers_converter.put(9,"Nine");
numbers_converter.put(10,"Ten");
numbers_converter.put(11,"Eleven");
numbers_converter.put(12,"Twelve");
numbers_converter.put(13,"Thirteen");
numbers_converter.put(14,"Fourteen ");
numbers_converter.put(15,"Fifteen");
numbers_converter.put(16,"Sixteen");
numbers_converter.put(17,"Seventeen");
numbers_converter.put(18,"Eighteen");
numbers_converter.put(19,"Nineteen");
number_place.put(3,"Hundred");
number_place.put(4,"Thousand");
number_place.put(7,"Million");
number_place.put(11,"Billion");
number_2nd.put(2,"Twenty");
number_2nd.put(3,"Thirty");
number_2nd.put(4,"Forty");
number_2nd.put(5,"Fifty");
number_2nd.put(6,"Sixty");
number_2nd.put(7,"Seventy");
number_2nd.put(8,"Eighty");
number_2nd.put(9,"Ninty");
if(input_number== 0){
System.out.println("zero");
}
else if(input_number>0 && input_number<19){
System.out.println(numbers_converter.get(input_number));
}
else if(input_number>19 && input_number<100){
int rem=input_number%10;
input_number=input_number/10;
System.out.print(number_2nd.get(input_number));
System.out.print(numbers_converter.get(rem));
}
else if(input_number==100){
System.out.println(number_place.get(3));
}
else if(input_number>100 && input_number<1000){
int reminder=input_number%100;
int r1=reminder%10;
int q1=reminder/10;
int quot=input_number/100;
System.out.print(numbers_converter.get(quot) + "hundred");
if(reminder>0 && reminder<20){
System.out.print(numbers_converter.get(reminder));
}
else{
System.out.println(number_2nd.get(q1) + numbers_converter.get(r1));
}
}
else if(input_number==1000){
System.out.println(number_place.get(4));
}
else if(input_number>1000 && input_number<10000){
int rem=input_number%100;
int rem_two=rem%10;
int quotient =rem/10;
input_number=input_number/100;
int thousand=input_number/10;
int hundred = input_number%10;
System.out.print(numbers_converter.get(thousand) + "thousand" + numbers_converter.get(hundred)+ " hundred");
if(rem >0 && rem<20){
System.out.print(numbers_converter.get(rem));
}
else if(rem >19 && rem <100){
System.out.print(number_2nd.get(quotient) + numbers_converter.get(rem_two));
}
}
else if(input_number>10000 && input_number<1000000000){
//Say number 418,229,356
int third_part=input_number%1000;//hold 356
input_number=input_number/1000;//hold 418,229
int sec_part=input_number%1000;//hold 229
input_number=input_number/1000;// hold 418
int rem_m=third_part%100;//hold 56
int rem_m1=rem_m%10;//hold 6
int rem_q=rem_m/10;// hold 5
int q_m=third_part/100;// hold 3
int sec_part_rem=sec_part%100;// hold 29
int sec_part_rem1=sec_part_rem%10;//9
int sec_part_q=sec_part_rem/10;//hold 2
int sec_q=sec_part/100;// hold 2
int input_q=input_number/100;// hold 4
int input_rem=input_number%100;//hold 18
int input_q_q=input_rem/10;//hold 1
int input_rem1=input_rem%10;// hold 8
System.out.print(numbers_converter.get(input_q) + " hundred ");
if(input_rem>0 && input_rem<20){
System.out.print(numbers_converter.get(input_rem)+ " Million ");
}
else{
System.out.print(number_2nd.get(input_q_q) + " " + numbers_converter.get(input_rem1) + " Million ");
}
System.out.print(numbers_converter.get(sec_q) + " hundred ");
if(sec_part_rem >0 && sec_part_rem<20){
System.out.println(numbers_converter.get(sec_part_rem) + " thousand ");
}
else{
System.out.print(number_2nd.get(sec_part_q) + " " + numbers_converter.get(sec_part_rem1) + " thousand ");
}
System.out.print(numbers_converter.get(q_m) + " hundred ");
if(rem_m>0 && rem_m<20){
System.out.print(numbers_converter.get(rem_m));
}
else{
System.out.print(number_2nd.get(rem_q) + " " + numbers_converter.get(rem_m1));
}
}
}
}
Redundant Code Blocks
int rem=input_number%100;
int rem_two=rem%10;
int quotient =rem/10;
input_number=input_number/100;
int thousand=input_number/10;
int hundred = input_number%10;
This type of code block used almost every where. Taking a number divide it with 100 or 1000 to find out the hundred position then then divide it with 10 to find out the tenth position of the number. Finally using %(modular division) to find out the ones position.
How could I include user define function and switch case to minimize the code block.
Instead of storing the results in variables, use a method call:
int remainder100(int aNumber) {
return aNumber % 100;
}
int remainder10(int aNumber) {
return aNumber % 10;
}
...etc.
System.out.println(numbers_converter.get(remainder100(input_number)));
About 3rd problem: I wouldn't use switch ... case, too many cases.
Instead, take advantage that numbering repeats itself every 3 digits. That means the pattern for thousands and millions is the same (and billions, trillions, etc).
To do that, use a loop like this:
ArrayList<String> partialResult = new ArrayList<String>();
int powersOf1000 = 0;
for (int kiloCounter = input_number; kiloCounter > 0; kiloCounter /= 1000) {
partialResult.add(getThousandsMilionsBillionsEtc(powersOf1000++);
partialResult.add(convertThreeDigits(kiloCounter % 1000));
}
Then you can print out the contents of partialResult in reverse order to get the final number.
I'd suggest you break your single main method down into a couple of classes. And if you haven't already create a few unit tests to allow you to easily test / refactor things. You'll find it quicker than starting the app and reading from stdin.
You'll find it easier to deal with the number as a string. Rather than dividing by 10 all the time you just take the last character of the string. You could have a class that does that bit for you, and a separate one that does the convert.
Here's what I came up with, but I'm sure it can be improved. It has a PoppableNumber class which allows the last character of the initial number to be easily retrieved. And the NumberToString class which has a static convert method to perform the conversion.
An example of a test would be
#Test
public void Convert102356Test() {
assertEquals("one hundred and two thousand three hundred and fifty six", NumberToString.convert(102356));
}
And here's the NumberToString class :
import java.util.HashMap;
import java.util.Map;
public class NumberToString {
// billion is enough for an int, obviously need more for long
private static String[] power3 = new String[] {"", "thousand", "million", "billion"};
private static Map<String,String> numbers_below_twenty = new HashMap<String,String>();
private static Map<String,String> number_tens = new HashMap<String,String>();
static {
numbers_below_twenty.put("0","");
numbers_below_twenty.put("1","one");
numbers_below_twenty.put("2","two");
numbers_below_twenty.put("3","three");
numbers_below_twenty.put("4","four");
numbers_below_twenty.put("5","five");
numbers_below_twenty.put("6","six");
numbers_below_twenty.put("7","seven");
numbers_below_twenty.put("8","eight");
numbers_below_twenty.put("9","nine");
numbers_below_twenty.put("10","ten");
numbers_below_twenty.put("11","eleven");
numbers_below_twenty.put("12","twelve");
numbers_below_twenty.put("13","thirteen");
numbers_below_twenty.put("14","fourteen ");
numbers_below_twenty.put("15","fifteen");
numbers_below_twenty.put("16","sixteen");
numbers_below_twenty.put("17","seventeen");
numbers_below_twenty.put("18","eighteen");
numbers_below_twenty.put("19","nineteen");
number_tens.put(null,"");
number_tens.put("","");
number_tens.put("0","");
number_tens.put("2","twenty");
number_tens.put("3","thirty");
number_tens.put("4","forty");
number_tens.put("5","fifty");
number_tens.put("6","sixty");
number_tens.put("7","seventy");
number_tens.put("8","eighty");
number_tens.put("9","ninty");
}
public static String convert(int value) {
if (value == 0) {
return "zero";
}
PoppableNumber number = new PoppableNumber(value);
String result = "";
int power3Count = 0;
while (number.hasMore()) {
String nextPart = convertUnitTenHundred(number.pop(), number.pop(), number.pop());
nextPart = join(nextPart, " ", power3[power3Count++], true);
result = join(nextPart, " ", result);
}
if (number.isNegative()) {
result = join("minus", " ", result);
}
return result;
}
public static String convertUnitTenHundred(String units, String tens, String hundreds) {
String tens_and_units_part = "";
if (numbers_below_twenty.containsKey(tens+units)) {
tens_and_units_part = numbers_below_twenty.get(tens+units);
}
else {
tens_and_units_part = join(number_tens.get(tens), " ", numbers_below_twenty.get(units));
}
String hundred_part = join(numbers_below_twenty.get(hundreds), " ", "hundred", true);
return join(hundred_part, " and ", tens_and_units_part);
}
public static String join(String part1, String sep, String part2) {
return join(part1, sep, part2, false);
}
public static String join(String part1, String sep, String part2, boolean part1Required) {
if (part1 == null || part1.length() == 0) {
return (part1Required) ? "" : part2;
}
if (part2.length() == 0) {
return part1;
}
return part1 + sep + part2;
}
/**
*
* Convert an int to a string, and allow the last character to be taken off the string using pop() method.
*
* e.g.
* 1432
* Will give 2, then 3, then 4, and finally 1 on subsequent calls to pop().
*
* If there is nothing left, pop() will just return an empty string.
*
*/
static class PoppableNumber {
private int original;
private String number;
private int start;
private int next;
PoppableNumber(int value) {
this.original = value;
this.number = String.valueOf(value);
this.next = number.length();
this.start = (value < 0) ? 1 : 0; // allow for minus sign.
}
boolean isNegative() {
return (original < 0);
}
boolean hasMore() {
return (next > start);
}
String pop() {
return hasMore() ? number.substring(--next, next+1) : "";
}
}
}
Is it possible to convert the function go into the non-recursive function? Some hints or a start-up sketch would be very helpful
public static TSPSolution solve(CostMatrix _cm, TSPPoint start, TSPPoint[] points, long seed) {
TSPSolution sol = TSPSolution.randomSolution(start, points, seed, _cm);
double t = initialTemperature(sol, 1000);
int frozen = 0;
System.out.println("-- Simulated annealing started with initial temperature " + t + " --");
return go(_cm, sol, t, frozen);
}
private static TSPSolution go(CostMatrix _cm, TSPSolution solution, double t, int frozen) {
if (frozen >= 3) {
return solution;
}
i++;
TSPSolution bestSol = solution;
System.out.println(i + ": " + solution.fitness() + " " + solution.time() + " "
+ solution.penalty() + " " + t);
ArrayList<TSPSolution> nHood = solution.nHood();
int attempts = 0;
int accepted = 0;
while (!(attempts == 2 * nHood.size() || accepted == nHood.size()) && attempts < 500) {
TSPSolution sol = nHood.get(rand.nextInt(nHood.size()));
attempts++;
double deltaF = sol.fitness() - bestSol.fitness();
if (deltaF < 0 || Math.exp(-deltaF / t) > Math.random()) {
accepted++;
bestSol = sol;
nHood = sol.nHood();
}
}
frozen = accepted == 0 ? frozen + 1 : 0;
double newT = coolingSchedule(t);
return go(_cm, bestSol, newT, frozen);
}
This is an easy one, because it is tail-recursive: there is no code between the recursive call & what the function returns. Thus, you can wrap the body of go in a loop while (frozen<3), and return solution once the loop ends. And replace the recursive call with assignments to the parameters: solution=bestSol; t=newT;.
You need to thinkg about two things:
What changes on each step?
When does the algorithm end?
Ans the answer should be
bestSol (solution), newT (t), frozen (frozen)
When frozen >= 3 is true
So, the easiest way is just to enclose the whole function in something like
while (frozen < 3) {
...
...
...
frozen = accepted == 0 ? frozen + 1 : 0;
//double newT = coolingSchedule(t);
t = coolingSchedule(t);
solution = bestSol;
}
As a rule of thumb, the simplest way to make a recursive function iterative is to load the first element onto a Stack, and instead of calling the recursion, add the result to the Stack.
For instance:
public Item recursive(Item myItem)
{
if(myItem.GetExitCondition().IsMet()
{
return myItem;
}
... do stuff ...
return recursive(myItem);
}
Would become:
public Item iterative(Item myItem)
{
Stack<Item> workStack = new Stack<>();
while (!workStack.isEmpty())
{
Item workItem = workStack.pop()
if(myItem.GetExitCondition().IsMet()
{
return workItem;
}
... do stuff ...
workStack.put(workItem)
}
// No solution was found (!).
return myItem;
}
This code is untested and may (read: does) contain errors. It may not even compile, but should give you a general idea.
I write an OpenGL app in Java using JOGL. I am trying to completely avoid the creation of objects during the main app's phase as it could lead to the small periodic lag caused by GC.
I want to wrap some JOGL's methods with my own. Imagine a method void method(int[] result, int offset) which receives the pointer to an array and an offset and puts one integer value into it at the specified index. I want to wrap it with simple int getResult()
So I need to create a temporary array somewhere and I must do that in advance (according to 1).
But if it will be stored in a field of the class containing this wrapper method, this will force me to make the wrapper method synchronized. I know that sychronization in time of mostly single-thread access shouldn't produce a big overhead but I still want to know is it there a better solution for this.
Notes:
Synchronized is not the answer, 3.000.000 of empty synchronized blocks, just monitorenter-monitorexit take 17 ms. You have only 16.(6) if you want to keep 60 fps.
As I haven't enough power for voting up the only way I found to appreciate Dave's answer is writting a demo:
class Test {
private static final int CYCLES = 1000000000;
int[] global = new int[1];
ThreadLocal<int[]> local = new ThreadLocal<int[]>();
void _fastButIncorrect() { global[0] = 1; }
synchronized void _slowButCorrect() { global[0] = 1; }
void _amazing() {
int[] tmp = local.get();
if( tmp == null ){
tmp = new int[1];
local.set(tmp);
}
tmp[0] = 1;
}
long fastButIncorrect() {
long l = System.currentTimeMillis();
for (int i = 0; i < CYCLES; i++) _fastButIncorrect();
return System.currentTimeMillis() - l;
}
long slowButCorrect() {
long l = System.currentTimeMillis();
for (int i = 0; i < CYCLES; i++) _slowButCorrect();
return System.currentTimeMillis() - l;
}
long amazing() {
long l = System.currentTimeMillis();
for (int i = 0; i < CYCLES; i++) _amazing();
return System.currentTimeMillis() - l;
}
void test() {
System.out.println(
"fastButIncorrect cold: " + fastButIncorrect() + "\n" +
"slowButCorrect cold: " + slowButCorrect() + "\n" +
"amazing cold: " + amazing() + "\n" +
"fastButIncorrect hot: " + fastButIncorrect() + "\n" +
"slowButCorrect hot: " + slowButCorrect() + "\n" +
"amazing hot: " + amazing() + "\n"
);
}
public static void main(String[] args) {
new Test().test();
}
}
on my machine the results are:
fastButIncorrect cold: 40
slowButCorrect cold: 8871
amazing cold: 46
fastButIncorrect hot: 38
slowButCorrect hot: 9165
amazing hot: 41
Thanks again, Dave!
If you don't have too many threads, you can use a ThreadLocal:
ThreadLocal<int[]> tmpArrayThreadLocal = new ThreadLocal<int[]>();
code to use this:
int[] tmpArray = tmpArrayThreadLocal.get();
if( tmpArray == null ){
tmpArray = new int[100];
tmpArrayThreadLocal.set(tmpArray);
}
method(tmpArray, 5)
You could clean up the code by encapsulating the ThreadLocal in another class.
I'm just rephrasing the question I asked a little while ago.
I have a sorted array {2.0,7.8,9.0,10.5,12.3}
If I given an input 9.5
What is the fastest way to find 9.0 and 10.5 to indicate that 9.5 is in between 9.0 and 10.5 (9.5 >=9.0 and <10.5) ?
Is binary search an option?But since the input need not be in the array.I'm not sure how I should do this.
Also If there is any other data structure that is suitable please comment.
A binary search would certainly be the "standard" approach - http://en.wikipedia.org/wiki/Binary_search_algorithm. Speed is O(log(N)) as opposed to linear.
In certain specialised cases you can do better than O(log(N)). But unless you are dealing with truly gigantic array sizes and satisfy these special cases then your binary search is really the fastest approach.
You could use Arrays.binarySearch to quickly locate 9.0 and 10.0, indeed.
Here's a binary search algorithm I just wrote for you that does the trick:
import java.util.Random;
public class RangeFinder {
private void find(double query, double[] data) {
if (data == null || data.length == 0) {
throw new IllegalArgumentException("No data");
}
System.out.print("query " + query + ", data " + data.length + " : ");
Result result = new Result();
int max = data.length;
int min = 0;
while (result.lo == null && result.hi == null) {
int pos = (max - min) / 2 + min;
if (pos == 0 && query < data[pos]) {
result.hi = pos;
} else if (pos == (data.length - 1) && query >= data[pos]) {
result.lo = pos;
} else if (data[pos] <= query && query < data[pos + 1]) {
result.lo = pos;
result.hi = pos + 1;
} else if (data[pos] > query) {
max = pos;
} else {
min = pos;
}
result.iterations++;
}
result.print(data);
}
private class Result {
Integer lo;
Integer hi;
int iterations;
long start = System.nanoTime();
void print(double[] data) {
System.out.println(
(lo == null ? "" : data[lo] + " <= ") +
"query" +
(hi == null ? "" : " < " + data[hi]) +
" (" + iterations + " iterations in " +
((System.nanoTime() - start) / 1000000.0) + " ms. )");
}
}
public static void main(String[] args) {
RangeFinder rangeFinder = new RangeFinder();
// test validation
try {
rangeFinder.find(12.4, new double[] {});
throw new RuntimeException("Validation failed");
} catch (IllegalArgumentException e) {
System.out.println("Validation succeeded");
}
try {
rangeFinder.find(12.4, null);
throw new RuntimeException("Validation failed");
} catch (IllegalArgumentException e) {
System.out.println("Validation succeeded");
}
// test edge cases with small data set
double[] smallDataSet = new double[] { 2.0, 7.8, 9.0, 10.5, 12.3 };
rangeFinder.find(0, smallDataSet);
rangeFinder.find(2.0, smallDataSet);
rangeFinder.find(7.9, smallDataSet);
rangeFinder.find(10.5, smallDataSet);
rangeFinder.find(12.3, smallDataSet);
rangeFinder.find(10000, smallDataSet);
// test performance with large data set
System.out.print("Preparing large data set...");
Random r = new Random();
double[] largeDataSet = new double[20000000];
largeDataSet[0] = r.nextDouble();
for (int n = 1; n < largeDataSet.length; n++) {
largeDataSet[n] = largeDataSet[n - 1] + r.nextDouble();
}
System.out.println("done");
rangeFinder.find(0, largeDataSet);
rangeFinder.find(5000000.42, largeDataSet);
rangeFinder.find(20000000, largeDataSet);
}
}
I would do it like that
double valuebefore = 0;
double valueafter = 0;
double comparevalue = 9;
foreach (var item in a)
{
valueafter = item;
if (item > comparevalue)
{
break;
}
valuebefore = item;
}
System.Console.WriteLine("Befor = {0} After = {1}", valuebefore, valueafter);
If the input numbers are in an array then binary search will be handy. Every time the search fails, indicating the number is not present in the array, the array elements at index low and high will give you the range.
The most efficient (space and time-wise) is to implement this as a modified binary search.
A simple (but less efficient) solution is to replace the array with a NavigableMap<Double, Double> and use floorKey and ceilingKey to find the bounding values. Assuming that you use a TreeMap, this has the same complexity as binary search.
For small numbers of bins a sorted linked list will be most elegant. You scan over it and when you find a number bigger you have the range.
For very large numbers it is worth putting them in a BTree or similar Tree structure in order to get O(log(N)) performance.
In Java you can use a TreeSet for this.
lowerBound = boundaries.headSet(yourNumber).last();
upperBound = boundaries.tailSet(yourNumber).first();
or similar will be O(logN) for large numbers.