I need to estimate if the array list is sorted (don't sort).
When Strings are sorted, they are in alphabetical order.
I try to use compareTo() method to determine which string comes first
And return true if the array list is sorted, else false.
Code:
public boolean isSorted()
{
boolean sorted = true;
for (int i = 1; i < list.size(); i++) {
if (list.get(i-1).compareTo(list.get(i)) != 1) sorted = false;
}
return sorted;
}
Easy test:
ArrayList<String> animals = new ArrayList<String>();
ArrayListMethods zoo = new ArrayListMethods(animals);
animals.add("ape");
animals.add("dog");
animals.add("zebra");
//test isSorted
System.out.println(zoo.isSorted());
System.out.println("Expected: true");
animals.add("cat");
System.out.println(zoo.isSorted());
System.out.println("Expected: false");
animals.remove("cat");
animals.add(0,"cat");
System.out.println(zoo.isSorted());
System.out.println("Expected: false");
**Output:**
false
Expected: true
false
Expected: false
false
Expected: false
This easy test shows only 1/3 coverage.
How to solve this issue.
You have a small bug in your method. Should be :
public boolean isSorted()
{
boolean sorted = true;
for (int i = 1; i < list.size(); i++) {
if (list.get(i-1).compareTo(list.get(i)) > 0) sorted = false;
}
return sorted;
}
>0 instead of !=1, you can't be sure that 1 is returned..
Change the condition :
if (list.get(i - 1).compareTo(list.get(i)) >0)
You should check for >0 instead of !=-1 .
Go through the documentation of compareTo()
the value 0 if the argument string is equal to this string; a value less than 0 if this string is lexicographically less than the string argument; and a value greater than 0 if this string is lexicographically greater than the string argument.
Try this
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
public class Sort {
public static void main(String []args) {
List<String> l1=new ArrayList<String>();
List<String> l2=new ArrayList<String>();
l1.add("a");
l1.add("b");
l1.add("c");
l2.add("b");
l2.add("c");
l2.add("a");
if(isSorted(l1)){
System.out.println("already sorted");
}
else{
Collections.sort(l1);
}
}
public static boolean isSorted(List<String> list){
String previous = "";
for (String current: list) {
if (current.compareTo(previous) < 0)
return false;
previous = current;
}
return true;
}
}
You can write a utily method like isSortedList(List list).
public static boolean isSortedList(List<? extends Comparable> list)
{
if(list == null || list.isEmpty())
return false;
if(list.size() == 1)
return true;
for(int i=1; i<list.size();i++)
{
if(list.get(i).compareTo(list.get(i-1)) < 0 )
return false;
}
return true;
}
As as utility method, you can use it anywhere.
you have to change the compareTo expresion to any positive number, which indicates that the previous element is alphabetically after the current element, hence the list is not ordered
public boolean isSorted()
{
boolean sorted = true;
for (int i = 1; i < list.size(); i++) {
if (list.get(i-1).compareTo(list.get(i)) > 0) sorted = false;
}
return sorted;
}
You need to check for unsorted case.
This means that if you are assuming sorting ascending, the unsorted case will be finding an element at index i being out of order from index i-1
where element[i] < element[i-1].
Related
I am trying to solve a coding problem. The problem is following:
Given a sequence of integers as an array, determine whether it is possible to obtain a strictly increasing sequence by removing no more than one element from the array.
For example:
[1,3,2,1] is false
[1,3,2] is true
I implemented it in Java. The code is as follows:
boolean almostIncreasingSequence(int[] sequence) {
int count =0;
for(int i =0; i < sequence.length; i++){
if (sequence[i] <= sequence[i-1]){
count++;
}
if(count>1){
return false;
}
if(sequence[i] <= sequence[i-2] && sequence[i+1] <= sequence[i-1]){
return false;
}
}
return true;
}
This is the following error:
Execution error on test 1: Your program had a runtime error.
Any help will be appreciated. It seems a small problem but I can't resolve it.
One implementation can be based on remove just 1 element when strictly ascending condition is not achieved.
public class TestAlmostIncreasingSequence {
public static boolean almostIncreasingSequence(int[] sequence)
{
if(sequence==null) return false;
//mandatory to remove just 1 element, if no one(or more) removed then false
boolean flag_removed=false;
for(int i=1, prev=sequence[0];i<sequence.length;i++)
{
if(prev>=sequence[i] && flag_removed==false)
{
//mark removed
flag_removed=true;
}
//if element was removed then false
else if(prev>=sequence[i] && flag_removed==true)
{
return false;
}
else
{
//change only if element removed is not the current
//comparisons will not be done with removed element
prev=sequence[i];
}
//System.out.println(prev);
}
//could have a strictly increased arr by default which will return false [1,2,3]
return flag_removed;
}
public static void main(String[] args)
{
//only for printing purpose
String arr="";
int s1[] = {1,2,3,1};
arr=Arrays.stream(s1).mapToObj(t->String.valueOf(t)).
collect(Collectors.joining(",","[","]"));
System.out.println(arr+"\n"+almostIncreasingSequence(s1)+"\n");
int s2[] = {1,2,3};
arr=Arrays.stream(s2).mapToObj(t->String.valueOf(t)).
collect(Collectors.joining(",","[","]"));
System.out.println(arr+"\n"+almostIncreasingSequence(s2)+"\n");
int s3[] = {1,2,3,1,2};
arr=Arrays.stream(s3).mapToObj(t->String.valueOf(t)).
collect(Collectors.joining(",","[","]"));
System.out.println(arr+"\n"+almostIncreasingSequence(s3)+"\n");
int s4[] = {1};
arr=Arrays.stream(s4).mapToObj(t->String.valueOf(t)).
collect(Collectors.joining(",","[","]"));
System.out.println(arr+"\n"+almostIncreasingSequence(s4)+"\n");
int s5[] = {1,1};
arr=Arrays.stream(s5).mapToObj(t->String.valueOf(t)).
collect(Collectors.joining(",","[","]"));
System.out.println(arr+"\n"+almostIncreasingSequence(s5)+"\n");
int s6[] = null;
arr="null";
System.out.println(arr+"\n"+almostIncreasingSequence(s6)+"\n");
}
}
Output
[1,2,3,1]
true
[1,2,3]
false
[1,2,3,1,2]
false
[1]
false
[1,1]
true
null
false
Note: The implementation have a case when the result is wrong [1,5,2,3], just update with one more branch with removed element=the previous one(not the current) and check both branched (one true means true)
This should fix the case
//method name is misguided, removePrev is better
public static boolean removeCurrent(int[] sequence)
{
if(sequence==null) return false;
//mandatory to remove just 1 element, if no one remove then false
boolean flag_removed=false;
for(int i=1, prev=sequence[0];i<sequence.length;i++)
{
if(prev>=sequence[i] && flag_removed==false)
{
//mark removed
flag_removed=true;
}
//if element was removed then false
else if(prev>=sequence[i] && flag_removed==true)
{
return false;
}
//compared element will be the current one
prev=sequence[i];
//System.out.println(prev);
}
//could have a strictly increased arr by default which will return false [1,2,3]
return flag_removed;
}
and use
int s1[] = {1,5,2,3};
arr=Arrays.stream(s1).mapToObj(t->String.valueOf(t)).
collect(Collectors.joining(",","[","]"));
boolean result= (almostIncreasingSequence(s1)==false) ? removeCurrent(s1) : true;
System.out.println(arr+"\n"+result +"\n");
Output
[1,5,2,3]
true (from removeCurrent_branch)
Seems one more case is wrong [5,6,3,4], means need to see if element[i-2](only after remove element) is not greater then current and 'prev' on last branch.
6>3 remove 6 (prev=3, 3<4 but [5>4 or 5>3] so false)
public static boolean removeCurrent(int[] sequence)
{
if(sequence==null) return false;
//mandatory to remove just 1 element, if no one remove then false
boolean flag_removed=false;
for(int i=1, prev=sequence[0], twoprev=Integer.MIN_VALUE;i<sequence.length;i++)
{
if(prev>=sequence[i] && flag_removed==false)
{
//mark removed
flag_removed=true;
if(i>=2) twoprev=sequence[i-2];
}
//if element was removed then false
else if(prev>=sequence[i] && flag_removed==true)
{
return false;
}
else if(twoprev>=sequence[i] || twoprev>=prev)
{
return false;
}
//compared element will be the current one
prev=sequence[i];
//System.out.println(prev);
}
//could have a strictly increased arr by default which will return false [1,2,3]
return flag_removed;
}
Output
[5,6,3,4]
false
Now, as far as I see all cases seems covered.
Brute force can also generate a solution but will be less optimal.(use a loop to remove an element, sort the result and compare with base)
public class TestInc {
public static void main(String[] args)
{
int s1[] = {1,1,2,3};
System.out.println(checkInc(s1));
}
public static boolean checkInc(int[] arr)
{
if(arr==null || arr.length==1) return false;
List<Integer> lst = Arrays.stream(arr).boxed().collect(Collectors.toList());
//remove this check if requirement is other(or return true)
if(checkIfAlreadySortedAsc(lst))
{
return false;
}
for(int i=0;i<lst.size();i++)
{
List<Integer> auxLst = new ArrayList<Integer>(lst);
auxLst.remove(i);
List<Integer> sorted = new ArrayList<Integer>(auxLst);
sorted = sorted.stream().distinct().sorted().collect(Collectors.toList());
if(auxLst.equals(sorted))
{
// System.out.println("=");
return true;
}
else
{
// System.out.println("!=");
}
}
return false;
}
//any ascending sorted list will be the same type if remove one element
//but as requirement on this case will return false
//(or don't use method in want other)
public static boolean checkIfAlreadySortedAsc(List<Integer> lst)
{
List<Integer> auxLst = new ArrayList<Integer>(lst);
auxLst = auxLst.stream().distinct().sorted().collect(Collectors.toList());
if(auxLst.equals(lst))
{
return true;
}
return false;
}
}
Output
[1,1,2,3]
true
This line would produce an ArrayIndexOutOfBoundsException when i == 0 because it will attempt to access sequence[-1]
if (sequence[i] <= sequence[i-1]){
I am trying to check whether values of two hashmaps are equal to each other or not with using hashMap.values().equals(). But even if two HashMap have same values it's not considered as equal.
String s = "egg";
String t = "add";
int count = 0;
HashMap<String,Integer> hashMap = new HashMap<>();
for (int i = 0; i < s.length(); i++) {
String val = String.valueOf(s.charAt(i));
if (!hashMap.containsKey(val)) {
count++;
hashMap.put(val, count);
} else {
hashMap.put(val, hashMap.get(val));
}
}
HashMap<String,Integer> hashMap2 = new HashMap<>();
int count2 = 0;
for (int j = 0; j < t.length(); j++) {
String val = String.valueOf(t.charAt(j));
if (!hashMap2.containsKey(val)) {
count2++;
hashMap2.put(val, count2);
} else{
hashMap2.put(val, hashMap2.get(val));
}
}
if (hashMap.values().equals(hashMap2.values())) {
return true;
} else {
return false;
}
You're comparing two collections, they will never be equal because you're doing a reference compare on two different collections. Apache commons-collections has CollectionUtils#isEqualCollection, use that. Of course if you're creating you own class as value of the map, implement equals and hashCode in it.
Since hashMap.values() is return Collection<T> we cannot compare it with equals(). Thanks to Ali Ben Zarrouk for help. Here is the implementation of how to check if values of two hashmaps are equal or not without using any third party library.
if(areHashMapValuesEqual(hashMap.values(),hashMap2.values())){
return true;
} else {
return false;
}
static <T> boolean areHashMapValuesEqual(Collection<T> lhs, Collection<T> rhs) {
boolean equals = false;
if(lhs!=null && rhs!=null) {
equals = lhs.size( ) == rhs.size( ) && lhs.containsAll(rhs) && rhs.containsAll(lhs);
} else if (lhs==null && rhs==null) {
equals = true;
}
return equals;
}
public static boolean verifyRecords(LinkedList<String> recordList, String order) throws Exception {
/*To check ascending order*/
if("Ascending".equalsIgnoreCase(order) || "A".equalsIgnoreCase(order)) {
String previous = new String();
for(String current : recordList) {
if(current.compareTo(previous) < 0)
return false;
previous = current;
}
} else if("Descending".equalsIgnoreCase(order) || "D".equalsIgnoreCase(order))
{
for(String current : recordList) {
if(current.compareTo(previous) > 0)
return false;
previous = current;
}
}
return true;
}
Here, I am giving new String(), i.e. Empty, string to start with for Ascending order. But for Descending order, what should be the starting String to start descending order comparison the i should use?
Any help would be much appreciated.
You dont need to loop untill the last element, you can compare any uneven thing and break from there to achieve your results or verify the list.
if ("Ascending".equalsIgnoreCase(order) || "A".equalsIgnoreCase(order)) {
for (int i = 1; i < recordList.size(); i++) {
if (recordList.get(i - 1).compareTo(recordList.get(i)) > 0) {
isSorted = false;
break;
}
}
} else if ("Descending".equalsIgnoreCase(order)
|| "D".equalsIgnoreCase(order)) {
for (int i = 1; i < recordList.size(); i++) {
if (recordList.get(i - 1).compareTo(recordList.get(i)) < 0) {
isSorted = false;
break;
}
}
}
return isSorted;
You could use the Collections.reverse(list) to compare. The idea is to create a shallow copy of the recordList, sort in descending order and compare them.
LinkedList<String> recordList = new LinkedList<String>(Arrays.asList("a","B", "c"));
LinkedList<String> validateList = new LinkedList<String>(recordList);
Collections.sort(validateList); // sorts in ascending order
Collections.reverse(validateList); // reverses the ascending ordered list
System.out.println(recordList.equals(validateList));
EDIT: With your help I managed to fix my problem. I have edited my code to now show how I had to have it set up to get it working.
Currently I am having trouble coding a part which compares the content of two iterators. As part of the requirements for my assignment, I need to use a linkedlist to store the individual characters of the entered String. I have gotten to the point where I have two iterators which would contain the input one way and the reverse way.
String palindrom = input.getText();
String [] chara = palindrom.split (""); //this is successfully splitting them, tested.
int length = palindrom.length( ); // length == 8
System.out.println (length); //can use this for how many checks to do?
LinkedList ll = new LinkedList(Arrays.asList(chara));
Iterator iterator = ll.iterator();
Iterator desIterator = ll.descendingIterator();
/*while(iterator.hasNext() ){
System.out.println(iterator.next() );
}
while(desIterator.hasNext() ){
System.out.println(desIterator.next() );
}*/
boolean same = true;
while(iterator.hasNext()){
if(!iterator.next().equals(desIterator.next())){
same = false;
break;
}
}
And using the System.out I can see that they are being stored correctly, but I don't know how to check if the iterators store the same contents. What would be one of the simplest methods to compare the two iterators or convert them into something I can compare? To clarify I want to verify they contain the same elements in the same order.
boolean same = true;
while(iterator.hasNext()){
if(!desIterator.hasNext() || !iterator.next().equals(desIterator.next())){
same = false;
break;
}
}
System.out.println(same);
You need to iterate over both iterators simultaneously, i.e. with one loop. Here is a general comparison function (0 when equal, < 0 when A < B, > 0 when A > B):
static <T extends Comparable<S>, S> int compare(Iterator<T> a, Iterator<S> b) {
while (a.hasNext() && b.hasNext()) {
int comparison = a.next().compareTo(b.next());
if (comparison != 0) {
return comparison;
}
}
if (a.hasNext())
return 1;
if (b.hasNext())
return -1;
return 0;
}
To just check if they are equal, this can be simplified:
static <T, S> boolean equals(Iterator<T> a, Iterator<S> b) {
while (a.hasNext() && b.hasNext()) {
if (!a.next().equals(b.next())) {
return false;
}
}
if (a.hasNext() || b.hasNext()) {
// one of the iterators has more elements than the other
return false;
}
return true;
}
Guava implements this as Iterators.elementsEqual.
In both answers throw NullPointerException, if iterator.next() == null. This method is more optimal.
public static boolean equals(Iterator i1, Iterator i2) {
if (i1 == i2) {
return true;
}
while (i1.hasNext()) {
if (!i2.hasNext()) {
return false;
}
if (!Objects.equals(i1.next(), i2.next())) {
return false;
}
}
if (i2.hasNext()) {
return false;
}
return true;
}
I am using Selenium Webdriver with Java binding and I'm testing a sorting functionality whereby you have values arranged in an arraylist = {"4"","4.5"","5.5""}. So basically the string contains decimal points as well as double quotation. I have the following code below. The problem is that I keep getting false due to the fact that when it compares the current to previous, it comes with false. Thanks for your help
public Boolean checkAscendingOrderScreensize(List<String> list){
if(list == null || list.isEmpty())
return false;
if(list.size() == 1)
return true;
for(int i=1; i<list.size();i++)
{
String current = list.get(i).toString();
String previous = list.get(i-1).toString();
current = current.replace(",",".");
current = current.replace("\"", "");
previous = previous.replace(",",".");
previous = previous.replace("\"", "");
if(current.compareTo(previous)>0)
return false;
}
return true;
}
You will need to covert the string to double before conversion. So the workaround will be
public class Main {
public static void main(String bicycle[]) {
List<String> texts = new ArrayList<String>();
texts.add("4\"");
texts.add("4.5\"");
texts.add("5.5\"");
System.out.println(checkAscendingOrderScreensize(texts));
// prints true
}
public static boolean checkAscendingOrderScreensize(List<String> list) {
if (list == null || list.isEmpty())
return false;
if (list.size() == 1)
return true;
for (int i = 1; i < list.size(); i++) {
String current = list.get(i).toString();
String previous = list.get(i - 1).toString();
current = current.replace(",", ".");
current = current.replace("\"", "");
previous = previous.replace(",", ".");
previous = previous.replace("\"", "");
if(Double.valueOf(current)<Double.valueOf(previous))
return false;
}
return true;
}
}