Comparing variables for objects in ArrayList (Java) - java

I tried searching, but to no avail, I hope you can help me out.
I have an ArrayList containing objects, which all have 4 integer variables. I want my program to throw an Exception, if some of the variables for these objects are identical.. I'll try and write in pseudocode:
for(Object x : ArrayList)
{
if(x.Variable == someVariables)// all the variables for the objects in the arraylist
{
throw exception
}
}
This is a newbie question, but I hope you can help me out, thanks.

Inside your for loop add them into a set if add method returns false duplicate exist
for(Object x : ArraList)
{
Set<Integer> set=new HashSet<Integer>();
for(int i:x.getAllValues()){
boolean status=set.add(i)
if(status==false){
//throw exception
}
}
}
write get values method in your object class
OR
Simply create a set from list and check their length
Set<Integer> set= new HashSet<Integer>(list);
if(set.size()!=list.size()){
//contains duplicates
}

Id recommend to implement your value check inside of your class which is your Object's type. To me it seems to be important that a "thing" like your Object is able to perform a validity check on it's own values. I give you an example:
public class Container {
// declaration of your four variables
// other code, maybe getters and setters
/**
* Checks if all variables are pairwise inequal
* #return true if so, false otherwise
*/
public boolean isValid() {
// check vars
}
}
This way your routine to check all objects of your list is very easy:
for (Container x : arrayList) {
if (!x.isValid()) {
throw new RuntimeException("A bad thing just happend!");
}
}

Related

How to remove duplicates from an ArrayLlist of ArrayLists that are composed of custom objects

