Java tutorial
/* * To change this license header, choose License Headers in Project Properties. * To change this template file, choose Tools | Templates * and open the template in the editor. */ package zappos; import java.io.IOException; import java.net.*; import java.io.*; import java.util.Vector; import java.util.HashMap; import java.util.Iterator; import java.util.Map; import java.util.Scanner; import java.util.Set; import java.util.TreeMap; import org.json.JSONArray; import org.json.JSONObject; /** * * @author vigneshiyer */ /* This class consists of all the methods to find the gift options for a given price and number of products. */ class ZapposProblemSolver { private final String DEVELOPER_KEY = "&key=52ddafbe3ee659bad97fcce7c53592916a6bfd73"; //sort value in the Zappos API call private final String SORT_PARAMS_ASC = "&sort={\"price\":\"asc\"}"; //limit value in the Zappos API call private final String MAX_RESULTS = "&limit=100"; private final int MAX_RESPONSE = 100; //count of how many calls have been made to the API. For efficiency purposes. private int totalAPICalls = 0; private int PAGE_NO = 1; //excludes value in the Zappos API call private final String EXCLUDE_PARAMS = "&excludes=[\"originalPrice\",\"styleId\",\"productUrl\",\"productId\",\"thumbnailImageUrl\",\"brandName\",\"colorId\",\"percentOff\"]"; //base_url value in the Zappos API call private final String BASE_URL = "http://api.zappos.com/Search?term="; //facets value in the Zappos API call private final String PRICE_FACET = "&facets=[\"price\"]"; //excludes results value in the Zappos API call private final String EXCLUDE_RESULTS = "&excludes=[\"results\"]"; private String API_URL, statusCode; //flag is true if the totalResultCount is obtained by API private boolean totalResultsFlag = false; private URL url; private URLConnection urlConnection; private int totalResultCount; JSONObject root; JSONArray results, values, facets; BufferedReader in; // Stores the unique Zappos product prices as the key and the #of products as the value. TreeMap<Double, Integer> priceList = new TreeMap<Double, Integer>(); // Stores the unique Zappos product prices as the key and the cumulative count of products as the value. //this is used for direct calculation of page number in which the product of desired price is found. TreeMap<Double, Integer> cumulativepriceList = new TreeMap<Double, Integer>(); //This stores the combinations of product price possible for a given amount and # of products. Vector<Double[]> priceCombinations; //This stores the unique produt prices of the priceCombinations calculated Vector<Double> productPrice = new Vector<>(); //This stores the product price as key and all the product names available for this price as the key. HashMap<Double, String[]> products = new HashMap<>(); /* This method initializes the required variables and objects. */ public boolean initialize() { try { System.out.println("Getting product counts using price facet"); API_URL = BASE_URL + DEVELOPER_KEY + PRICE_FACET + EXCLUDE_RESULTS; //System.out.println(API_URL); url = new URL(API_URL); urlConnection = url.openConnection(); totalAPICalls++; in = new BufferedReader(new InputStreamReader(urlConnection.getInputStream())); String input; StringBuilder strBuilder = new StringBuilder(); while ((input = in.readLine()) != null) strBuilder.append(input); System.out.println("Response received. Parsing data"); root = new JSONObject(strBuilder.toString()); if (root != null && (statusCode = root.getString("statusCode")) != null && Integer.parseInt(statusCode) == 200) { facets = (JSONArray) root.get("facets"); values = (JSONArray) ((JSONObject) facets.get(0)).get("values"); //System.out.println(values.length()); //populating the priceList Integer sum = new Integer(0); for (int i = 0; i < values.length(); i++) { priceList.put((Double) values.getJSONObject(i).getDouble("name"), (Integer) values.getJSONObject(i).getInt("count")); } // calculate cumulative count System.out.println("Calculating cumulative counts for each product"); Set set = priceList.entrySet(); Iterator iterator = set.iterator(); while (iterator.hasNext()) { Map.Entry me2 = (Map.Entry) iterator.next(); sum += (Integer) me2.getValue(); cumulativepriceList.put((Double) me2.getKey(), sum); } } else { System.out.println("Zappos API returned no/invalid response for your query."); return false; } } catch (MalformedURLException ex) { System.out.println("Invalid URL"); return false; } catch (IOException ex) { System.out.println("URLConnection failed to open"); return false; } catch (Exception ex) { System.out.println("Exception occured! " + ex.getMessage()); return false; } return true; } /* This method calculates all the price combinations for the given amount */ public void getPriceCombinations(int n, double sum) { double[] arr; if (priceList.size() > sum) arr = new double[priceList.size()]; else arr = new double[(int) sum]; int pos = 0; for (Map.Entry<Double, Integer> entrySet : priceList.entrySet()) { if (entrySet.getKey() <= sum) arr[pos++] = entrySet.getKey(); else break; } double[] p = new double[pos + 1]; priceCombinations = new Vector<>(); System.out.println("Calculating all possible price combinations for sum " + sum); compute(arr, p, 0, 0, pos, sum, n); System.out.println("Price combinations successfully calculated. (Total# " + priceCombinations.size()); for (int i = 0; i < priceCombinations.size(); i++) { for (int j = 0; j < n; j++) { Double obj = priceCombinations.get(i)[j]; if (!productPrice.contains(obj)) productPrice.add(obj); } } //System.out.println(productPrice.size()); } /* This method recursively calls to get the price combinations */ public void compute(double[] arr, double[] p, int index, int low, int high, double sum, int n) { //System.out.println(index); if ((sum < 0) || (low > high) || index > n) return; if (sum <= 0.01 && index == n) { Double[] temp = new Double[n]; for (int i = 0; i < index; i++) { temp[i] = p[i]; //System.out.print(p[i]+" "); } //System.out.println(); priceCombinations.add(temp); return; } p[index] = arr[low]; compute(arr, p, index + 1, low + 1, high, sum - arr[low], n); compute(arr, p, index, low + 1, high, sum, n); } /* This method gets the Zappos product details */ public void getZapposProductDetails() { int size = productPrice.size(); System.out.println("Calling Zappos API to fetch the products based on price with search term as blank."); for (int i = 0; i < size; i++) { //get the page number Double obj = productPrice.get(i); int page = cumulativepriceList.get(obj) / 100 + 1; int elementNumber = cumulativepriceList.get(obj) % 100 - 1; int count = priceList.get(obj); try { String[] productNames = new String[count]; int pos = 0; while (count > 0) { //call api to get data API_URL = BASE_URL + DEVELOPER_KEY + SORT_PARAMS_ASC + MAX_RESULTS + "&page=" + Integer.toString(page) + EXCLUDE_PARAMS; url = new URL(API_URL); urlConnection = url.openConnection(); System.out.println("Directly calling Zappos API (Page# " + page + ") to get price for products with price $" + obj); totalAPICalls++; in = new BufferedReader(new InputStreamReader(urlConnection.getInputStream())); String input; StringBuilder strBuilder = new StringBuilder(); int j; while ((input = in.readLine()) != null) strBuilder.append(input); root = new JSONObject(strBuilder.toString()); //System.out.println(root.getString("statusCode")); if (root != null && (statusCode = root.getString("statusCode")) != null && Integer.parseInt(statusCode) == 200) { for (j = elementNumber; j >= 0 && count > 0; j--) { //System.out.println(results.length()); JSONArray result = ((JSONArray) root.get("results")); JSONObject ele = (JSONObject) result.getJSONObject(j); productNames[pos++] = ele.getString("productName"); //System.out.println(str); count--;//sum+=Double.parseDouble(str.substring(1)); } if (count > 0) { page--; elementNumber = MAX_RESPONSE - 1; } else elementNumber = j + 1; } else break; } products.put(obj, productNames); /*System.out.println(elementNumber); JSONArray result = ((JSONArray)root.get("results")); JSONObject ele = (JSONObject)result.getJSONObject(elementNumber); String str = ele.getString("productName")+" "+ele.getString("price").replace(",", ""); System.out.println(str);*/ } catch (MalformedURLException ex) { System.out.println("Invalid URL"); } catch (IOException ex) { System.out.println("URLConnection failed to open"); } catch (Exception ex) { System.out.println("Exception occured! " + ex.getMessage()); } //break; } //calculate totalResultCount if (root.get("totalResultCount") != null) { totalResultCount = Integer.parseInt((String) root.get("totalResultCount")); totalResultsFlag = true; } } /* Display the gift options */ public void displayZapposProducts() { System.out.println("\n"); System.out.println("Displaying gift options from Zappos for your input"); int size = priceCombinations.size(); System.out.println("There are in total " + size + " no of options available."); double sum = 0; for (int i = 0; i < size; i++) { sum = 0; System.out.println(); System.out.println("**** OPTION " + (i + 1) + " ****"); Double[] arr = priceCombinations.get(i); for (int j = 0; j < arr.length; j++) { sum += arr[j]; System.out.println("For $" + arr[j] + " you can buy,"); String[] productNames = products.get(arr[j]); for (int k = 0; k < productNames.length; k++) { if (k == productNames.length - 1) System.out.println("(" + productNames[k] + ")"); else System.out.println("(" + productNames[k] + ") OR "); } if (j != arr.length - 1) System.out.println(" AND "); } System.out.println("Summary: " + arr.length + " order(s) for $" + sum); if ((i + 1) % 10 == 0) { System.out.println("Displayed " + (i + 1) + " options. There are about " + (size - i) + " more options. " + "Press Enter key for more options. Press any key to exit"); String input; Scanner sin = new Scanner(System.in); input = sin.nextLine(); if (!input.equals("")) break; } } System.out.println("Program successfully ended."); if (totalResultsFlag) System.out.println("Some statistics :- The API returned " + totalResultCount + " products in total. For each call, the maximum results obtained is 100.\n" + "Hence there are " + totalResultCount / 100 + " pages. But of these only " + totalAPICalls + " pages were traversed thereby making only " + (totalAPICalls * 100 / (double) totalResultCount) + "% of calls."); } } /* This class contains the main method */ public class Zappos { /** * @param args the command line arguments */ public static void main(String[] args) { ZapposProblemSolver problemSolver = new ZapposProblemSolver(); System.out.println("Enter number of products and total amount "); Scanner sin = new Scanner(System.in); int no_of_products = sin.nextInt(); double total_amount = sin.nextDouble(); if (no_of_products > 0 && total_amount > 0) { if (problemSolver.initialize()) { problemSolver.getPriceCombinations(no_of_products, total_amount); problemSolver.getZapposProductDetails(); problemSolver.displayZapposProducts(); } } else System.out.println("Sorry! No products are found for this input."); } }