Search code examples
javarangewebshop

Generate Price-Ranges in Java from Big-Integer-List


I hava a list of Products, which have a Price as a BigInteger. I want to create dynamic price-ranges to filter the product-search, like google does on google.com/shopping:

dynamic price ranges from google shopping

How do i calculate good dynamic price ranges from the given list of items/prices? I tried google but couldn't find any good results or any solution at all! I do NOT want to define Ranges by hand and simply add the prices to the given ranges....

I appreciate your help!


Solution

  • You have to filter your products, e.g. with the Java 8 Streaming API (if Java 8 is available):

    List<Product> results = new ArrayList();    
    products.stream().filter(p -> p.getPrice() > minPrice && p.getPrice() < maxPrice).forEach(results::add);
    

    Of course, at the end of the Stream, you could do .forEach(this::output); instead.

    If you need Support for older Versions, the equivalent would be a for loop:

    for(Product p : products){
       if(p.getPrice() > minPrice && p.getPrice() < maxPrice)
          this.output(p); //or add to a list
    }
    

    You can of course wrap it up as a method:

    public static List<Product> filterProducts(BigInteger minPrice, BigInteger maxPrice){
       List<Product> results = new ArrayList();    
       products.stream().filter(p -> p.getPrice() > minPrice && p.getPrice() < maxPrice).forEach(results::add);
       return results;
    }
    

    Find ranges

    If you have 30 items you want to divide into 3 ranges, you want your ranges to be price of the lowest - somewhere between price of the tenth lowest and price of the eleventh lowest.

    let's assume you already sorted your list somehow:

    double[] calcRanges(List<Product> sortedProducts, int count){
        double result = new double[count + 1];
        result[0] = 0;
        for(int i = 1; i < result.length; i++) {
            int pos = (sortedProducts.getSize() * i) / count;
            result[i] = sortedProducts.get(pos).getPrice();
        }
    }
    

    The Problem is, you will get ranges like 2.99 - 3.49 / 3.49 - 12.35 etc.

    That means that you will need to "round" prices. You can either make a static list of allowed range starts / ends and seek the next biggest range end:

    double[] allowedRangeEnds = {0,1,5,10,20,50,100,200,500,1000,2000,5000,10000};
    
    //returns the smalles allowed rangeend which is > value
    double getNextRangeEnd(double value){
        int i = 0;
        while(allowedRangeEnds[i] < value && i < allowedRangeEnds.length - 1){
            i++;
        }
        return allowedRangeEnds[i];
    }
    

    You could of course generate your ranges, in case your prices skyrocket and you don't want to change your static ranges:

    List<Double> calcRangeEnds(double maxValue) {
        List<Double> result = new ArrayList<Double>();
        double base = 1;
        while(base / 2 <= maxValue) { //the last value added is base / 2
            result.add(base);
            result.add(base * 2);
            result.add(base * 5);
            base *= 10;
        }
        return result;
    }