Trying to compare the contents two Iterators, how? - java

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;
}

Related

A Java Set for at most 2 objects

I'm writing a method that returns a Set<String>. The set may contain 0, 1, or 2 objects. The string keys are also quite small (maximum 8 characters). The set is then used in a tight loop with many iterations calling contains().
For 0 objects, I would return Collections.emptySet().
For 1 object, I would return Collections.singleton().
For 2 objects (the maximum possible number), a HashSet seems overkill. Isn't there a better structure? Maybe a TreeSet is slightly better? Unfortunately, I'm still using Java 7 :-( so can't use modern things like Set.of().
An array of 2 strings would probably give the best performance, but that's not a Set. I want the code to be self-documenting, so I really want to return a Set as that is the logical interface required.
Just wrap an array with an AbstractSet. You only have to implement 2 methods, assuming you want an unmodifiable set:
class SSet extends AbstractSet<String> {
private final String[] strings;
SSet(String[] strings) {
this.strings = strings;
}
#Override
public Iterator<String> iterator() {
return Arrays.asList(strings).iterator();
}
#Override
public int size() {
return strings.length;
}
}
If you want, you can store the Arrays.asList(strings) in the field instead of a String[]. You can also provide 0, 1 and 2-arg constructors if you want to constrain the array only to be that length.
You can also override contains:
public boolean contains(Object obj) {
for (int i = 0; i < strings.length; ++i) {
if (Objects.equals(obj, strings[i])) return true;
}
return false;
}
If you don't want to create a list simply to create an iterator, you can trivially implement one as an inner class:
class ArrayIterator implements Iterator<String> {
int index;
public String next() {
// Check if index is in bounds, throw if not.
return strings[index++];
}
public boolean hasNext() {
return index < strings.length;
}
// implement remove() too, throws UnsupportedException().
}
The set is then used in a tight loop with many iterations calling contains().
I would probably streamline it for this. Perhaps something like:
public static class TwoSet<T> extends AbstractSet<T> {
T a = null;
T b = null;
#Override
public boolean contains(Object o) {
return o.equals(a) || o.equals(b);
}
#Override
public boolean add(T t) {
if(contains(t)){
return false;
}
if ( a == null ) {
a = t;
} else if ( b == null ) {
b = t;
} else {
throw new RuntimeException("Cannot have more than two items in this set.");
}
return true;
}
#Override
public boolean remove(Object o) {
if(o.equals(a)) {
a = null;
return true;
}
if(o.equals(b)) {
b = null;
return true;
}
return false;
}
#Override
public int size() {
return (a == null ? 0 : 1) + (b == null ? 0 : 1);
}
#Override
public Iterator<T> iterator() {
List<T> list;
if (a == null && b == null) {
list = Collections.emptyList();
} else {
if (a == null) {
list = Arrays.asList(b);
} else if (b == null) {
list = Arrays.asList(a);
} else {
list = Arrays.asList(a, b);
}
}
return list.iterator();
}
}
You can achieve this by
Make a class that implements Set interface
Override add and remove method
Add value upon class initialisation by super.add(E element)
Use that class instead

Check whether there are remaining items in the List while iterating

I'm doing a Bean Validation for a List of conditions:
public abstract class BaseMyConditionValidator<T extends Annotation> implements ConstraintValidator<T, List<MyCondition>> {
#Override
public void initialize(T constraintAnnotation) {}
#Override
public boolean isValid(List<MyCondition> conditions, ConstraintValidatorContext context) {
boolean result = true;
if (!conditions.isEmpty()){
int i = 0;
for (MyCondition cond : conditions){
if (cond.getJoinPart() != null){
if (!hasNext(i, conditions)){
return false;
}
}
i++;
}
}
return result;
}
private boolean hasNext(int index, List<MyCondition> conditions){
try {
conditions.get(index + 1);
} catch (Exception e){
return false;
}
return true;
}
}
My question is is there a simpler approach to deal with:
Checking if there is still an item next in line during a iteration of a List
You could use plain old Iterator to iterate through the list, or instead of hasNext(i, conditions) just check list length (i < conditions.size() - 1)
In the end, instead of iterating through whole list, just check if last element's JoinPart is null (at least it is what you are doing)
#Override
public boolean isValid(List<MyCondition> conditions, ConstraintValidatorContext context) {
return conditions.isEmpty() || conditions.get(conditions.size() - 1).getJoinPart() != null;
}
In fact, in your case/code you don't need to check whether there is another element in the list. Using for(MyCondition cond : conditions) will iterate over all elements in conditions list. If you need to check what is the size of the list, you can use contidions.size().
Of course!
for (int i = 0; i < conditions.size(); i++){
cond = conditions.get(i);
if (cond.getJoinPart() != null){
if (i < conditions.size()){
continue;
} else {
return false;
}
}
}
But I don't understand why you would do that... are you just trying to ensure that .getJoinPart() doesn't equal null for every element?

Comparing items in a stack

I am trying to compare two seperate stacks to see if they are the same or not. I have a loop iterate through each object in each stack and compare both objects. What I want to happen is if they are equal, continue the loop and return true. If they are not equal at any given point, break the loop and return false. This is what I have written:
public boolean isPalindrome (Stack a, Stack b) {
Object temp1;
Object temp2;
boolean answer;
for (int i = 0; a.size() > 0; i++) {
temp1 = a.pop();
temp2 = b.pop();
if (temp1 != temp2) {
answer = false;
}
else {
answer = true;
}
}
return answer;
}
What I see happening in this is that I have a boolean, and through each loop that boolean is assigned a value depending on what the objects are, then at the end of the loop, return that boolean in its most recent state. No matter what I initialize the variable to, its like the loop does absolutely nothing to it. Can you not modify or return a boolean in a loop? What would be the better way to go about this instance? I have looked at tons of other posts for similar issues, but most of them seem to be trying something a little different ad I would like to stick as true to my original ideas as possible, I just need to know what I am doing wrong. Any suggestions would help greatly. Thanks!
The basic idea that you can return false (which breaks method execution) once you find stacks are not equal. Otherwise return true:
public boolean isPalindrome (Stack a, Stack b) {
if (a.size() != b.size()) {
return false;
}
while (a.size() > 0) {
if (!a.pop().equals(b.pop())) {
return false;
}
}
return true;
}
public boolean isPalindrome (Stack a, Stack b) {
Object temp1;
Object temp2;
boolean answer = true;
for (int i = 0; a.size() > 0; i++) {
temp1 = a.pop();
temp2 = b.pop();
if (temp1 != temp2) {
answer = false;
break;
}
}
return answer;
}
You need to place a return statement when you find a false item -- else, you're simply returning the boolean found in the last iteration of your loop.
public boolean isPalindrome (Stack a, Stack b) {
Object temp1;
Object temp2;
boolean answer;
for (int i = 0; a.size() > 0; i++) {
temp1 = a.pop();
temp2 = b.pop();
if (temp1 != temp2) {
answer = false;
return answer;
}
else {
answer = true;
}
}
return answer;
}
My suggestion:
public boolean isPalindrome (Stack a, Stack b) {
if (a.size() != b.size()) return false;
while (a.size() > 0) {
if (a.pop() != b.pop()) {
return false;
}
}
return true;
}
You should put a break statement in just after answer is set to false. Without this, you are returning false only if the last items are not equal.
Quick note: I would also add a check for the case that the two stacks are not the same size.

Detecting multiple values in a list

I am having trouble with this problem: I am to write a method contains3 that accepts a List of strings as a parameter and returns true if any single string occurs at least 3 times in the list, and false otherwise. I need to use a map.
When there are three instances of a word, it still does not return true; I am having trouble locating where things went wrong.
Here is what I have:
private static boolean contains3(List<String> thing) {
Map<String, Integer> wordCount = new TreeMap<String, Integer>();
for (String s: thing) {
String word = s;
if (wordCount.containsKey(word)) { // seen before.
int count = wordCount.get(word);
wordCount.put(word, count + 1);
} else {
wordCount.put(word, 1); // never seen before.
}
if (wordCount.containsValue(3)) {
return true;
} else {
return false;
}
}
return false;
}
The problem is here:
if (wordCount.containsValue(3)) {
//...
You should get the value using the key, in other words, the word you're counting.
if (wordCount.get(word) >= 3) {
return true;
}
Note that I removed the return false; from this if statement since it will break the method in the first iteration.
As a suggestion, you may use a HashMap instead of TreeMap to enhance the performance of your method since the put and get time in HashMap are O(1) (constant time) while TreeMap's are O(log n).
Try using the following code.
private static boolean contains3(List<String> thing) {
Map<String, Integer> wordCount = new TreeMap<String, Integer>();
thing.add("hi");
thing.add("hi");
thing.add("hi");
thing.add("hia");
thing.add("hi3");
for (String s: thing) {
String word = s;
if (wordCount.containsKey(word)) { // seen before.
int count = wordCount.get(word);
wordCount.put(word, count + 1);
} else {
wordCount.put(word, 1); // never seen before.
}
}
if (wordCount.containsValue(3)) {
return true;
} else {
return false;}
You're running this code as you add each word:
if (wordCount.containsValue(3)) {
return true;
} else {
return false;
The test will fail when the first word is added, and you'll immediately return false. Move that block to the end of the method, in the final line where you currently have return false to only make the check when you've counted all the words.
put
if (wordCount.containsValue(3)) {
return true;
} else {
return false;
}
outside the for loop
It is much more efficient to check if count is >= 3 in the initial if block
if (wordCount.containsKey(word)) { // seen before.
int count = wordCount.get(word) + 1;
if(count >= 3) {
return true;
}
wordCount.put(word, count);
}
and remove the following if else block
if (wordCount.containsValue(3)) {
return true;
} else {
return false;
}

Java Compare Two List's object values?

I have two list **ListA<MyData> listA = new ArrayList<MyData>()** and ListB<MyData> listB = new ArrayList<MyData>() both contain object of type MyData and MyData contain these variables.
MyData {
String name;
boolean check;
}
ListA and ListB both contains MyData objects ,now I have to compare both the list's object values here name as well check variable like if ListA contains these object values
ListA = ["Ram",true],["Hariom",true],["Shiv",true];
and ListB also contain
ListB = ["Ram",true],["Hariom",true],["Shiv",true];
then i have to compare lists and return false because both list are same
But if ListA contains
ListA = ["Ram",true],["Hariom",true],["Shiv",false];
and ListB Contain
ListB = ["Ram",true],["Hariom",true],["Shiv",true];
then I have to compare lists and return true because both list are not same
or vice-versa so any slight change in the any list values I have to return true.
One thing I have to mentioned here objects can be in any order.
It's not the most efficient solution but the most terse code would be:
boolean equalLists = listA.size() == listB.size() && listA.containsAll(listB);
Update:
#WesleyPorter is right. The solution above will not work if duplicate objects are in the collection.
For a complete solution you need to iterate over a collection so duplicate objects are handled correctly.
private static boolean cmp( List<?> l1, List<?> l2 ) {
// make a copy of the list so the original list is not changed, and remove() is supported
ArrayList<?> cp = new ArrayList<>( l1 );
for ( Object o : l2 ) {
if ( !cp.remove( o ) ) {
return false;
}
}
return cp.isEmpty();
}
Update 28-Oct-2014:
#RoeeGavriel is right. The return statement needs to be conditional. The code above is updated.
ArrayList already have support for this, with the equals method. Quoting the docs
...
In other words, two lists are defined to be equal if they contain the same elements in the same order.
It does require you to properly implement equals in your MyData class.
Edit
You have updated the question stating that the lists could have different orders. In that case, sort your list first, and then apply equals.
I got this solution for above problem
public boolean compareLists(List<MyData> prevList, List<MyData> modelList) {
if (prevList.size() == modelList.size()) {
for (MyData modelListdata : modelList) {
for (MyData prevListdata : prevList) {
if (prevListdata.getName().equals(modelListdata.getName())
&& prevListdata.isCheck() != modelListdata.isCheck()) {
return true;
}
}
}
}
else{
return true;
}
return false;
}
EDITED:-
How can we cover this...
Imagine if you had two arrays "A",true "B",true "C",true and "A",true "B",true "D",true. Even though array one has C and array two has D there's no check that will catch that(Mentioned by #Patashu)..SO for that i have made below changes.
public boolean compareLists(List<MyData> prevList, List<MyData> modelList) {
if (prevList!= null && modelList!=null && prevList.size() == modelList.size()) {
boolean indicator = false;
for (MyData modelListdata : modelList) {
for (MyData prevListdata : prevList) {
if (prevListdata.getName().equals(modelListdata.getName())
&& prevListdata.isCheck() != modelListdata.isCheck()) {
return true;
}
if (modelListdata.getName().equals(prevListdata.getName())) {
indicator = false;
break;
} else
indicator = true;
}
}
}
if (indicator)
return true;
}
}
else{
return true;
}
return false;
}
First, implement the MyData.equals(Object o) and MyData.hashCode() methods.
Once you implemented the equals method, you can iterate over the lists as follows:
if(ListA == null && ListB == null)
return false;
if(ListA == null && ListB != null)
return true;
if(ListA != null && ListB == null)
return true;
int max = ListA.size() > ListB.size() ? ListA.size() : ListB.size();
for(int i = 0; i < max; i++) {
myData1 = ListA.get(i);
myData2 = ListB.get(i);
if(!myData1.equals(myData2)) {
return true;
}
}
return false;
I found a very basic example of List comparison at List Compare
This example verifies the size first and then checks the availability of the particular element of one list in another.
This can be done easily through Java8 using forEach and removeIf method.
Take two lists. Iterate from listA and compare elements inside listB
Write any condition inside removeIf method.
Hope this will help
listToCompareFrom.forEach(entity -> listToRemoveFrom.removeIf(x -> x.contains(entity)));
Override the equals method in your class and use Collection#equals() method to check for equality.
See if this works.
import java.util.ArrayList;
import java.util.List;
public class ArrayListComparison {
public static void main(String[] args) {
List<MyData> list1 = new ArrayList<MyData>();
list1.add(new MyData("Ram", true));
list1.add(new MyData("Hariom", true));
list1.add(new MyData("Shiv", true));
// list1.add(new MyData("Shiv", false));
List<MyData> list2 = new ArrayList<MyData>();
list2.add(new MyData("Ram", true));
list2.add(new MyData("Hariom", true));
list2.add(new MyData("Shiv", true));
System.out.println("Lists are equal:" + listEquals(list1, list2));
}
private static boolean listEquals(List<MyData> list1, List<MyData> list2) {
if(list1.size() != list2.size())
return true;
for (MyData myData : list1) {
if(!list2.contains(myData))
return true;
}
return false;
}
}
class MyData{
String name;
boolean check;
public MyData(String name, boolean check) {
super();
this.name = name;
this.check = check;
}
#Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + (check ? 1231 : 1237);
result = prime * result + ((name == null) ? 0 : name.hashCode());
return result;
}
#Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
MyData other = (MyData) obj;
if (check != other.check)
return false;
if (name == null) {
if (other.name != null)
return false;
} else if (!name.equals(other.name))
return false;
return true;
}
}
You can subtract one list from the other using CollectionUtils.subtract, if the result is an empty collection, it means both lists are the same. Another approach is using CollectionUtils.isSubCollection or CollectionUtils.isProperSubCollection.
For any case you should implement equals and hashCode methods for your object.
Using java 8 removeIf to compare similar items
public int getSimilarItems(){
List<String> one = Arrays.asList("milan", "dingo", "elpha", "hafil", "meat", "iga", "neeta.peeta");
List<String> two = new ArrayList<>(Arrays.asList("hafil", "iga", "binga", "mike", "dingo")); //Cannot remove directly from array backed collection
int initial = two.size();
two.removeIf(one::contains);
return initial - two.size();
}
Logic should be something like:
First step: For class MyData implements Comparable interface, override the compareTo method as per the per object requirement.
Second step: When it comes to list comparison (after checking for nulls),
2.1 Check the size of both lists, if equal returns true else return false, continue to object iteration
2.2 If step 2.1 returns true, iterate over elements from both lists and invoke something like,
listA.get(i).compareTo(listB.get(i))
This will be as per the code mentioned in step-1.
It's been about 5 years since then and luckily we have Kotlin now.
Comparing of two lists now looks is as simple as:
fun areListsEqual(list1 : List<Any>, list2 : List<Any>) : Boolean {
return list1 == list2
}
Or just feel free to omit it at all and use equality operator.
I know it's old question but in case anyone needs it. I use this in my application and it works well. i used it to check if the cart has been changed or not.
private boolean validateOrderProducts(Cart cart) {
boolean doesProductsChanged = false;
if (originalProductsList.size() == cart.getCartItemsList().size()) {
for (Product originalProduct : originalProductsList) {
if (!doesProductsChanged) {
for (Product cartProduct : cart.getCartProducts()) {
if (originalProduct.getId() == cartProduct.getId()) {
if (originalProduct.getPivot().getProductCount() != cartProduct.getCount()) {
doesProductsChanged = true;
// cart has been changed -> break from inner loop
break;
}
} else {
doesProductsChanged = false;
}
}
} else {
// cart is already changed -> break from first loop
break;
}
}
} else {
// some products has been added or removed (simplest case of Change)
return true;
}
return doesProductsChanged;
}
String myData1 = list1.toString();
String myData2 = list2.toString()
return myData1.equals(myData2);
where :
list1 - List<MyData>
list2 - List<MyData>
Comparing the String worked for me. Also NOTE I had overridden toString() method in MyData class.
I think you can sort both lists and convert to List if some of them was a HashSet colleciton.
java.utils.Collections package lets you do it.
List<Category> categoriesList = new ArrayList<>();
Set<Category> setList = new HashSet<>();
Collections.sort(categoriesList);
List<Category> fileCategories = new ArrayList<>(setList);
Collections.sort(fileCategories);
if(categoriesList.size() == fileCategories.size() && categoriesList.containsAll(fileCategories)) {
//Do something
}

Categories