I am trying to sort users in ascending order when I search for the users in our UI. I started the approach with Insertion Sort and I currently have something like this:
if (CollectionUtils.isNotEmpty(userList)) {
//Sort by ascending by display name
for (int i=1; i<userList.size(); i++){
User key = userList.get(i);
int j = i-1;
System.out.println("I: "+key.getFirstName());
System.out.println("J: "+userList.get(j).getFirstName());
while (j>-1 && isAscending(key.getFirstName(), userList.get(j).getFirstName())){
User temp = userList.get(j+1);
System.out.println("TEMP: "+temp.getFirstName());
userList.add(j+1, userList.get(j));
userList.add(j, temp);
j--;
}
userList.add(j+1, key);
}
for (final User user : userList) {
beanList.add(UserBean.getInstance(user));
}
}
Assuming that we have nulls, my isAscending method checks for that and the idea is that the users who's name is null will be placed at the bottom of the list:
private boolean isAscending(String left, String right){
if(left.equals(right)) return false;
if(left == null && right == null) return false;
if((left == null && right != null) || left != null && right == null){
return false;
}
if(left.toLowerCase().compareTo(right.toLowerCase())>0){
return true;
}
return false;
}
With these 2 methods I want to be able to sort users in an ascending order based on their first name. Currently I am running into an infinite loop as after the first iteration, the user at the first index is being compared to himself (aka the user at the first index) over and over again.
Any suggestion would be welcome. Thanks
One of your problems is that you keep adding stuff to the list, but you never remove anything. For example, your inner loop is:
while (j>-1 && isAscending(key.getFirstName(), userList.get(j).getFirstName())){
User temp = userList.get(j+1);
System.out.println("TEMP: "+temp.getFirstName());
userList.add(j+1, userList.get(j));
userList.add(j, temp);
j--;
}
Let's say the list contains [3,2,1]. So the first time through you get:
temp = userList.get(1) // so temp = 2
userList.add(1, 3); // this makes the list contain [3,3,2,1]
userList.add(j, temp) // result: [2,3,3,2,1]
You want to swap the values at locations j and j+1. So write:
temp = userList.get(j+1);
userList.set(j+1, userList.get(j));
userList.set(j, temp);
Also, you probably should fix your isAscending method. Currently, you're calling equals on a potentially null reference. Also, there's no reason to call toLowerCase on the parameters to compareTo when you can easily call compareToIgnoreCase. A cleaner comparison method is:
private boolean isAscending(String left, String right){
// if either parameter is null, then not ascending
if(left == null || right == null) return false;
return (left.compareToIgnoreCase(right) > 0);
}
You might reconsider the null handling logic in your code. Does it really make sense for there to be null values for the fields you're comparing? If not, then you probably should have the comparison method throw an exception.
If you do want to support null values, then you need to modify your isAscending method because the current logic makes any non-null value equal to any null value. So if your list contained [3,null,1], then sorting it would return the same order because calling isAscending(3, null) will return false, and so will isAscending(null, 1). If you want to sort nulls to the front, you want this:
// both values are null, so not ascending
if (left == null && right == null) return false;
// left is null, but right is not
if (left == null) return true;
// right is null, but left is not
if (right == null) return false;
return (left.compareToIgnoreCase(right) > 0);
Related
What is the best way to check if array is null value or if the array contents are null in combination in 1 statement in Java 6:
if ((myArray[0] != null) || (myArray[1] != null) || (myArray!= null)) {
...
}
To have it check for any value, I'd use allMatch. It's also important to check for array != null first, otherwise you'll get an Exception if it is.
if (array == null || Arrays.stream(array).allMatch(Objects::isNull))
Note that this won't work with java prior to version 8, OP edited his requirements after I posted the answer
Firstly, check if the array is not null itself. If the array is null, it makes no reason to iterate its elements since Java will throw the NullPointerException upon access to it:
if (myArray != null) {
// ...
}
Then inside the body of the condition iterate through all its elements and check if one of them is null.
boolean hasNull = false;
for (int i=0; i<myArray.length; i++) {
if (myArray[i] == null) {
hasNull = true;
break; // to terminate the iteration since there is no need to iterate more
}
}
This one-line solution (thanks for the warning from #Napstablook). The condition is evaluated as true if the array itself is null or one of its element is null:
if !(myArray != null && myArray[0] != null && myArray[1] != null) { ... }
Be aware that the && operator works that if the left side is evaluated as false, it stops evaluating the rest of the condition because it will not affect the result. The same does || but with true. However, I suggest you avoid this solution since the index might overflow. Better use the for-loop mentioned above.
Check if Array is null:
String array[] = null;
if (array == null) {
System.out.println("array is null");
}
Check if array is Empty:
array = new int[0];
if (array.length == 0) {
System.out.println("array is empty");
}
Check for null at the same time:
int[] array = ...;
if (array.length == 0) { } // no elements in the array
if (array == null || iarray.length == 0) { }
Try this
if (myArray == null || Arrays.stream(myArray).allMatch(element-> element==null)) {}
Edit- For java 6, I really don't see this happening in one line. You can try this if one line is not necessary
boolean isNull = true;
if(myArray==null){
System.out.println("array is null");
}else{
for(Integer element: myArray){
if(element!=null){
System.out.println("array is not null");
isNull=false;
break;
}
}
if(isNull)
System.out.println("Array is null");
}
Instead Itreating Manullay the array, re use the existing collection for this case.
Convert Array Into List
Check Null is present in list or not using contains() method;
Please find the sample code:
public static void main(String[] args) {
Integer[] array = new Integer[3];
array[0] = 1;
array[1] = null;
array[2] = 2;
System.out.println(Arrays.asList(array).contains(null));
}
for example this
boolean isNullOrContainsNull = array == null || Arrays.asList(array).contains(null);
checks in a line whether the array is null or contains null elements
If you want to check whether the array is null or empty or all elements are null take
boolean containsNothingUseful = array == null
|| array.length == 0
|| !new HashSet<String>(Arrays.asList(array))
.retainAll(Arrays.asList((String)null));
(assuming a String[] array)
Uses the Collection#retainAll() method which returns true when there were other values present, i.e. the inverse of "containsOnly"
Using this one liner is actually fairly inefficient and one better uses a method like below which doesn't create lots of temporary objects and mutates collections etc.
public static boolean containsNothingUseful(String[] array) {
if (array == null || array.length == 0)
return true;
for (String element : array) {
if (element != null)
return false;
}
return true;
}
// ...
if (containsNothingUseful(myArray)) { .. }
I have the classes BinaryTreeNode(int value) with its left and right child and BinaryTree(int rootVal) with BinaryTreeNode root with rootVal as its value.
I developed a code to calculate the number of nodes in the tree (in class BinaryTreeNode), but it doesn't work because of a NullPointerException:
public int size(){
if(this == null) { // base case
return 0;
} else {
return 1 + left.size() + right.size();
}
}
However another solution I found, with a similar strategy, works:
public int size(BinaryTreeNode refNode){
if(refNode == null) { // base case
return 0;
} else {
return 1 + size(refNode.left) + size(refNode.right);
}
}
I have understood why my code throws an exception (it is because left/right would point to null).
But I would like to understand why the second solution works with quasi the same principle.
Thank you in advance!
In your first example you try to find the size before you check for null:
first you call
left.size()
and then inside the size() method you check to see if the object you just called the method on is null
if(this == null) { // base case
return 0;
...
so if left is null, you get the NPE before you get into the size() method.
The main thing to remember here, is that this can never be null. If it was, you couldn't be running a method on it in the first place. So you weren't actually terminating your recursion on a null case like you thought you were.
In the second you check for null first:
if refNode.left is null here
return 1 + size(refNode.left) + size(refNode.right);
the size() method does a pre-check
if(refNode == null) { // base case
return 0;
...
and safely returns 0.
You could make your first method work by explicitly putting the null-check first on each branch:
public int size(){
return 1
+ left == null ? 0 : left.size() // check for null first
+ right == null ? 0 : right.size(); // check for null first
}
The base case is organized in the wrong way; checking for null on the current instance makes no sense. The method should be rewritten as follows.
public int size(){
int sizeLeft = 0;
if (this.left != null)
sizeLeft = left.size();
int sizeRight = 0;
if (this.right != null)
sizeRight = right.size();
return 1 + sizeLeft + sizeRight;
}
this can never be null inside the running class. You'll be getting a NPE because a Node with left == null or right == null will not be able to call the size() code, because the pointer refers to nothing.
Perhaps your code should be more defensive and check if the children are null before attempting to retrieve their size:
public int size() {
int total = 1;
if (left != null)
total += left.size();
if (right != null)
total += right.size();
return total;
}
I am trying to sort ArrayList w.r.t termDate
ArrayList contains firstName,lastName,email,startDate,termDate
Dates can be either empty or null.
I have to compare accordingly and put all the null/empty date values at the end.
Collections.sort(usersList, new Comparator<User>() {
public int compare(User o1, User o2) {
if(o1.getTermDate() == null && o2.getTermDate() == null)
return 0; //They are both null, both equal
if(o1.getTermDate() == null && o2.getTermDate() != null)
return -1; // The first is null and the second is not, return the first as lower than the second
if(o1.getTermDate() != null && o2.getTermDate() == null)
return 1; //The first is not null and the second is, return the first as higher than the second
else
return o1.getTermDate().compare(o2.getTermDate()); //Return the actual comparison
}
});
It is not compiling compare method.
Please guide.
You should change return o1.getTermDate().compare(o2.getTermDate()); to return o1.getTermDate().compareTo(o2.getTermDate()); Because the class java.util.Date; has not method called compare.
public static boolean isComponentBefore(GuiInterface component) {
int index = 0;
for (int i = 0; i < components.size(); i++) {
if (components.get(i).getName() == component.getName()) {
if(components.get(i- 1) == null){
return false;
}
}
}
return true;
}
I currently use this, though this can lead to ConcurrentModificationExceptions & it isn't working because it keeps throwing ConcurrentModificationExceptions whenever I try to see if the element before the element passed in is null.
I was wondering if there are other ways to do this.
Looking at your logic, you will a NullPointerException incase the component in the ArrayList before the given component is null, because components.get(i) would be null and components.get(i).getName() will throw the NPE.
You can try to change the logic here a bit. For every null element in the list, check if the next component is the component you're searching for and return accordingly.
for (int i = 0; i < components.size(); i++) {
if (components.get(i) == null) { // If a particular element is null, check if the next element is what you want
if(components.get(i+1).getName().equals(component.getName())) { // you need to handle the edge case for i+1 as well for the last iteration
return false;
}
}
}
Note that you need to compare the Strings using equals() method and not the == operator. You also need to handle the corner case of i+1 for the last iteration.
This line
if (components.get(i).getName() == component.getName()) {
Should be
if (components.get(i).getName().equals(component.getName())) {
However, your condition can never happen. If component.get(i-1) is null, then in the previous loop iteration
components.get(i).getName() // <-- null pointer exception, so
component.get(i-1) must not be null and you need to hope that i isn't 0 or you'd get an index out of bounds exception.
Use an iterator
e.g
int i = 0;
Iterator<GuiInterface > it = components.iterator();
while (it.hasNext()) {
i++;
GuiInterface thisComp = it.next ();
if (thisComp.getName().equals(component.getName())) {
if(i > 0 && components.get(i- 1) == null){ // this code does not make sense
return false;
}
}
}
Assuming the passed component is not in your list:
public static boolean isComponentBefore(GUIComponent component) {
// Start at 1 to avoid IndexOutOfBounds
for(int i = 1; i < components.size(); i++) {
if (components.get(i).getName().equals(component.getName())) {
return components.get(i - 1) != null;
}
}
// Given component is not in the list, or the list only has one element
return false;
}
Assuming the passed component is in the list:
public static boolean isComponentBefore(GUIComponent component) {
int index = components.indexOf(component);
return index > 0 && components.get(index - 1) != null;
}
I am merging two ArrayLists with the following code. The code is working and giving me the desired result, but I want a more efficient version. Here are the conditions.
Method accepts two lists, and both list have elements in decreasing order (5,4,3,2)
Method accepts an integer to decide the size of the resulting ArrayList.
First input list size is never greater than the size of the resulting ArrayList.
Code:
public ArrayList<Integer> mergeList(ArrayList<Integer> first,ArrayList<Integer> second, int n){
//case 1: when both list are null.
if(first == null && second == null )
return null;
//case 2: when first list is null but second list have elements
else if( first == null && second != null){
return second.size() >=n ? new ArrayList<Integer>(second.subList(0, n)) : second;
}
//case 3: when first list have record and second list is null
else if(first != null && second == null){
return first;
}
//case 4: when both list have elements
else {
first.addAll(second);
Collections.sort(first);
Collections.reverse(first);
return first.size()>=n ? new ArrayList<Integer>(first.subList(0, n)) : first;
}
}
}
It depends on what you mean by "More efficient".
In terms of what? Memory, CPU, readability?
Based on your code above, I'm making the following assumptions:
Readability is more important than pure performance/memory consumption without any profiling measurements/requirements "The First Rule of Program Optimization: Don't do it. The Second Rule of Program Optimization (for experts only!): Don't do it yet." — Michael A. Jackson
Prefer the null object pattern over returning null
Duplicate elements are desirable/required
Use a Comparator to perform a reverse
sort
private List<Integer> mergeList(List<Integer> list1, List<Integer> list2, final int newSize) {
// Enforce null object pattern
if (list1 == null) {
list1 = Collections.emptyList();
}
if (list2 == null) {
list2 = Collections.emptyList();
}
// If duplicates are not desirable, a TreeSet would perform automatic sorting.
List<Integer> result = new ArrayList<Integer>(list1);
result.addAll(list2);
Comparator<Integer> reverseSortComparator = new Comparator<Integer>() {
#Override
public int compare(final Integer o1, final Integer o2) {
return o2.compareTo(o1);
}
};
Collections.sort(result, reverseSortComparator);
if (result.size() > newSize) {
return result.subList(0, newSize);
} else {
return result;
}
}
It looks like you are trying to preserve the contents of first and second. If you are not, then this will do just fine for you and will make your code both faster and more readable:
public ArrayList<Integer> mergeList(ArrayList<Integer> first,ArrayList<Integer> second, int maxLength){
//case 1: when both list are null.
if(first == null && second == null )
return null;
//case 2: when first list is null but second list have elements
else if( first == null && second != null){
return second;
}
//case 3: when first list have record and second list is null
else if(first != null && second == null){
return first;
}
//case 4: when both list have elements
else if(first != null && second != null){
first.addAll(second);
Collections.sort(first); //want to merge these two line into one
Collections.reverse(first);
}
return (ArrayList) first.size() > maxLength ? first.subList(0, n) : first;
}
The reason why this is faster is because with each addAll(), Java must iterate through all the items, copying them into tempList. I preserved the Collections.reverse call because it seems like you need to have your data in reverse sorted order.