I am generating a box and whisker chart with one item per category.I also want to generate a report with the mean, median and all the values per item in the BoxPlot. So, after i create the dataset, defaultboxandwhiskercategorydataset based on the categoryType, I call the method convertReportData to fetch each item in the defaultboxandwhiskercategorydataset and save the mean, median etc into another data object later for report generation. But it just prints only one category. Could anyone please help me to figure out what is wrong?
My boxplot
Code:
public static BoxAndWhiskerCategoryDataset createDataset() {
startTime = inputData.getItimeFrom();
endTime = inputData.getItimeTo();
List<String> categorylist = new ArrayList<>();
categorylist.add("Distance 0-20");
categorylist.add("Distance 20-40");
categorylist.add("Distance 40-60");
categorylist.add("Distance 60-80");
categorylist.add("Distance 80-100");
categorylist.add("Distance >100");
Map<String, List<Double>> map = new HashMap<String, List<Double>>();
map = addDistance(values_list);
DefaultBoxAndWhiskerCategoryDataset defaultboxandwhiskercategorydataset = new DefaultBoxAndWhiskerCategoryDataset();
for (String categoryType : categorylist) {
map.remove(null);
for (Map.Entry<String, List<Double>> entry : map.entrySet()) {
if (entry.getKey().equalsIgnoreCase(categoryType)) {
defaultboxandwhiskercategorydataset.add(entry.getValue(),
categoryType, " ");
}
}
}
convertReportData(defaultboxandwhiskercategorydataset, categorylist);
return defaultboxandwhiskercategorydataset;
}
private static void convertReportData(DefaultBoxAndWhiskerCategoryDataset boxandwhiskercategorydataset, List<String> latencyTypelist) {
report = new HashMap<>();
for (int i = 0; i < boxandwhiskercategorydataset.getColumnKeys().size(); i++) {
BoxAndWhiskerItem item = boxandwhiskercategorydataset.getItem(i, 0);
ReportData data = new ReportData();
data.setMean(item.getMean());
data.setMedian(item.getMedian());
data.setQ1(item.getQ1());
data.setQ3(item.getQ3());
data.setMaxOutlier(item.getMaxOutlier());
data.setMaxRegularNumber(item.getMaxRegularValue());
data.setMinOutlier(item.getMinOutlier());
data.setMinRegularNumber(item.getMinRegularValue());
data.setOutliers(item.getOutliers());
report.put(boxandwhiskercategorydataset.getRowKey(i).toString(),
data);
}
}
The problem is with
for (int i = 0; i < boxandwhiskercategorydataset.getColumnKeys().size(); i++) {
you are using getColumnKeys whereas you have only one Column. It should have been,
for (int i = 0; i < boxandwhiskercategorydataset.getRowKeys().size(); i++) {
Related
I have a json file that contains 500k Objects and this is its format:
"WORKORDER": [
{
"Attributes": {
"SITEID": {
"content": "BEDFORD"
},
"WONUM": {
"content": "1000"
},
"WOPRIORITY": {
"content": 2
},
"WORKTYPE": {
"content": "CM"
}
}
},
{
"Attributes": {
"SITEID": {
"content": "BEDFORD"
},
"WONUM": {
"content": "1000-10"
},
"WORKTYPE": {
"content": "CM"
}
}
}
Im geting the distinct values like this :
for (int i = 0; i < WORKORDER.length(); i++) {
JSONObject obj = WORKORDER.getJSONObject(i);
JSONObject att = obj.getJSONObject("Attributes");
if( att.has(col)){ // getting col from params in the servlet
JSONObject column = att.getJSONObject(col);
Object colval = column.get("content");
if(!(list.contains(colval))) {
out.println( colval);
list.add(colval);
}
But it takes long time for only 5000 objects !
Is there any way to get the distinct values of any column without parsing the whole Json file, otherwise parsing only the column needed.
You are iterating on a JSON with 500k elements. For each element you check if it was previously added in a List. That means your logic will iterate the list 500k times.
Instead, you should use a HashSet, first, the Set prevent duplicated value. So you just need to set.add(value) but the most interesting is the fact that the instance have a constant complexity value. Since it used buckets to organize the value, it doesn't have to iterate the Set fully.
You can read more about that in amit answer's about How can a HashSet offer constant time add operation?
Note that HashSet gives amortized and average time performance of O(1), not worst case. This means, we can suffer an O(n) operation from time to time.
So, when the bins are too packed up, we just create a new, bigger array, and copy the elements to it.
Note that to use any Hash#### implementation, you need to make sure the instance you store implements hashCode and equals correctly. You can find out more about this in the community post about What issues should be considered when overriding equals and hashCode in Java?.
Now for the solution :
Set<Object> sets = new HashSet<>();
for (int i = 0; i < WORKORDER.length(); i++) {
// ...
Object colval = column.get("content");
if(sets.add(colval)){ //`add` return true if it wasn't present already.
out.println( colval);
}
}
I kept the Object type but this should be correctly typed, at least to be sure that those instance are implementing those methods as needed.
colval being an Object, it is possible it doesn't implements correctly the methods needed so I suggest you parse it correctly. You should use column.getString("content) instead or check the instance type.
To validate this, I have used a method to create a fake JSON:
public static JSONObject createDummyJson(int items) {
JSONObject json = new JSONObject();
JSONArray orders = new JSONArray();
json.put("order", orders);
JSONObject attributes;
JSONObject item;
JSONObject order;
Random rand = new Random();
String[] columns = {"columnA", "columnB", "columnC", "columnD"};
for(int i = 0; i < items; ++i) {
order = new JSONObject();
attributes = new JSONObject();
order.put("Attributes", attributes);
orders.put(order);
for(int j = 0; j < rand.nextInt(1000) % columns.length; ++j) {
item= new JSONObject();
long rValue = rand.nextLong();
item.put("content", j%3 == 0 ? ("" + rValue ) : rValue );
attributes.put(columns[j], item);
}
}
return json;
}
Then ran a basic benchmark for both method and had the following results :
public static void main(String[] args) throws Exception {
final int jsonLength = 500_000;
JSONObject json = createDummyJson(jsonLength);
long start = System.currentTimeMillis();
List<Object> list = parseJson(json);
long end = System.currentTimeMillis();
System.out.format("List - Run in %d ms for %d items and output %d lines%n", end-start, jsonLength, list.size());
start = System.currentTimeMillis();
Set<Object> set = parseJsonSet(json);
end = System.currentTimeMillis();
System.out.format("Set - Run in %d ms for %d items and output %d lines%n", end-start, jsonLength, set.size());
}
public static List<Object> parseJson(JSONObject json) {
String col = "columnC";
JSONArray array = json.getJSONArray("order");
List<Object> list = new ArrayList<>();
for (int i = 0; i < array.length(); i++) {
JSONObject obj = array.getJSONObject(i);
JSONObject att = obj.getJSONObject("Attributes");
if (att.has(col)) { // getting col from params in the servlet
JSONObject column = att.getJSONObject(col);
Object colval = column.get("content");
if (!(list.contains(colval))) {
//System.out.println(colval);
list.add(colval);
}
}
}
return list;
}
public static Set<Object> parseJsonSet(JSONObject json) {
String col = "columnC";
JSONArray array = json.getJSONArray("order");
Set<Object> set = new HashSet<>();
for (int i = 0; i < array.length(); i++) {
JSONObject obj = array.getJSONObject(i);
JSONObject att = obj.getJSONObject("Attributes");
if (att.has(col)) { // getting col from params in the servlet
JSONObject column = att.getJSONObject(col);
Object colval = column.get("content");
if (set.add(colval)) {
//System.out.println(colval);
}
}
}
return set;
}
List - Run in 5993 ms for 500000 items and output 46971 lines
Set - Run in 62 ms for 500000 items and output 46971 lines
I even went to a JSON with 5M row (removed the List that would never end)
Set - Run in 6436 ms for 5000000 items and output 468895 lines
Important, remove the line that print in console every new insertion, it will reduce the execution time a bit.
I've got big problem with visualiation of arff files in javaFX table view. My code :
ArffLoader loader = new ArffLoader();
loader.setFile(arff);
Instances data = loader.getDataSet();
List<TableColumn<Instance, String>> atrributes = new ArrayList<>();
for (int i = 0; i < data.numAttributes(); i++) {
atrributes.add(new TableColumn<Instance,String>` (data.attribute(i).name()));
}
List <Instance> instances = new ArrayList<>();
for (int i =0;i<data.size();i++)
{
instances.add(data.get(i));
}
ObservableList<Instance> tableContent = FXCollections.observableArrayList(instances);
table.getColumns().removeAll();
table.getColumns().addAll(atrributes);
table.setItems(tableContent);
table.setVisible(true);
Names of columns(attributes) are set properly but contest is not shwon(tableContent variable)
You need to set a cell value factory for each table column. This is a function that maps the Instance in each row to the value to be displayed in the corresponding cell in that column.
I am not familiar with Weka, but looking at the Javadocs, I think you need
for (int i = 0; i < data.numAttributes(); i++) {
TableColumn<Instance, String> column
= new TableColumn<Instance,String>(data.attribute(i).name());
final int attIndex = i ;
column.setCellValueFactory(cellData ->
new SimpleStringProperty(cellData.getValue().toString(attIndex)));
atrributes.add(column);
}
So I have an object(Drink) with a Map of ingredients and I want to go through a List of them.
I would like to find any Drink that as only the ingredients I search for, and not ones that have any other ingredients.
drinkA.ingredients("water","sugar","salt")
drinkB.ingredients("sugar","salt")
drinkC.ingredients("water")
drinkD.ingredients("sugar")
drinkE.ingredients("salt")
drinkF.ingredients("water","sugar")
drinkG.ingredients("water","salt")
So if I search for water and salt I want to see
drinkC
drinkE
drinkG
This is what I have but it only gives me Drinks with the ingredients I've searched for and more.
public void findSearchResults(String searchRegex, Gui gui) {
if(searchRegex.equals("") || searchRegex == null){
return;
}
List<String> multiSearch = new ArrayList<String>();
if(searchRegex.contains(",")){
multiSearch = Arrays.asList(searchRegex.split(","));
}else{
multiSearch.add(searchRegex);
}
int originSize = multiSearch.size();
gui.drinksToDisplay = new ArrayList<Drink>();
for(Drink d : allDrinks){
int regexIn = 0;
List<String> tempStrs = new ArrayList<String>();
tempStrs.addAll(multiSearch);
if(gui.searchStyle.equals("Has only Ingredients")){
Map<String, String> ingreds = d.getIngredients();
Set<Entry<String, String>> ingredsSet = ingreds.entrySet();
Iterator<Entry<String, String>> ingredsIter = ingredsSet.iterator();
while(ingredsIter.hasNext()){
Entry<String, String> e = ingredsIter.next();
for(String s : tempStrs){
if(e.getKey().toLowerCase().contains(s.toLowerCase())){
tempStrs.remove(s);
regexIn++;
break;
}
}
if(regexIn == originSize && tempStrs.isEmpty()){
gui.drinksToDisplay.add(d);
break;
}
}
}
}
}
edit: I added some more code and a little more information on what I want to acomplish
I want to create a nested array like in php. But someone told it is not available in Java and tell to use map and hash map. So I have tried following to accomplish this issue
List<WebElement> address = driver.findElements(By.xpath(addressXpath));
List<WebElement> addressPrimaryList = driver.findElements(By.xpath(addressPrimaryXpath));
List<WebElement> addressSecondryList = driver.findElements(By.xpath(addressSecondryXpath));
List<WebElement> addressLocationList = driver.findElements(By.xpath(addressLocationXpath));
Map<String, String> addresses = new HashMap<String, String>();
Map<String, String> addressesParent = new HashMap<String, String>();
int totalAdd = address.size();
System.out.println("Total addresses are " + totalAdd);
for (int i = 0; i < totalAdd; i++) {
addressesParent.put("'" + i + "'", addresses.put("addressPrimary", addressPrimaryList.get(i).getText()));
addressesParent.put("'" + i + "'", addresses.put("addressSecondry", addressSecondryList.get(i).getText()));
addressesParent.put("'" + i + "'", addresses.put("addressLocation", addressLocationList.get(i).getText()));
}
// addresses.get("addressPrimary"); // returns "addressPrimary value"
System.out.println(addresses.toString());
System.out.println(addressesParent.toString());
It gives me following results
{addressSecondry=Apt B, addressLocation=Merrick, NY 11566-3559, addressPrimary=1964 Stuyvesant Ave}
{'0'=null, '1'=Merrick, NY 11566-4523}
But I want results like some thing in php
Note: following php code is just example I want to something similar
$addresses[0]['primary'] = $primaryaddress;
$addresses[0]['secondy'] = $secondryaddress;
$addresses[0]['location'] = $locationaddress;
$addresses[1]['primary'] = $primaryaddress;
$addresses[1]['secondy'] = $secondryaddress;
$addresses[1]['location'] = $locationaddress;
I think you are making the wrong approach. You should encapsulate the data in an object and create a list (or array) of these objects. Like:
public class Address {
private String addressPrimary, addressSecondry, addressLocation;
public void setAddressPrimary(String ap) {
addressPrimary = ap;
}
public String getAddressPrimary() {
return addressPrimary;
}
public void setAddressSecondry(String as) {
addressSecondry = as;
}
public String getAddressSecondry() {
return addressSecondry;
}
public void setAddressLocation(String al) {
addressLocation = al;
}
public String getAddressLocation() {
return addressLocation;
}
}
Merged with your code it would look like:
List<WebElement> address = driver.findElements(By.xpath(addressXpath));
List<WebElement> addressPrimaryList = driver.findElements(By.xpath(addressPrimaryXpath));
List<WebElement> addressSecondryList = driver.findElements(By.xpath(addressSecondryXpath));
List<WebElement> addressLocationList = driver.findElements(By.xpath(addressLocationXpath));
int totalAdd = address.size();
System.out.println("Total addresses are " + totalAdd);
List<Address> addresses = new ArrayList<>();
for (int i = 0; i < totalAdd; i++) {
Address address = new Address();
address.setAddressPrimary(addressPrimaryList.get(i).getText());
address.setAddressSecondry(addressSecondryList.get(i).getText());
address.setAddressLocation(addressLocationList.get(i).getText());
addresses.add(address);
}
You would access the data like following:
addresses.get(0).getAddressPrimary();
// ^ ^
// | |
// Returns an Address object
// |
// Returns the addressPrimary property
You could also work with maps but I think that it is bad style and the wrong approach:
List<WebElement> address = driver.findElements(By.xpath(addressXpath));
List<WebElement> addressPrimaryList = driver.findElements(By.xpath(addressPrimaryXpath));
List<WebElement> addressSecondryList = driver.findElements(By.xpath(addressSecondryXpath));
List<WebElement> addressLocationList = driver.findElements(By.xpath(addressLocationXpath));
int totalAdd = address.size();
System.out.println("Total addresses are " + totalAdd);
List<Map<String, String> addresses = new ArrayList<>();
for (int i = 0; i < totalAdd; i++) {
Map<String, String> address = new HashMap<>();
address.put("addressPrimary", addressPrimaryList.get(i).getText());
address.put("addressSecondry", addressSecondryList.get(i).getText());
address.put("addressLocation", addressLocationList.get(i).getText());
addresses.add(address);
}
Then you access data with:
addresses.get(0).get("addressPrimary");
I don't recommend this.
I'm using an ExpandableListView to get an expandable list. I have 3 expandable "parent" lists: Price, Details, Notes. I want to be able to add unique child lists for each parent list. But the way its set up now, the same child list is being added for each parent list. How do I make it so I can add unique, separate child lists for Price, Details, and Notes?
Here is my code:
public class Assignment extends ExpandableListActivity {
int listFlag = 0;
#SuppressWarnings("unchecked")
public void onCreate(Bundle savedInstanceState) {
try{
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_assignment);
SimpleExpandableListAdapter expListAdapter =
new SimpleExpandableListAdapter(
this,
createGroupList(), // Creating group List.
R.layout.group_row, // Group item layout XML.
new String[] { "Group Item" }, // the key of group item.
new int[] { R.id.row_name }, // ID of each group item.-Data under the key goes into this TextView.
createChildList(), // childData describes second-level entries.
R.layout.child_row, // Layout for sub-level entries(second level).
new String[] {"Sub Item"}, // Keys in childData maps to display.
new int[] { R.id.grp_child} // Data under the keys above go into these TextViews.
);
setListAdapter( expListAdapter ); // setting the adapter in the list.
}catch(Exception e){
System.out.println("Errrr +++ " + e.getMessage());
}
}
//Create Headings of Assignment attributes
private List createGroupList() {
ArrayList result = new ArrayList();
//Create string array for Topic headings
String[] topics = {"Price", "Details", "Notes"};
//Iterate through array of names to lay them out correctly
for( int i = 0 ; i < 3 ; ++i ) {
listFlag = i;
HashMap m = new HashMap();
m.put( "Group Item", topics[i] ); // the key and it's value.
result.add( m );
}
return (List)result;
}
#SuppressWarnings("unchecked")
private List createChildList() {
ArrayList result = new ArrayList();
for( int i = 0 ; i < 3 ; ++i ) { // this -15 is the number of groups(Here it's fifteen)
/* each group need each HashMap-Here for each group we have 3 subgroups */
ArrayList secList = new ArrayList();
for( int n = 0 ; n < 1 ; n++ ) {
HashMap child = new HashMap();
child.put( "Sub Item", " "test"));
secList.add( child );
}
result.add( secList );
}
return result;
}
Android does not support nested listviews.
Your createChildList needs to return a List<ArrayList<HashMap<String, String>>>.
Your createChildList should look something like this:
private List<ArrayList<HashMap<String, String>>> createChildList(int maxValue) {
ArrayList<ArrayList<HashMap<String, String>>> groupList =
new ArrayList<ArrayList<HashMap<String, String>>>();
for (int i = 0; i <= maxValue; i++) {
ArrayList<HashMap<String, String>> childList =
new ArrayList<HashMap<String, String>>();
for (int j = 0; j <= maxValue; j++) {
HashMap<String, String> map = new HashMap<String, String>();
map.put("Sub Item", "test: " + String.valueOf(j));
childList.add(map);
}
groupList.add(childList);
}
return groupList;
}
Let me know if that works.