I have a problem with a comparator. It works most of the time. I have created a test where it fails but I cannot see why it fails or what is wrong. It fails with the error of: java.lang.IllegalArgumentException: Comparison method violates its general contract!
The general situation is a list of fields from a PDF that are being sorted by page then by the Y position and then by the X position.
I hope someone can point me in the right direction as to why this is failing with the given test data.
import junit.framework.TestCase;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
public class DateUtilsTest extends TestCase {
public void testForDerrick() {
String fields = "null\t\t27.5118\t\t496.989\n" +
"null\t\t121.96\t\t192.52\n" +
"0\t\t79.5814\t\t301.597\n" +
"0\t\t79.5814\t\t264.662\n" +
"0\t\t196.29\t\t429.681\n" +
"0\t\t195.955\t\t314.32\n" +
"0\t\t196.868\t\t277.982\n" +
"0\t\t210.99\t\t429.681\n" +
"0\t\t210.82\t\t277.982\n" +
"0\t\t225.552\t\t429.681\n" +
"0\t\t224.029\t\t277.982\n" +
"0\t\t218.91\t\t198.61\n" +
"0\t\t267.12\t\t340.05\n" +
"0\t\t298.85\t\t346.5\n" +
"0\t\t372.16\t\t384.81\n" +
"null\t\t349.16\t\t346.5\n" +
"0\t\t549.35\t\t188.459\n" +
"0\t\t626.48\t\t457.041\n" +
"0\t\t649.28\t\t511.764\n" +
"0\t\t647.456\t\t503.618\n" +
"0\t\t647.456\t\t477.432\n" +
"0\t\t658.659\t\t539.6\n" +
"0\t\t658.659\t\t477.432\n" +
"0\t\t701.73\t\t474.041\n" +
"0\t\t712.98\t\t474.041\n" +
"0\t\t626.48\t\t121.0\n" +
"0\t\t626.48\t\t41.0\n" +
"0\t\t662.44\t\t117.0\n" +
"0\t\t673.611\t\t117.0\n" +
"0\t\t687.52\t\t117.0\n" +
"0\t\t700.73\t\t117.0\n" +
"0\t\t712.98\t\t117.0\n" +
"0\t\t787.169\t\t150.654\n" +
"null\t\t123.57\t\t532.77\n" +
"1\t\t35.6173\t\t92.42\n" +
"1\t\t47.83\t\t515.0\n" +
"1\t\t47.83\t\t369.25\n" +
"1\t\t76.5\t\t441.88\n" +
"1\t\t76.5\t\t368.85\n" +
"null\t\t123.57\t\t417.02\n" +
"1\t\t99.03\t\t515.0\n" +
"1\t\t99.03\t\t441.88\n" +
"1\t\t99.03\t\t369.25\n" +
"1\t\t99.03\t\t53.2\n" +
"1\t\t109.29\t\t515.0\n" +
"1\t\t109.29\t\t441.88\n" +
"1\t\t109.29\t\t369.25\n" +
"1\t\t109.29\t\t53.2\n" +
"1\t\t119.56\t\t515.0\n" +
"1\t\t119.56\t\t441.88\n" +
"1\t\t119.56\t\t369.25\n" +
"1\t\t119.56\t\t53.2\n" +
"1\t\t129.83\t\t515.0\n" +
"1\t\t129.83\t\t441.88\n" +
"1\t\t129.83\t\t369.25\n" +
"1\t\t129.83\t\t53.2\n" +
"1\t\t140.09\t\t515.0\n" +
"1\t\t140.09\t\t441.88\n" +
"1\t\t140.09\t\t369.25\n" +
"1\t\t140.09\t\t53.2\n" +
"1\t\t150.36\t\t515.0\n" +
"1\t\t150.36\t\t441.88\n" +
"1\t\t150.36\t\t369.25\n" +
"1\t\t150.36\t\t53.2\n" +
"1\t\t160.62\t\t515.0\n" +
"1\t\t160.62\t\t441.88\n" +
"1\t\t160.62\t\t369.25\n" +
"1\t\t160.62\t\t53.2\n" +
"1\t\t171.319\t\t515.0\n" +
"1\t\t171.319\t\t441.88\n" +
"1\t\t171.319\t\t369.25\n" +
"1\t\t171.319\t\t53.2\n" +
"1\t\t180.464\t\t401.15\n" +
"1\t\t192.194\t\t514.83\n" +
"1\t\t192.194\t\t441.71\n" +
"1\t\t192.194\t\t369.08\n" +
"1\t\t202.464\t\t514.83\n" +
"1\t\t202.464\t\t441.71\n" +
"1\t\t202.464\t\t369.08\n" +
"1\t\t202.464\t\t53.0295\n" +
"1\t\t212.724\t\t514.83\n" +
"1\t\t212.724\t\t441.71\n" +
"1\t\t212.724\t\t369.08\n" +
"1\t\t212.724\t\t53.0295\n" +
"1\t\t222.994\t\t514.83\n" +
"1\t\t222.994\t\t441.71\n" +
"1\t\t222.994\t\t369.08\n" +
"1\t\t222.994\t\t53.0295\n" +
"1\t\t233.254\t\t514.83\n" +
"1\t\t233.254\t\t441.71\n" +
"1\t\t233.254\t\t369.08\n" +
"1\t\t233.254\t\t53.0295\n" +
"1\t\t243.564\t\t514.83\n" +
"1\t\t243.564\t\t441.71\n" +
"1\t\t243.564\t\t369.08\n" +
"1\t\t243.564\t\t242.83\n" +
"1\t\t243.564\t\t136.83\n" +
"1\t\t253.874\t\t514.83\n" +
"1\t\t253.874\t\t441.71\n" +
"1\t\t253.874\t\t369.08\n" +
"1\t\t253.874\t\t242.83\n" +
"1\t\t253.874\t\t136.83\n" +
"1\t\t264.264\t\t514.83\n" +
"1\t\t264.264\t\t441.71\n" +
"1\t\t264.264\t\t369.08\n" +
"1\t\t264.264\t\t242.83\n" +
"1\t\t264.264\t\t136.83\n" +
"1\t\t274.154\t\t400.98\n" +
"1\t\t285.485\t\t515.0\n" +
"1\t\t285.485\t\t441.444\n" +
"1\t\t285.485\t\t369.25\n" +
"1\t\t285.485\t\t53.2\n" +
"1\t\t295.802\t\t515.0\n" +
"1\t\t295.802\t\t441.444\n" +
"1\t\t295.802\t\t369.25\n" +
"1\t\t295.802\t\t149.84\n" +
"1\t\t295.802\t\t104.36\n" +
"1\t\t305.576\t\t515.0\n" +
"1\t\t305.576\t\t441.444\n" +
"1\t\t305.576\t\t369.25\n" +
"1\t\t305.576\t\t242.29\n" +
"1\t\t305.576\t\t189.18\n" +
"1\t\t305.576\t\t107.88\n" +
"1\t\t316.153\t\t515.0\n" +
"1\t\t316.153\t\t441.444\n" +
"1\t\t316.153\t\t369.25\n" +
"1\t\t316.153\t\t198.06\n" +
"1\t\t316.153\t\t151.58\n" +
"1\t\t326.675\t\t515.0\n" +
"1\t\t326.675\t\t441.444\n" +
"1\t\t326.675\t\t369.25\n" +
"1\t\t326.675\t\t211.5\n" +
"1\t\t326.675\t\t165.02\n" +
"1\t\t336.47\t\t401.15\n" +
"1\t\t347.74\t\t515.0\n" +
"1\t\t347.74\t\t441.88\n" +
"1\t\t347.74\t\t369.25\n" +
"1\t\t347.74\t\t53.2\n" +
"1\t\t358.13\t\t515.0\n" +
"1\t\t358.13\t\t441.88\n" +
"1\t\t358.13\t\t369.25\n" +
"1\t\t358.13\t\t247.9\n" +
"1\t\t358.13\t\t153.0\n" +
"1\t\t368.02\t\t401.15\n" +
"1\t\t400.19\t\t442.787\n" +
"1\t\t400.19\t\t368.25\n" +
"null\t\t123.57\t\t306.57\n" +
"1\t\t423.977\t\t516.463\n" +
"1\t\t423.977\t\t443.343\n" +
"1\t\t423.977\t\t369.713\n" +
"1\t\t423.977\t\t54.6625\n" +
"1\t\t434.237\t\t516.463\n" +
"1\t\t434.237\t\t443.343\n" +
"1\t\t434.237\t\t369.713\n" +
"1\t\t434.237\t\t54.6625\n" +
"1\t\t444.507\t\t516.463\n" +
"1\t\t444.507\t\t443.343\n" +
"1\t\t444.507\t\t369.713\n" +
"1\t\t444.507\t\t54.6625\n" +
"1\t\t454.777\t\t516.463\n" +
"1\t\t454.777\t\t443.343\n" +
"1\t\t454.777\t\t369.713\n" +
"1\t\t454.777\t\t54.6625\n" +
"1\t\t465.037\t\t516.463\n" +
"1\t\t465.037\t\t443.343\n" +
"1\t\t465.037\t\t369.713\n" +
"1\t\t465.037\t\t54.6625\n" +
"1\t\t475.307\t\t516.463\n" +
"1\t\t475.307\t\t443.343\n" +
"1\t\t475.307\t\t369.713\n" +
"1\t\t475.307\t\t54.6625\n" +
"1\t\t485.567\t\t516.463\n" +
"1\t\t485.567\t\t443.343\n" +
"1\t\t485.567\t\t369.713\n" +
"1\t\t485.567\t\t54.6625\n" +
"1\t\t495.837\t\t516.463\n" +
"1\t\t495.957\t\t443.343\n" +
"1\t\t495.957\t\t369.713\n" +
"1\t\t495.957\t\t54.6625\n" +
"1\t\t506.847\t\t402.613\n" +
"1\t\t517.117\t\t516.463\n" +
"1\t\t517.117\t\t443.343\n" +
"1\t\t517.117\t\t369.713\n" +
"1\t\t517.117\t\t54.6625\n" +
"1\t\t527.387\t\t516.463\n" +
"1\t\t527.387\t\t443.343\n" +
"1\t\t527.387\t\t369.713\n" +
"1\t\t527.387\t\t54.6625\n" +
"1\t\t537.647\t\t516.463\n" +
"1\t\t537.647\t\t443.343\n" +
"1\t\t537.647\t\t369.713\n" +
"1\t\t537.647\t\t54.6625\n" +
"1\t\t547.917\t\t516.463\n" +
"1\t\t547.917\t\t443.343\n" +
"1\t\t547.917\t\t369.713\n" +
"1\t\t547.917\t\t54.6625\n" +
"1\t\t558.177\t\t516.463\n" +
"1\t\t558.177\t\t443.343\n" +
"1\t\t558.177\t\t369.713\n" +
"1\t\t558.177\t\t54.6625\n" +
"1\t\t568.447\t\t516.463\n" +
"1\t\t568.447\t\t443.343\n" +
"1\t\t568.447\t\t369.713\n" +
"1\t\t568.447\t\t54.6625\n" +
"1\t\t578.707\t\t516.463\n" +
"1\t\t578.707\t\t443.343\n" +
"1\t\t578.707\t\t369.713\n" +
"1\t\t578.707\t\t54.6625\n" +
"1\t\t588.977\t\t516.463\n" +
"1\t\t588.977\t\t443.343\n" +
"1\t\t588.977\t\t369.713\n" +
"1\t\t588.977\t\t54.6625\n" +
"1\t\t599.237\t\t516.463\n" +
"1\t\t599.237\t\t443.343\n" +
"1\t\t599.237\t\t369.713\n" +
"1\t\t599.237\t\t54.6625\n" +
"1\t\t609.507\t\t516.463\n" +
"1\t\t609.637\t\t443.343\n" +
"1\t\t609.637\t\t369.713\n" +
"1\t\t609.637\t\t54.6625\n" +
"1\t\t620.527\t\t402.613\n" +
"1\t\t630.787\t\t516.463\n" +
"1\t\t630.787\t\t443.343\n" +
"1\t\t630.787\t\t369.713\n" +
"1\t\t630.787\t\t54.6625\n" +
"1\t\t641.057\t\t516.463\n" +
"1\t\t641.057\t\t443.343\n" +
"1\t\t641.057\t\t369.713\n" +
"1\t\t641.057\t\t54.6625\n" +
"1\t\t651.317\t\t516.463\n" +
"1\t\t651.317\t\t443.343\n" +
"1\t\t651.317\t\t369.713\n" +
"1\t\t651.317\t\t54.6625\n" +
"1\t\t661.587\t\t516.463\n" +
"1\t\t661.587\t\t443.343\n" +
"1\t\t661.587\t\t369.713\n" +
"1\t\t661.587\t\t54.6625\n" +
"1\t\t671.847\t\t516.463\n" +
"1\t\t671.847\t\t443.343\n" +
"1\t\t671.847\t\t369.713\n" +
"1\t\t671.847\t\t54.6625\n" +
"1\t\t682.117\t\t516.463\n" +
"1\t\t682.117\t\t443.343\n" +
"1\t\t682.117\t\t369.713\n" +
"1\t\t682.117\t\t54.6625\n" +
"1\t\t692.387\t\t516.463\n" +
"1\t\t692.387\t\t443.343\n" +
"1\t\t692.387\t\t369.713\n" +
"1\t\t692.387\t\t54.6625\n" +
"1\t\t702.777\t\t516.463\n" +
"1\t\t702.777\t\t443.343\n" +
"1\t\t702.777\t\t369.713\n" +
"1\t\t702.777\t\t54.6625\n" +
"1\t\t712.667\t\t402.613\n" +
"2\t\t131.82\t\t494.835\n" +
"2\t\t166.95\t\t334.15\n" +
"2\t\t166.95\t\t311.9\n" +
"2\t\t180.85\t\t334.15\n" +
"2\t\t180.85\t\t311.9\n" +
"2\t\t193.091\t\t334.15\n" +
"2\t\t204.861\t\t334.15\n" +
"2\t\t198.31\t\t311.9\n" +
"2\t\t216.78\t\t334.15\n" +
"2\t\t216.78\t\t311.9\n" +
"2\t\t140.206\t\t286.44\n" +
"2\t\t140.206\t\t250.77\n" +
"null\t\t90.11\t\t192.52\n" +
"null\t\t47.83\t\t440.17\n" +
"null\t\t572.54\t\t197.55\n" +
"2\t\t140.206\t\t224.243\n" +
"2\t\t140.206\t\t188.434\n" +
"2\t\t152.411\t\t190.822\n" +
"2\t\t166.95\t\t191.0\n" +
"2\t\t198.31\t\t191.0\n" +
"2\t\t216.78\t\t191.0\n" +
"null\t\t166.95\t\t254.0\n" +
"2\t\t313.6\t\t501.8\n" +
"2\t\t313.6\t\t57.8\n" +
"2\t\t342.27\t\t501.8\n" +
"2\t\t342.27\t\t57.8\n" +
"2\t\t371.07\t\t501.8\n" +
"2\t\t371.07\t\t57.8\n" +
"2\t\t399.87\t\t501.8\n" +
"2\t\t399.87\t\t57.8\n" +
"2\t\t428.67\t\t501.8\n" +
"2\t\t428.67\t\t57.8\n" +
"2\t\t457.47\t\t501.8\n" +
"2\t\t457.47\t\t57.8\n" +
"2\t\t486.27\t\t501.8\n" +
"2\t\t486.27\t\t57.8\n" +
"2\t\t515.07\t\t501.8\n" +
"2\t\t515.07\t\t57.8\n" +
"2\t\t543.87\t\t501.8\n" +
"2\t\t543.87\t\t57.8\n" +
"2\t\t572.67\t\t501.8\n" +
"2\t\t572.67\t\t57.8\n" +
"2\t\t601.47\t\t501.8\n" +
"2\t\t601.47\t\t57.8\n" +
"2\t\t630.27\t\t501.8\n" +
"2\t\t630.27\t\t57.8\n" +
"2\t\t659.07\t\t501.8\n" +
"2\t\t659.07\t\t57.8\n" +
"2\t\t687.87\t\t501.8\n" +
"2\t\t687.87\t\t57.8\n" +
"2\t\t715.92\t\t501.8\n" +
"2\t\t715.92\t\t57.8\n" +
"3\t\t359.57\t\t394.05\n" +
"3\t\t390.22\t\t394.05\n" +
"3\t\t458.086\t\t545.206\n" +
"3\t\t458.086\t\t478.15\n" +
"3\t\t458.086\t\t317.306\n" +
"3\t\t488.85\t\t394.05\n" +
"3\t\t518.65\t\t394.05\n" +
"3\t\t538.809\t\t435.303\n" +
"3\t\t550.477\t\t435.303\n" +
"3\t\t568.55\t\t394.05\n" +
"3\t\t581.219\t\t436.03\n" +
"3\t\t590.989\t\t436.03\n" +
"3\t\t603.112\t\t436.03\n" +
"3\t\t620.3\t\t394.05\n" +
"3\t\t687.503\t\t317.306\n" +
"null\t\t639.63\t\t117.0\n" +
"null\t\t650.984\t\t117.0\n" +
"3\t\t314.184\t\t39.7711\n" +
"3\t\t336.086\t\t39.7711\n" +
"3\t\t358.272\t\t39.7711\n" +
"3\t\t571.296\t\t40.0028\n" +
"3\t\t599.766\t\t39.8304\n" +
"3\t\t621.736\t\t39.8304\n" +
"3\t\t665.499\t\t39.8304\n" +
"3\t\t687.859\t\t39.8304\n" +
"4\t\t115.997\t\t503.877\n" +
"4\t\t115.62\t\t324.0\n" +
"4\t\t115.62\t\t40.5\n" +
"4\t\t121.715\t\t215.873\n" +
"4\t\t188.51\t\t432.749\n" +
"4\t\t200.49\t\t432.75\n" +
"4\t\t220.99\t\t432.75\n" +
"4\t\t233.98\t\t432.75\n" +
"4\t\t244.96\t\t432.75\n" +
"4\t\t255.95\t\t432.75\n" +
"4\t\t266.94\t\t432.75\n" +
"4\t\t278.92\t\t432.75\n" +
"4\t\t288.55\t\t432.75\n" +
"4\t\t299.294\t\t432.749\n" +
"4\t\t312.88\t\t432.75\n" +
"4\t\t321.887\t\t432.75\n" +
"4\t\t188.51\t\t288.75\n" +
"4\t\t200.49\t\t288.75\n" +
"4\t\t220.99\t\t288.75\n" +
"4\t\t233.98\t\t288.75\n" +
"4\t\t244.96\t\t288.75\n" +
"4\t\t255.95\t\t288.75\n" ;
List<TestSort> testSortList = new ArrayList<TestSort>();
String[] fieldList = fields.split("\n");
for (String field : fieldList) {
String[] threeVals = field.split("\t\t");
TestSort df = new TestSort();
df.setPage(!"null".equals(threeVals[0]) ? Integer.valueOf(threeVals[0]) : null);
df.setTopLeftY(Double.valueOf(threeVals[1]));
df.setTopLeftX(Double.valueOf(threeVals[2]));
df.setFormField("");
testSortList.add(df);
}
Collections.sort(testSortList, new Comparator<TestSort>() {
#Override
public int compare(TestSort o1, TestSort o2) {
if (o1.getPage() == null || o2.getPage() == null || o1.getPage().equals(o2.getPage())) {
if (o1.getTopLeftY() == null || o2.getTopLeftY() == null || o1.getTopLeftY().equals(o2.getTopLeftY())) {
if (o1.getTopLeftX() == null || o2.getTopLeftX() == null || o1.getTopLeftX().equals(o2.getTopLeftX())) {
return o1.getFormField().compareTo(o2.getFormField());
} else {
return o1.getTopLeftX().compareTo(o2.getTopLeftX());
}
} else {
return o1.getTopLeftY().compareTo(o2.getTopLeftY());
}
} else {
return o1.getPage().compareTo(o2.getPage());
}
}
});
}
public class TestSort {
private Integer page;
private Double topLeftY;
private Double topLeftX;
private String formField;
public String getFormField() {
return formField;
}
public void setFormField(String formField) {
this.formField = formField;
}
public Integer getPage() {
return page;
}
public void setPage(Integer page) {
this.page = page;
}
public Double getTopLeftY() {
return topLeftY;
}
public void setTopLeftY(Double topLeftY) {
this.topLeftY = topLeftY;
}
public Double getTopLeftX() {
return topLeftX;
}
public void setTopLeftX(Double topLeftX) {
this.topLeftX = topLeftX;
}
}
}
The exception is indicating that this is a non-transitive comparison. I have to agree with Dave Newton's comment that it's hard to reason about this comparator. All the null-checking is confusing, but it seems like the order that things get compared in is not consistent. See Effective Java, Item 12 (Consider Implementing Comparable):
If a class has multiple significant fields, the order in which you compare them is critical. You must start with the most significant field and work your way down. If a comparison results in anything other than zero (which represents equality), you’re done; just return the result. If the most significant fields are equal, go on to compare the next-most-significant fields, and so on. If all fields are equal, the objects are equal; return zero.
Specifically, if you're comparing a null field to a non-null field your code is trying to go on and compare the next most significant field, that means you're taking a case where one field is null and the other isn't, so one ought to sort higher than the other, and you're treating them as if they are equivalent, yet you're going forward with comparing the next most significant fields.
Here's a comparator written to comply with Bloch's advice, that tries to clean up the null-checking; nulls get replaced with a low-sorting value so the ordering will be consistent:
class TestSortComparator implements Comparator<TestSort> {
Double defaultIfNull(Double d) {
return d == null ? Double.NEGATIVE_INFINITY : d;
}
Integer defaultIfNull(Integer i) {
return i == null ? Integer.MIN_VALUE : i;
}
String defaultIfNull(String s) {
return s == null ? "" : s;
}
#Override
public int compare(TestSort o1, TestSort o2) {
int pageComp = defaultIfNull(o1.getPage())
.compareTo(defaultIfNull(o2.getPage()));
if (pageComp != 0) return pageComp;
int yComp = defaultIfNull(o1.getTopLeftY())
.compareTo(defaultIfNull(o2.getTopLeftY()));
if (yComp != 0) return yComp;
int xComp = defaultIfNull(o1.getTopLeftX())
.compareTo(defaultIfNull(o2.getTopLeftX()));
if (xComp != 0) return xComp;
return defaultIfNull(o1.getFormField())
.compareTo(defaultIfNull(o2.getFormField()));
}
}
Nathan's answer correctly summarizes the problem with your Comparator; it is not obeying the contract with regards to the transitivity of comparisons. From the Javadocs of compareTo():
The implementor must also ensure that the relation is transitive:
((compare(x, y) > 0) && (compare(y, z) > 0)) implies
compare(x, z) > 0
It can be difficult to write a null-safe comparator that compares multiple properties of an object -- even more difficult to write an implementation that's actually correct. Checking for nullness and keeping track of the value of the previous comparison makes the code clunky and verbose.
For the reasons mentioned above, it is preferable to utilize a proper framework to make the code more readable and less error-prone. Implementing a fluent Comparator is easy (and fun) with the help of Google Guava's ComparisonChain class. Here's how the Comparator looks like using ComparisonChain:
static class FluentComparator implements Comparator<TestSort> {
#Override
public int compare(TestSort o1, TestSort o2) {
return ComparisonChain
.start()
.compare(o1.getPage(), o2.getPage(),
Ordering.natural().nullsFirst())
.compare(o1.getTopLeftY(), o2.getTopLeftY())
.compare(o1.getTopLeftX(), o2.getTopLeftX())
.compare(o1.getFormField(), o2.getFormField())
.result();
}
}
Note how fluently you can chain the different comparisons into a "one-liner". Also, each comparison in the chain is lazily evaluated (i.e. only if required), making the implementation efficient without needing to write multiple return statements. From the docs:
ComparisonChain performs a "lazy" comparison: it only performs comparisons
until it finds a nonzero result, after which it ignores further input.
You need to be careful with nullable properties, however. As getPage() can return null in your example data, we need to use the overload of compare which accepts nullable inputs and a strategy for handling nulls (nulls first in this case).
Related
I am making a a mini game plugin, i need to replace every blocks that not a type, so i maked this :
public static void replaceBlock(String x, String y, String z, String x2, String y2, String z2, String block, String secondBlockType, String mapDict) {
String[] BlocksToReplace = mapDict.split("\\*");
System.out.println(ConsoleColorUtils.PURPLE + "[" + Main.pName +"]" + ConsoleColorUtils.RESET + " " + x + " " + y + " " + z + " " + x2 + " " + y2 + " " + z2);
ConsoleCommandSender console = Bukkit.getServer().getConsoleSender();
String pos1 = "/pos1 " + x + "," + y + "," + z;
String pos2 = "/pos2 " + x2 + "," + y2 + "," + z2;
Bukkit.dispatchCommand(console, pos1);
Bukkit.dispatchCommand(console, pos2);
tasak = Bukkit.getServer().getScheduler().runTaskTimer(Main.plugin, new Runnable() {
private int count = 2;
#Override
public void run() {
if(count == 0) {
for(String b : BlocksToReplace) {
if(b == block) {
System.out.println(ConsoleColorUtils.PURPLE + "[" + Main.pName +"]" + ConsoleColorUtils.RESET + " fdbshjfbdjshq ");
}else {
String fillcmd = "/replace " + b + " " + secondBlockType;
System.out.println(ConsoleColorUtils.PURPLE + "[" + Main.pName +"]" + ConsoleColorUtils.RESET + " " + fillcmd + " " + block);
Bukkit.dispatchCommand(console, fillcmd);
}
}
tasak.cancel();
} else {
count--;
}
}
}, 20, 20);
}
Map dict is => gold_block*wool:15*stained_hardened_clay:4*wool:4*stained_hardened_clay:3*stained_hardened_clay:11*wool:9*wool:11*stained_hardened_clay:9*wool:10*wool:2*stained_hardened_clay:10*stained_hardened_clay:2*stained_hardened_clay:6*diamond_block*prismarine:2*prismarine:1*melon_block*wool:5*slime*emerald_block*quartz_block*stained_hardened_clay*sandstone:2*nether_brick*wool:14*wool:13
block var is : stained_hardened_clay:14
When i call the function, it replace every blocks not all exept the block i want
Any way to fix it ?
Dont use "==" for strings. use b.equals(block). Because "==" compares the hash values of the String objects. And the equals Method compares the string itself.
More Info: https://www.java67.com/2012/11/difference-between-operator-and-equals-method-in.html
I am using the PDFBox to extract the character coordinates from the read PDF. However, I can't identify the unit of measurement of the value returned by the getXDirAdj () and getYDirAdj () methods?
#Override
protected void processTextPosition(TextPosition text) {
String tChar = text.getCharacter();
System.out.println("String[" + text.getXDirAdj() + ","
+ text.getYDirAdj() + " fs=" + text.getFontSize() + " xscale="
+ text.getXScale() + " height=" + text.getHeightDir() + " space="
+ text.getWidthOfSpace() + " width="
+ text.getWidthDirAdj() + "]" + text.getCharacter());
}
1 unit = 1/72 inch
"how to obtain the rotation of the character read": from the ExtractText.java tool:
static int getAngle(TextPosition text)
{
Matrix m = text.getTextMatrix().clone();
m.concatenate(text.getFont().getFontMatrix());
return (int) Math.round(Math.toDegrees(Math.atan2(m.getShearY(), m.getScaleY())));
}
I have the following:
ArrayList<GregorianCalendar> toRemove = new ArrayList<GregorianCalendar>();
SortedSet<GregorianCalendar> copyKeys = new TreeSet<GregorianCalendar>(MyCalendarTester.myCal.getMyCalHash().keySet());
for(GregorianCalendar remove: toRemove){
copyKeys.removeAll(Collections.singleton(remove));
}
And I am trying to remove every occurrence of the key "remove" in my TreeSet copyKeys. But it only seems to remove one of them. Could someone please tell me what I'm doing wrong? Please let me know if you need more information.
EDIT:
For the sake of it, here is my entire mess of a method (I know it has a few more issues that just the question that I am asking), but here is goes:
public void eventList(){
int year = -1;
GregorianCalendar tempKey = null;
ArrayList<Event> tempArr = new ArrayList<Event>();
ArrayList<GregorianCalendar> toRemove = new ArrayList<GregorianCalendar>();
int countEnd = 0;
if(MyCalendarTester.myCal.getMyCalHash().equals(null)){
System.out.println("Your calendar is empty!");
}
else{
System.out.println("Here are your events: ");
SortedSet<GregorianCalendar> keys = new TreeSet<GregorianCalendar>(MyCalendarTester.myCal.getMyCalHash().keySet());
SortedSet<GregorianCalendar> copyKeys = new TreeSet<GregorianCalendar>(MyCalendarTester.myCal.getMyCalHash().keySet());
tempKey = keys.first();
int countTotal = keys.size();
for(GregorianCalendar key : copyKeys){
GregorianCalendar copyKey = key;
Event value = MyCalendarTester.myCal.getMyCalHash().get(key);
// System.out.println(" key.get(Calendar.MONTH) = " + key.get(Calendar.MONTH));
// System.out.println("(tempKey.get(Calendar.MONTH)) = " + (tempKey.get(Calendar.MONTH)));
// System.out.println(" key.get(Calendar.DATE) = " + key.get(Calendar.DATE));
// System.out.println(" tempKey.get(Calendar.DATE) = " + (tempKey.get(Calendar.DATE)));
tempArr.add(value);
countEnd++;
if(key.get(Calendar.MONTH) == (tempKey.get(Calendar.MONTH))
&& key.get(Calendar.DATE) == (tempKey.get(Calendar.DATE))
&& key.get(Calendar.YEAR) == tempKey.get(Calendar.YEAR)){
// tempArr.add(value);
if(key.get(Calendar.YEAR) != year){
System.out.println(key.get(Calendar.YEAR));
year = key.get(Calendar.YEAR);
System.out.println(MyCalendarTester.arrayOfDays[key.get(Calendar.DAY_OF_WEEK) - 1] + ", " + MyCalendarTester.arrayOfMonths[key.get(Calendar.MONTH) - 1] + " "
+ key.get(Calendar.DATE) + " ");
}
toRemove.add(copyKey);
// toRemove.add(copyKey);
//keys.remove(copyKey);
}else{
//if(count <= 1){
//if(tempArr.size() == 1){
if(countEnd == countTotal){
tempArr.remove(tempArr.size() - 1);
}else{
if(tempArr.size() > 1){
tempArr.remove(tempArr.size() - 2);
}else{
tempArr.remove(tempArr.size() - 1);
}
if(toRemove.size() > 0){
toRemove.remove(toRemove.size() - 1);
}
}
// }
// else{
// tempArr.remove(tempArr.size() - 2);
// toRemove.remove(toRemove.size() - 1);
// }
//
// count = 0; //reset matches
//}
}
tempKey = key;
}
Collections.sort(tempArr);
for(Event e: tempArr){
if(e.endTime != null){
System.out.println(" " + e.eventName + " " + e.startTime.get(Calendar.HOUR_OF_DAY) + ":" +
e.startTime.get(Calendar.MINUTE) + " " + e.endTime.get(Calendar.HOUR_OF_DAY)
+ ":" + e.endTime.get(Calendar.MINUTE));
//tempKey = key;
// year = key.get(Calendar.YEAR);
//keys.remove(key);
}
else{
System.out.println(" " + e.eventName + " " + e.startTime.get(Calendar.HOUR_OF_DAY) + ":" +
e.startTime.get(Calendar.MINUTE));
// tempKey = key;
// year = key.get(Calendar.YEAR);
//keys.remove(key);
}
}
tempArr.clear();
//break;
for(GregorianCalendar remove: toRemove){
copyKeys.removeAll(Collections.singleton(remove));
}
for(GregorianCalendar key : copyKeys){
Event value = MyCalendarTester.myCal.getMyCalHash().get(key);
if(tempArr.size() == 0){
if(value.endTime != null){
if(key.get(Calendar.YEAR) == year){
System.out.println(MyCalendarTester.arrayOfDays[key.get(Calendar.DAY_OF_WEEK) - 1] + ", " + MyCalendarTester.arrayOfMonths[key.get(Calendar.MONTH) - 1] + " "
+ key.get(Calendar.DATE) + " " + value.startTime.get(Calendar.HOUR_OF_DAY) + ":" + value.startTime.get(Calendar.MINUTE) + " - " + value.endTime.get(Calendar.HOUR_OF_DAY)
+ ":" + value.endTime.get(Calendar.MINUTE) + " " + value.eventName);
// tempKey = key;
}else{
System.out.println(key.get(Calendar.YEAR));
System.out.println(MyCalendarTester.arrayOfDays[key.get(Calendar.DAY_OF_WEEK) - 1] + ", " + MyCalendarTester.arrayOfMonths[key.get(Calendar.MONTH) - 1] + " "
+ key.get(Calendar.DATE) + " " + value.startTime.get(Calendar.HOUR_OF_DAY) + ":" + value.startTime.get(Calendar.MINUTE) + " - " + value.endTime.get(Calendar.HOUR_OF_DAY)
+ ":" + value.endTime.get(Calendar.MINUTE) + " " + value.eventName );
year = key.get(Calendar.YEAR);
tempKey = key;
}
}else{
if(key.get(Calendar.YEAR) == year){
System.out.println(MyCalendarTester.arrayOfDays[key.get(Calendar.DAY_OF_WEEK) - 1] + ", " + MyCalendarTester.arrayOfMonths[key.get(Calendar.MONTH) - 1] + " "
+ key.get(Calendar.DATE) + " " + value.startTime.get(Calendar.HOUR_OF_DAY) + ":" + value.startTime.get(Calendar.MINUTE) + " " + value.eventName);
tempKey = key;
}else{
System.out.println(key.get(Calendar.YEAR));
System.out.println(MyCalendarTester.arrayOfDays[key.get(Calendar.DAY_OF_WEEK) - 1] + ", " + MyCalendarTester.arrayOfMonths[key.get(Calendar.MONTH) - 1] + " "
+ key.get(Calendar.DATE) + " " + value.startTime.get(Calendar.HOUR_OF_DAY) + ":" + value.startTime.get(Calendar.MINUTE) + " " + value.eventName);
System.out.println();
year = key.get(Calendar.YEAR);
tempKey = key;
}
}
}
}
}
}
I originally have it sorted by the keys (dates) in ascending order. From there, I am looking for any identical dates and sorting them by the time (values). Then, since I've already sorted and printed those days by the time, I don't want to reprint them later. I've been tweaking this for hours to try to get it to cooperate, so perhaps I'm over thinking it at this point. Anyway, if anyone is nice enough to look at this and make a few suggestions, I'd greatly appreciate it. Otherwise, just skip over because this is a long and convoluted one.
There will only be one occurrence of any given object in a Set and that is why only one is being removed.
Sets do not allow duplicates. If you want to allow duplicates, use another data structure such as an ArrayList.
I need the currentStockLevel for another void Method in java, is there any possibility to get it?
I think no, because of void right?
public void receive (int currentStock)
{
String outLine;
if (currentStockLevel > 0)
outLine = productCode;
{
outLine = ". Current Stock: " + currentStockLevel;
outLine += " Current Stock changed from " + currentStockLevel;
currentStockLevel += currentStock;
outLine += " to " + currentStockLevel;
int storeCost = wholeSalePrice * currentStockLevel;
System.out.println (productCode + ":" + " Received " + currentStockLevel + "." + " Store Cost " + "$" + storeCost + "." + " New stock level: " + currentStockLevel);
}
I'm looking for a Java built-in data structure that would be the best at handling adjacent rooms.
I have a grid/floor divided into randomly generated rooms like so:
+ + + + + + + + + + + + + + + + + + + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + + + + + + + + + + + + + + + + + + +
+ + + +
+ + + +
+ + + +
+ + + +
+ + + +
+ + + + + + + + + + + + + + + + + + + +
+ + + +
+ + + +
+ + + +
+ + + +
+ + + + + + + + + + + + + + + + + + + +
and i'm looking for a data structure in which it would be fastest/easiest to store this grid and map out what rooms neighbour what rooms.
Does anyone have a suggestion?
thanks
You just need to store:
the opposite corners of each room
the adjacency graph/matrix of the graph formed by rooms as nodes and adjacency as the edge.
You can use a graph to represent rooms as nodes and neighboring relationship as edges.
You can represent graphs in many different ways. In this case, since the relationship is sparse, it's better to use adjacency list instead of adjacency matrix.
In Java, the graph can be represented with Map<Room,List<Room>>. Basically, it is what it says: it's a map from a Room to a list of its neighboring Rooms.
Alternatively, if you prefer to work with basic integers and arrays, you can use an adjacency matrix representation boolean[][] adj, where adj[i][j] == true if and only if room i and room j are neighbors.