I have a recursive function that generates a list of lists that keeps tracks of valid hand combinations for a card game:
List<List<HandComponent>> validSCompArrangements = new ArrayList<>();
This list is populated by the recursive function successfully but often has duplicate sub-lists (by content but not by not order) that are unavoidable due to the required nature of the function. I wish to remove these duplicate sub-list entries (List<\HandComponent>) so that the above list in the end only features sub-lists that are unique in content, as order does not matter.
Here is the important part of the HandComponent class:
public class HandComponent {
private Type mType;
private Card mCard; // For runs this is the middle card
private Source mSource;
public HandComponent(Type type, Card card, Source source)
{
init(type, card, source);
}
public enum Type {PAIR, TRIPLE, QUAD, RUN}
public enum Source {STOLEN, SECRET, EITHER}
...
}
A sub-list List should only be considered equal to another sub-list if it contains the same exact HandComponents (i.e. the Type, Card, and Source between components of each list must be the same). Card is another enum defined in another file.
So, if two lists in "validSCompArrangements" are
(PAIR,CARD1,STOLEN), (TRIPLE,CARD7,STOLEN), (RUN, CARD8, SECRET)
and
(TRIPLE,CARD7,STOLEN), (RUN, CARD8, SECRET), (PAIR,CARD1, STOLEN)
they should be considered the same since they ultimately contain the same HandComponents even though the order is different and one should be removed so that "validSCompArrangements" only contains that unique list once.
Looking into this I've found bits and pieces on how to solve this problem but nothing that features this combination of a list of lists with custom objects.
One method seems to be to implement a custom Comparator that compares HandComponent instances to use with Collections in order to sort the sub-lists and then another custom Comparator to compare these sorted sub-lists for duplicates, though that seems a tad clunky and I'm not entirely sure how to override the compare method and what kind of return it expects for each comparator I'd need to make. The only other thing I've seen gestured at is that since for my usage the order of both the sub-lists and the main "validSCompArrangements" list itself don't matter, that I should be using Sets and a HashSet to solve this problem instead, I have no idea how to use those to fix this issue, other than that I might need to override the hashCode and equals methods for my HandComponent class, again, not being sure how to do so.
Overall I'm just a bit confused since any example I can manage to find thats remotely related to this usually is talking about just one list of custom objects that contain primatives and not enums, or a list of lists that uses only primatives and no custom objects at all. The fact this is a list of lists of custom objects who's members are enums has me a tad lost on how to go about this.
For example the marked answer in this question: Using collection to remove duplicate Lists, that only handles a portion of my problem, doesn't even seem to work for me despite the OP saying it does. Running that code as is, other than changing
Set<Integer> dedupedCollection = new HashSet<Integer>();
to
Set<List<Integer>> dedupedCollection = new HashSet<>();
as it was clearly meant to be, produces a collection of 3 entries where the second entry of 5, 10, 5 isn't seen as a duplicate and ignored as the OP suggested it should.
EDIT:
So far the closest thing I've found is converting my top-level list to a HashSet using:
Set<List<HandComponent>> handSet = new HashSet<>(validSCompArrangments);
but this only eliminates duplicate lists if their order is the same (which I am guessing is due to the nature of List's default implementation of "equals()"), while I need it to consider lists that are the same in content but different in order as duplicates also. One way around this would be to use Sets for the HandComponent sub-lists as well since they don't care about order innately, but this would prevent those sets from having duplicate HandComponents which I do need to be allowed.
As you said, you just need to implement equals :)
I've provided you how to implement equals method in the HandComponent class and how to use HashSet to getting only the combinations without duplicates.
I've implemented it in Java 8, you can also try to change it using for loop if you want :)
Here is the equals implementation of `HandComponent
public class HandComponent {
public enum Type {PAIR, TRIPLE, QUAD, RUN}
public enum Source {STOLEN, SECRET, EITHER}
public enum Card {ACE, ONE, TWO, TRHEE}
private Type type;
private Card card;
private Source source;
public HandComponent(Type type, Card card, Source source) {
this.type = type;
this.card = card;
this.source = source;
}
#Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (!(o instanceof HandComponent)) {
return false;
}
HandComponent handComponent = (HandComponent) o;
if (type != handComponent.type) {
return false;
}
if (card != handComponent.card) {
return false;
}
if (source != handComponent.source) {
return false;
}
return true;
}
#Override
public String toString() {
return "HandComponent=[" + String.join(", ", Arrays.asList(type.toString(), card.toString(), source.toString())) + "]";
}
}
And below you can see how you can use it
public class Main {
public static void main(String[] args) {
// Creating 2 hand components
HandComponent handComponent1 = new HandComponent(HandComponent.Type.PAIR, HandComponent.Card.ACE, HandComponent.Source.STOLEN);
HandComponent handComponent2 = new HandComponent(HandComponent.Type.QUAD, HandComponent.Card.TRHEE, HandComponent.Source.EITHER);
// 2 combinations with the same card, but different order => they are the same
List<HandComponent> firstCombination = Arrays.asList(handComponent1, handComponent2);
List<HandComponent> secondCombination = Arrays.asList(handComponent2, handComponent1);
// Mixing 2 combinations together
List<List<HandComponent>> combinations = Arrays.asList(firstCombination, secondCombination);
// printing the mix
System.out.println("Before: " + combinations);
// removing duplicates
List<ArrayList<HandComponent>> collect = combinations.stream() // having a stream of list<HandComponent>
.map(HashSet::new) // converting to HashSet, which mean there won't be duplicate in the combinations.
.distinct() // getting only the distinct combinations
.map(ArrayList::new) // reconverting to array list
.collect(Collectors.toList()); // collecting them as list
// result without duplicates
System.out.println("After: " + collect);
// You can now implement it with loop and no java 8 :)
}
}
What ended up working best for me was to implement the "equals()" method for my HandComponent class as suggested by Jiajie Xu, along with the "hashCode()" method automatically generated by Android Studio by using the option in the context menu or Alt + Insert:
#Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
HandComponent that = (HandComponent) o;
return mType == that.mType &&
mCard == that.mCard &&
mSource == that.mSource;
}
#Override
public int hashCode() {
return Objects.hash(mType, mCard, mSource);
}
I then also made the class implement the Comparable interface for use with the Collections class and specified the sort order priority of HandComponent instances within the "compareTo()" method like so:
#Override
public int compareTo(#NonNull HandComponent other) {
// Check Type first
int compareResult = mType.compareTo(other.mType);
if(compareResult == 0)
{
// Check Card second
compareResult = mCard.compareTo(other.mCard);
if(compareResult == 0)
{
// Check Source last
compareResult = mSource.compareTo(other.mSource);
}
}
return compareResult;
}
Since the default implementation of Comparable for List requires list order to be the same in order to return "true" when comparing two lists, I needed to sort my List of Lists every time I wanted to remove duplicates, which was perfectly fine as I benefited from the organization later on.
Ultimately, this allowed me remove the duplicates from my List of Lists of custom objects by first making sure the sub-lists of HandComponent were all sorted and then creating a HashSet of the top-level list.
List<List<HandComponent>> unsortedList = new ArrayList<>();
... // Populate list
for(int i = 0; i < unsortedList.size(); i++)
{
Collections.sort(unsortedList.get(i));
}
Set<List<HandComponent>> sortedDeDupedSet = new HashSet<>(unsortedList);
// Convert back to list since I need order to matter again later on
List<List<HandComponenet>> sortedDeDupedList = new ArrayList<>(sortedDeDupedSet);
This correctly removes duplicates from the top-level list now that I have properly implemented the "equals()" and "hashCode()" methods, as well as sorted the lists before hand with "compareTo()" by leveraging List's default Comparable implementation. Having to use a for loop to sort the lists themselves since I'm restricted to Java 7 does feel a little bad, but like I said before ultimately it was useful to have the lists sorted for other purposes and a lot of time and code is still saved from using a HashSet, versus the nested for loops that would be required to compare each List entry manually.

indexOf() for ArrayList of user defined objects not working

I am not getting the right answer when I try to use indexOf() of an ArrayList made up of user defined objects. Here is the code that creates one of the objects:
State kansas = new State("KS", 5570.81, 2000)
So, the name of the object is "kansas"
Here is the code that creates the ArrayList and adds the object:
ArrayList<State> allStates = new ArrayList<State>();
allStates.add(kansas);
And here is the code that I try to use to find the index of this object:
System.out.println(allStates.indexOf(kansas));
This is the point at which my compiler (Eclipse) throws me a red X indicating that there is a problem with my code and the problem is that it does not recognize 'kansas'. So I tried this:
String s = "kansas";
System.out.println(allStates.indexOf(s));
and it will run but the result is -1.
I am calling a method from a different class to create the ArrayList as opposed to creating it in the same class as my main method but I'm new enough to coding that I"m not sure if that is where I am going wrong. However, in order for the program that I am writing to work, I need to have data about each of the State objects stored so that I can access it from the main method.
Any advice?
*This is my first time posting a questions and I wasn't sure how much detail to go into so if I'm missing relevant information please let me know :)
method indexOf uses equlas() method to compare objects.
That why you have to override equals method in your custom class (if you planning use class in Map override hashCode method as well).
most IDE can generate these methods (equals and hashCode).
here simple example.
public class State {
private String stateCode;
public State(String stateCode /* other parameters*/) {
this.stateCode = stateCode;
}
#Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
State state = (State) o;
return stateCode.equals(state.stateCode);
}
#Override
public int hashCode() {
return stateCode.hashCode();
}
}
This is because, String is not your custom object State type. Your array list is a list of all 'State' types, which is why this -
String s = "kansas";
System.out.println(allStates.indexOf(s));
won't work.
What you can do is have a convenience method that iterates through the list and returns the index.
private int getIndexOfState(String stateName) {
for(State stateObject : allStates) {
if(stateObject.getName().equals(stateName))
return allStates.indexOf(stateObject);
}
return -1;
}
Now you can reuse this method to find index of any state name you pass, and whenever the method returns -1, it means the stateName(state) was not found in the list of states.You can pass in 'Kansas' or 'California' or anything as the parameter to the method.
In your method call you say
System.out.println(getIndexOfState("Kansas"));
System.out.println(getIndexOfState("Chicago"));
The return value is -1 because there is no String "kansas" in allStates, and ArrayList#indexOf returns -1 if the element is not present in the list. If you try to add s to allStates, the compiler won't even let you, because State is not a String.
I don't know why you instantiated a String with the value "kansas", but if you need to refer to the State from its name (maybe the name comes from a Scanner input), you will need a Map<String, State>, such as:
Map<String, State> map = new HashMap<>();
map.put("kansas", kansas) // a String and the object named kansas
Then, you can do:
System.out.println(allStates.indexOf(map.get("kansas")))
//or
String s = "kansas";
System.out.println(allStates.indexOf(map.get(s)))

Detect if ArrayList contains multiple instance of the same object

I tried to detect if an ArrayList contains the same coppies of an object with no success. Here is my code;
public class Foo{
int id;
int name;
#Override
public boolean equals(Object o){
Foo f = (Foo)o;
return f.id==this.id;
}
}
//in another class
ArrayList<Foo> foos;
...
boolean ifFoosListContainsMultipleFoo(Foo f){
return foos.indexOf(f)!=foos.lastIndexOf(f);
}
//but this method always returns `false` even the `foos` list
//contains multiple object with the same `id`;
So, what am I doing wrong and is there a more optimal way of doing this?
Thanks in advance.
EDIT: I saw that I need to override hash method of the Foo class, then why equals function is not enough;
EDIT 2: Sorry for wasting your time but it was my mistake. There is no problem with my code, I used ifFoosListContainsMultipleFoo as !ifFoosListContainsMultipleFoo so this was result of false response.
Apologize me.
Your code should work as it is, except in the case where f is not present in the list at all..
So you can do something like,
boolean ifFoosListContainsMultipleFoo(Foo f){
return (foos.indexOf(f) != -1) && (foos.indexOf(f)!=foos.lastIndexOf(f));
}
You can use a HashSet<Foo> to do this. You should override hashCode as well because HashSet uses hashes internally.
Set<Foo> set = new HashSet<Foo>(foos);
// check for duplicates
set.size() == foos.size();
You can also use the set manually which should let you retain the duplicates and can let you end the check sooner (instead of adding everything):
Set<Foo> set = new HashSet<Foo>();
// check for duplicates
for (Foo foo : foos){
if (!set.contains(foo)){
set.add(foo);
} else {
// do something with foo, which is a duplicate.
// possibly end check for duplicates or store in a list
}
}

Why when you set an ArrayList, there is no need to return a value?

I am new to java and I was writing some code to practice, but there is something that I am confused about. I have the following code:
public class test {
public static void main(String[]args) {
int n = 0;
ArrayList<String> fruits = new ArrayList();
setList(fruits);
n =setInt(9);
// get the values from fruits
for (String value: fruits) {
print(value);
}
}
public static void setList( ArrayList list) {
list.add("pear");
list.add("apple");
list.add("pear");
}
public static int setInt(int number) {
number = 3;
return number;
}
}
My question is why in order to set my Arraylist() there is no need to return the any value, but in order to set my int I need to return something.If run this code it prints all the values in my list, but I expected not to print anything because In my method setList I do not return any value. If I did not return any value with my setInt, the value of n would not change, and that makes sense to me.
Thank you.
There are different ways to that params get passed in functions. The usuall way that most beginners start with is pass by value. The other way is pass by reference. In passing by reference, the object itself is pass in, not a copy as is with pass by value. That means any changes will affect the param and remain, even after it is called. All objects in java are passed by reference, only primitives are passed by value. Thus, is why you don't have to return when using arraylist object.
Edit: Actually, I've made an error. What is actually occuring is that a copy of the reference itself is being passed by value. Take a look at this.
Everything in Java is Pass by Value.

How to tell if an Array or List is also a set?

I have a char[]. I would like to be able to tell if it is a Set and if so create a new Set with the array values. I know I can use a try-catch block but is there any built in method for Java which I could use to test this without throwing an error. It is not imperative that I use a char[]. I could also use a List or something else.
I have a char[]. I would like to be able to tell if it is a Set
It won't be. It can't be. It may have distinct values, but it won't be a Set.
If you actually want to check whether the array contains distinct values, the simplest way would probably be to create a Set<Character> and check whether any add operation returns false:
public static boolean uniqueValues(char[] values) {
Set<Character> set = new HashSet<Character>();
for (char c : values) {
if (!set.add(c)) {
return false;
}
}
return true;
}
(That gives you an early out as soon as you find a duplicate, rather than continuing to construct the whole set.)
An alternative would be to create a boolean[] of size 65536 to see which characters you've got:
public static boolean uniqueValues(char[] values) {
boolean[] seen = new boolean[65536];
for (char c : values) {
int index = c;
if (seen[index]) {
return false;
}
seen[index] = true;
}
return true;
}
For small arrays, this will be hugely wasteful of memory - for larger arrays (of distinct elements, or where the duplicate occurs late) it's more space efficient than the HashSet approach.
You can test if a variable is from certain type using instanceof operator:
if (myVar instanceof Set) {
System.out.println("It's a Set.");
//do what you want/need
}
Still, the usage of instanceof operator seems to be a problem in your design. Even more, you must not use instanceof operator in an array to check if it is a Collection.
EDIT: Based on your last comment in your question, you want to seek if there's a duplicated element in your array. You can do this using the Set as explained in JonSkeet's answer (no need to rewrite the logic and explanation he already has provided).
If your thinking of using "generics" for types the system may have List for the type it can store to check for Set you can use "instanceof" test operator in a comparison.
List<Object[]> alist = new ArrayList<Object[]>();
//setup the list of arrays
if(alist.get(0) instanceof Set){
// do what you do with a set
}else{
// do what you require
}

Categories

Resources