How to change the object of the class itself from inside itself? I have one class like this:
public class AdvancedArrayList<T> extends ArrayList<T>
And I want to assign a new object to itself. But, I am unable to do that. Just see this code:
AdvancedArrayList<T> abcd = this; // works fine
this = abcd; // ERROR: variable expected
And this is my entire class:
public class AdvancedArrayList<T> extends ArrayList<T> {
public void reverse(){
Collections.reverse(this);
}
public void removeDuplicates(){
ArrayList<T> wordDuplicate = new ArrayList<>();
ArrayList<T> tempList= new ArrayList<>();
for (T dupObject : wordDuplicate) {
if (!tempList.contains(dupObject)) {
tempList.add(dupObject);
}
}
this = tempList;
}
}
So, how can I change the object of the class itself?
Your #removeDuplicates method is attempting to mutate the list object it belongs to (known by this, within this class), and as such should actually make those modifications to the list itself (rather than a copy). Note as well, that by iterating your newly-made list wordDuplicate, the for loop will not actually execute (since there are no values inside the list). I would personally keep track using a Set (namely, HashSet with a roughly O(1) lookup, aka nearly constant-time), while taking advantage of the Iterator#remove method:
public void removeDuplicates() {
Set<T> seen = new HashSet<>();
Iterator<T> itr = this.iterator(); //similar to the mechanics behind for-each
while (itr.hasNext()) { //while another element can be found
T next = itr.next(); //get the next element
if (!seen.add(next)) { //#add returns "true" only if it was not in the Set previously
itr.remove(); //if it was previously in the set, remove it from the List
}
}
}
Note as well, that the semantics you are describing nicely fit the definition of a Set, which is a collection of items that do not contain duplicates. There are varients of Set (i.e. LinkedHashSet) which also allow linear traversal of the elements, based on insertion-order.
For a simpler, non-iterator solution, you could also do a "dirty swap" of the elements after your calculation, which would be similar to what you attempted to achieve via this = list:
public void removeDuplicates() {
Set<T> seen = new LinkedHashSet<>(); //to preserve iteration order
for (T obj : this) { //for each object in our current list
seen.add(obj); //will only add non-duplicates!
}
this.clear(); //wipe out our old list
this.addAll(seen); //add back our non-duplicated elements
}
This can be quicker to write, but would be less performant than the in-place removal (since the entire list must be wiped and added to again). Lastly, if this is a homework problem, try to avoid copy-pasting code directly, and instead write it out yourself at the very least. Merely working towards a solution can help to solidify the information down the line.
It's not possible in Java. this cannot be reassigned. Why (and when) do you need to re-assign an object from within itself?
When you have code such as obj.replace(otherObj) with an imaginary implementation of void replace(Object other) { this = other; }, then why not simply write obj = otherObj to update the reference?
Further clarifications after comments:
ArrayList is not meant to be inherited. If you want to write your own list collection, extend AbstractList. Your custom list can then use composition to delegate to its inner list.
Related
I have sorted my List and put sorted list in my table, now i want to unsort list but how to do that(i have JCheckBox to check when i want to sort my list and uncheck to unsort it)?
sort.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
boolean n = sort.isSelected();
if (n) {
AutoListSort comparator = new AutoListSort();
Collections.sort(Controller.getList(), comparator);
refresh.refresh();
}
}
});
My sorting class:
public class AutoListSort implements Comparator<Auto> {
#Override
public int compare(Auto person1, Auto person2) {
return person1.getGodiste().compareTo(person2.getGodiste());
}
}
I'm not aware of any generic way to "unsort" a sorted list/collection. The easiest thing to do is probably to maintain two lists: The original (unsorted) list and the sorted list.
Keep the previous state (an unsorted list) and update it right before the sort operation is performed.
Create a field (e.g. addedAt - the date of addition to the list) to make a backup possible.
I would like to call your attention to the way you are dealing with the controller. You are changing its state rather than providing the state you want to display. The idea I suggest is to pass a sorted copy to the controller and to keep the original data in somewhere else (e.g. in a service).
The second thing, you should think over, is a place where a Comparator should be initialised. You don't necessarily need to create a Comparator every time the event occurs.
The third point relates the AutoListSort. Make sure that the arguments and the Auto#getGodiste calls don't return a null, otherwise, an NPE is likely to happen. BTW, I would use the statement
Comparator.comparing(Auto::getGodiste).compare(person1, person2);
which seems to be more expressive for me.
I have a list of objects like the next class:
class A {
private String property1;
private String property2;
//Setters && Getters
}
So, after some operations I need to update the list with a default value with some logic like next:
listOfA.forEach(item -> {
item.setProperty1(findSomething());
}
This logic is repeated several times so I'm looking to export it to a method. So, my question is related to this method: Should I update the copy reference of the list with a void method, return it or create new list and update it?:
Option 1: Update the copy reference of the list
private void updateList(List<A> listOfA) {
listOfA.forEach(item -> {
item.setProperty1(findSomething());
}
}
Option 2: Return it
private List<A> updateList(List<A> listOfA) {
listOfA.forEach(item -> {
item.setProperty1(findSomething());
}
return listOfA;
}
Option 3: Create a new list from the other, update this and return it
private List<A> updateList(List<A> listOfA) {
List<A> newList = new ArrayList<>();
//Logic to copy listOfA in newList....
newList.forEach(item -> {
item.setProperty1(findSomething());
}
return newList ;
}
In the end it is very much personal opinion which option you prefer. There are however some considerations that might help you in the decision process:
The first and second option are virtually the same. Both operate on the List that is passed in as a parameter. The updating of the list does not create anything new. This would suggest option 1 as the solution to chose, as with only the signature alone (no additional documentation) option 2 might indicate that the returned list is a new List instance.
Returning the List as in option 2 and 3, has the advantage that you can execute further operations on that list, which make it changeable.
The last option employs defensive copy to actually create a new instance of the input List and operate on that list. While it is good practice to do so, it can have some side effects, that may be unwanted. With option 2 it is not required that the returned list is assigned to anything, as it is the same instance that was passed in as parameter. This is not the case of option 3. Here the result must be assigned, otherwise it becomes eligible for garbage collection.
Everything depends on the situation.
Option 1
This case is suitable when you do not need to use your list anywhere else. I mean that if other object has this list reference as member then this object will have this member modified too.
Option 2
This case seems like case 1 and you can use this method as case 1 but here you return your list. It brings some advantage in first case, you can use your method in chain of Stream API or Optionals:
private List<A> updateList(List<A> listOfA) {
List<A> newList = new ArrayList<>();
//Logic to copy listOfA in newList....
newList.forEach(item -> item.setProperty1(findSomething()));
return newList ;
}
public List<A> myMethod() {
List<A> myList = null;
// possible initialization of list
// ...
// here we update list. In the case when list is null then we do not modify it
return Optional.ofNullable(myList).map(this::updateList).orElse(null);
}
Option 3
In this case you copy array into another one. It make sense in the case when initial array should not be modified, for example it is field of some other class.
Method :3
when u r making a new list object it needs a certain memory in heap. And then you are just copy the content from your agrument list and update it and return the new list. Here creating a new list object takes an extra headache. No need for it.
Method :2
In this method no new list is created bt you return the same list. While java works on call by value (here values means values of the ref object). You can get the updated list on the calling method not need to return it. While u r returing an object u r increasing metadata of that method.
Method :1
It is the best approach. Here u are using the benefit of call by value (here values means values of the ref object). No unnecessary extra memory is occupied.
No unnecessary return. Thats the right approch.
In Java, a set only checks for equality of an object with objects already in the set only at insertion time. That means that if after an object is already present in the set, it becomes equal to another object in the set, the set will keep both equal objects without complaining.
EDIT: For example, consider a simple object, and assume that hashCode and equals are defined following best practices/
class Foo {
int foo;
Foo(int a){ foo = a; }
//+ equals and hashcode based on "foo"
}
Foo foo1 = new Foo(1);
Foo foo2 = new Foo(2);
Set<Foo> set = new HashSet<Foo>();
set.add(foo1);
set.add(foo2);
//Here the set has two unequal elements.
foo2.foo = 1;
//At this point, foo2 is equal to foo1, but is still in the set
//together with foo1.
How could a set class could be designed for mutable objects? The behavior I would expected would be the following: If at any time one of the objects in the set becomes equal to another object in the set, that object is deleted from the set by the set. Is there one already? Is there a programming language that would make this easier to accomplish?
I don't think this can be reliably done in Java in the general sense. There is no general mechanism for ensuring a certain action on mutation of an object.
There a few approaches for solutions that may be sufficient for your use case.
1. Observe elements for changes
You need to have control over the implementation of the types that go into the set
Small performance cost whenever an object in your set updates
You could try to enforce an observer like construction where your Set class is registered as an Observer to all its items. This implies you'd need to control the types of objects that can be put into the Set (only Observable objects). Furthermore, you'd need to ensure that the Observables notify the observer for every change that can affect hashcode and equals. I don't know of any class like this that exists already. Like Ray mentions below, you'll need to watch out for potential concurrency problems as well.
Example:
package collectiontests.observer;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Observable;
import java.util.Observer;
import java.util.Set;
public class ChangeDetectingSet<E extends Observable> implements Set<E>, Observer {
private HashSet<E> innerSet;
public void update(Observable o, Object arg) {
innerSet.remove(o);
innerSet.add((E)o);
}
public int size() {
return innerSet.size();
}
public boolean isEmpty() {
return innerSet.isEmpty();
}
public boolean contains(Object o) {
return innerSet.contains(o);
}
public Iterator<E> iterator() {
return innerSet.iterator();
}
public Object[] toArray() {
return innerSet.toArray();
}
public <T> T[] toArray(T[] a) {
return innerSet.toArray(a);
}
public boolean add(E e) {
e.addObserver(this);
return innerSet.add(e);
}
public boolean remove(Object o) {
if(o instanceof Observable){
((Observable) o).deleteObserver(this);
}
return innerSet.remove(o);
}
public boolean containsAll(Collection<?> c) {
return innerSet.containsAll(c);
}
public boolean addAll(Collection<? extends E> c) {
boolean result = false;
for(E el: c){
result = result || add(el);
}
return result;
}
public boolean retainAll(Collection<?> c) {
Iterator<E> it = innerSet.iterator();
E el;
Collection<E> elementsToRemove = new ArrayList<E>();
while(it.hasNext()){
el = it.next();
if(!c.contains(el)){
elementsToRemove.add(el); //No changing the set while the iterator is going. Iterator.remove may not do what we want.
}
}
for(E e: elementsToRemove){
remove(e);
}
return !elementsToRemove.isEmpty(); //If it's empty there is no change and we should return false
}
public boolean removeAll(Collection<?> c) {
boolean result = false;
for(Object e: c){
result = result || remove(e);
}
return result;
}
public void clear() {
Iterator<E> it = innerSet.iterator();
E el;
while(it.hasNext()){
el = it.next();
el.deleteObserver(this);
}
innerSet.clear();
}
}
This incurs a performance hit every time the mutable objects change.
2. Check for changes when Set is used
Works with any existing object you want to put into your set
Need to scan the entire set every time you require info about the set (performance cost may get significant if your set gets very large).
If the objects in your set change often, but the set itself is used rarely, you could try Joe's solution below. He suggests to check whether the Set is still correct whenever you call a method on it. As a bonus, his method will work on any set of objects (no having to limit it to observables). Performance-wise his method would be problematic for large sets or often used sets (as the entire set needs to be checked at every method call).
Possible implementation of Joe's method:
package collectiontests.check;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Set;
public class ListBasedSet<E> {
private List<E> innerList;
public ListBasedSet(){
this(null);
}
public ListBasedSet(Collection<E> elements){
if (elements != null){
innerList = new ArrayList<E>(elements);
} else {
innerList = new ArrayList<E>();
}
}
public void add(E e){
innerList.add(e);
}
public int size(){
return toSet().size();
}
public Iterator<E> iterator(){
return toSet().iterator();
}
public void remove(E e){
while(innerList.remove(e)); //Keep removing until they are all gone (so set behavior is kept)
}
public boolean contains(E e){
//I think you could just do innerList.contains here as it shouldn't care about duplicates
return innerList.contains(e);
}
private Set<E> toSet(){
return new HashSet<E>(innerList);
}
}
And another implementation of the check always method (this one based on an existing set). This is the way to go if you want to reuse the existing sets as much as possible.
package collectiontests.check;
import java.util.Collection;
import java.util.Comparator;
import java.util.Iterator;
import java.util.NavigableSet;
import java.util.SortedSet;
import java.util.TreeSet;
public class ChangeDetectingSet<E> extends TreeSet<E> {
private boolean compacting = false;
#SuppressWarnings("unchecked")
private void compact(){
//To avoid infinite loops, make sure we are not already compacting (compact also gets called in the methods used here)
if(!compacting){ //Warning: this is not thread-safe
compacting = true;
Object[] elements = toArray();
clear();
for(Object element: elements){
add((E)element); //Yes unsafe cast, but we're rather sure
}
compacting = false;
}
}
#Override
public boolean add(E e) {
compact();
return super.add(e);
}
#Override
public Iterator<E> iterator() {
compact();
return super.iterator();
}
#Override
public Iterator<E> descendingIterator() {
compact();
return super.descendingIterator();
}
#Override
public NavigableSet<E> descendingSet() {
compact();
return super.descendingSet();
}
#Override
public int size() {
compact();
return super.size();
}
#Override
public boolean isEmpty() {
compact();
return super.isEmpty();
}
#Override
public boolean contains(Object o) {
compact();
return super.contains(o);
}
#Override
public boolean remove(Object o) {
compact();
return super.remove(o);
}
#Override
public void clear() {
compact();
super.clear();
}
#Override
public boolean addAll(Collection<? extends E> c) {
compact();
return super.addAll(c);
}
#Override
public NavigableSet<E> subSet(E fromElement, boolean fromInclusive, E toElement, boolean toInclusive) {
compact();
return super.subSet(fromElement, fromInclusive, toElement, toInclusive);
}
#Override
public NavigableSet<E> headSet(E toElement, boolean inclusive) {
compact();
return super.headSet(toElement, inclusive);
}
#Override
public NavigableSet<E> tailSet(E fromElement, boolean inclusive) {
compact();
return super.tailSet(fromElement, inclusive);
}
#Override
public SortedSet<E> subSet(E fromElement, E toElement) {
compact();
return super.subSet(fromElement, toElement);
}
#Override
public SortedSet<E> headSet(E toElement) {
compact();
return super.headSet(toElement);
}
#Override
public SortedSet<E> tailSet(E fromElement) {
compact();
return super.tailSet(fromElement);
}
#Override
public Comparator<? super E> comparator() {
compact();
return super.comparator();
}
#Override
public E first() {
compact();
return super.first();
}
#Override
public E last() {
compact();
return super.last();
}
#Override
public E lower(E e) {
compact();
return super.lower(e);
}
#Override
public E floor(E e) {
compact();
return super.floor(e);
}
#Override
public E ceiling(E e) {
compact();
return super.ceiling(e);
}
#Override
public E higher(E e) {
compact();
return super.higher(e);
}
#Override
public E pollFirst() {
compact();
return super.pollFirst();
}
#Override
public E pollLast() {
compact();
return super.pollLast();
}
#Override
public boolean removeAll(Collection<?> c) {
compact();
return super.removeAll(c);
}
#Override
public Object[] toArray() {
compact();
return super.toArray();
}
#Override
public <T> T[] toArray(T[] a) {
compact();
return super.toArray(a);
}
#Override
public boolean containsAll(Collection<?> c) {
compact();
return super.containsAll(c);
}
#Override
public boolean retainAll(Collection<?> c) {
compact();
return super.retainAll(c);
}
#Override
public String toString() {
compact();
return super.toString();
}
}
3. Use Scala sets
You could cheat and do away with mutable objects (in the sense that instead of mutating, you'd create a new one with one property changed) in your set. You can look at the set in Scala (I thought it was possible to call Scala from Java, but I'm not 100% sure): http://www.scala-lang.org/api/current/scala/collection/immutable/IndexedSeq.html
You will not find a general datastructure that can take just any object for this purpose. That kind of set would have to constantly monitor its elements, which among other things would lead to a lot of questions on concurrency.
However, I can imagine something based on the practically unknown class java.util.Observable. You could e.g. write a class ChangeAwareSet implements Set<? extends Observable>, Observer. When an element is added to this Set, it would register as an Observer and so be notified on all changes to that object. (But don't expect this to be very efficient, and you might encounter concurrency problems in this scenario as well.)
You can get the behaviour you're after by using another collection, such as an ArrayList. The contains and remove methods for a List make no assumptions about objects remaining unchanged.
Since changes can happen at any time, there isn't much room for optimisation. Any operations would need to perform a full scan over all contents, as any object could have changed since the last operation.
You may or may not wish to override add to check whether the object currently appears to be present. Then, when using or printing, use new HashSet(list) to eliminate objects which are currently duplicate.
Your problem is the identity of an object vs state. identity is not mutable over time, state is. In your set, you should preferably rely on identity because this is the only warranty for not introducing duplication by mutation, or you must rebuild the Set each time there is an element mutation. Technically, equals() and hashCode() should be constant over time to reflect identity.
As #assylias commented, there is certainly an alternative if you need to have a collection with combined identity and state.
have a Map<TheObject, List<State>> rather than a Set<TheObjectWithState>
remove the object from the Set before mutation, then check if it exists after mutation, add it if there is no duplicate.
You have two broad strategies here, I expect both wont give great performance (but that might not be a problem for your use).
Have your set register with the objects for changes.
Instead of modifying the set constantly, only update it when it is used.
Note that these solutions will have a slight difference in behavior.
Register for changes
This involves adding an Observable pattern (or alternatively a listener) to all objects stored in the set.
When an object is in the Set, the Set will register for changes. When an object changes it will signal the Set it has changed and the Set will change accordingly.
The most naive implementation is to just remove all equals objects and then re-add the object at any change. The naive implementation is always a good start so you can write a proper test set, and from there on you can improve the performance step by step.
Thread safety
Be careful when using this Set or the objects in it from multiple threads. Which a solution like this there are a lot of risks for deadlocks, so you would probably end up with a single ReadWriteLock for both the Set and the objects stored in it.
Update it when it is used
An alternative is a lazy strategy: only update the set when it is used. This is very useful when there are many changes to the objects but the set is not used as often.
It uses the following set idea (this makes me think of Schrodinger's cat):
If nobody is looking at the Set, does it matter what is in it?
An object is only defined by it's behavior on it's interface(s). So instead you can evaluate your set (and update it accordingly) at the point when the information is used.
General remarks
Here follow some remarks that apply to both choices.
Desired behavior
Watch out that you might run in to really weird behavior with a set like this. When you remove an object from the Set because it has become equal to another object, the outside world will not know you have removed that object.
See for instance the following, suing your Foo class:
Foo foo1 = new Foo(1);
Foo foo2 = new Foo(2);
Set<Foo> set = new MySet<Foo>();
set.add(foo1);
set.add(foo2);
foo2.foo = 1; // foo or foo2 is removed from the set.
foo2.foo = 3; // now the set contains with a foo or with 1 or with 3.
As an alternative you could take the objects stored in a list and convert them to set at the time you use.
I am still not sure you understand the implications. If you have 2 objects which CAN equal each other at any point in time, may not equal each other at another point in time, therefore by default they are deemed as separate objects even though at the moment they may appear to be identical.
I would go about it at a different angle, and check if the set contains what the object will become when you perform the change, if you do not want it to exist in that set when it does equal another object.
Use safe publishing: Don't allow access to the Set or its elements; publish a deep copy instead.
You need a way of making a copy of a Foo; I'll assume a copy constructor.
private Set<Foo> set;
public Set<Foo> getFoos() {
// using java 8
return set.stream().map(Foo::new).collect(Collectors.toSet());
}
You should also save a copy of a Foo, rather than saving a foo, because the caller will have a reference to the added Foos, so the client can mutate them. Add an accessor method for this:
public boolean addFoo(Foo foo) {
return set.add(new Foo(foo));
}
This is a great question! Perhaps it is the source of many bugs! This is not just an issue with duplicates. Almost all the methods will return incorrect answers even without duplicates. Consider a hash set. If the hash changes even without creating a duplicate, the contains method will now return incorrect results since the object is in the wrong hash bucket. Similarly remove will not work correctly. For sorted sets, the iterator order will be incorrect.
I like the Observable pattern mentioned by #Thirler. Other solutions seem inefficient. In the observable approach mentioned there, there is a dependency that that implementer of the elements to be added to the set correctly notifies the set whenever and update occurs. The approach I mention here is somewhat more restrictive, but passes responsibility for the correct implementation to the set creator. So as long as the set is implemented correctly it will work for all users of the set. (See below for more on why the observer pattern is hard to implemented)
Here is the basic idea: Suppose that you want to create a set of foo object. We'll create a class called SetFoo. All aspects of foo objects are maintained by the set itself, including construction, and any changes to it. There is no way for any other user to create a Foo object directly because it is an inner class of SetFoo and the constructor is either private or protected. For example lets suppose we implement a class SetFoo where Foo has methods void setX(int x) and Foo int getX(). The class SetFoo would have methods like:
Foo instance(int x) //Returns the instance of foo if it exists, otherwise creates a new one and returns it.
Let's say that internally SetFoo maintains a hashset of Foo objects.
Now the setX method of Foo would be defined to remove and re-add the element to the hashset if the value of x changes.
We can extend the idea of SetFoo to contain any number of elements, all of which are maintained by the set. This is really easy to implement for any kind of objects, however, it does require that the elements are all maintained by the set (including construction and all setter methods). Of course to make it multi-thread safe would take more work.
From the point of view of any user of the SetFoo class things would be simple:
Foo f = setFoo.instance(1);
....
f.setX(2);
...
f.setX(3)
f = setFoo.instance(1); // Would internally create a new one since it was changed.
f= setFoo.instance(3) // Already in the set so no new one is created.
Now we can also add other methods to SetFoo, like
boolean contains (int x);
Iterator<Integer> iterator();
boolean remove(int x);
etc...
or we can add various methods to Foo:
remove() // removes foo from the set.
exists() // if foo still in the set?
add() // add foo back to the set
In the case where the elements can contain many fields we can have a FooSpec class. Suppose Foo contains an int x and int y. Then FooSpec would have getX, SetX, getY, setY methods and could be constructed using new FooSpec. Now setFoo would have methods like:
Foo instance(FooSpec fooSpec)
Collection<Foo> instanceAll(Collection<FooSpec> col)
...etc
So now you might be wondering why the observer pattern approach is subject to potential errors. With that approach the user of the set must correctly notify the set when it changes. That is effectively the same level of difficulty as as implementing a deeply immutable object (which may not be that easy). For example if the elements of the set are themselves collections or collections of collections, then you would need to make sure that you notify the set whenever anything in the collection (deeply) changes.
Leaving the responsibility to "deeply" notify the set, to the user of the set, would place a lot of burden on the developer. Better to implement a framework that would provide for objects that "deeply" notify.
Set does makes use of hashCode and equals method. But when you say
it becomes equal to another object in the set, the set will keep both equal objects without complaining.
It's not the case. If you run add method by adding already existing element, it will return you false saying hey you already have an object in set.
Set is a mathematical term which does not allow duplicates and is the case with Java Set. Set is agnostic about whether the object that you are inserting into it is mutable or immutable. It's just like a collection which hold values.
Edit:
As per the code, checks in set would be done when you insert the element to the Set and then if it changes, it wont care about it.
Here are a few aspects for one approach I see
Use a 'Dynamic Element Set'
It might be good to have a clear distinction between having a mutable set class for immutable elements, as well as another set class for mutable elements
The set class for mutable elements would be 'dynamic element sets', and require each element to have a pointer to the containing set
Element itself registers change on modification
You could have to have a corresponding wrapper class for the elements contained in the set, so that it can register with the containing element
Hash table for fast single-threaded uniqueness checks
When adding an element to the set, the set will compute a hash of the element, and add that to a table (I'm sure thats how sets work anyhow)
Use this to check uniqueness and do elimination in O(1) time
Dirty / clean state for multithreaded cases
When you update an element, mark the containing set as 'dirty'
When the containing set is dirty, you can at some point rerun the uniqueness test to see if all elements are unique.
While that is happening, it probably should block any modifications to the elements until it has completed
With this, you probably deviate from exact uniqueness property.
Consider this: You have 3 elements in the list: A, B, and C, each with unique values
You change element B to same value as A
Mark as dirty
Change element A to a different, unique value
Still marked as dirty
Run the uniqueness check
So if you don't need absolute set property, but only an approximate, this might work
Otherwise if you need absolute set property, in a multithreaded case might not work
Updates seem to be pretty cheap, so you might be able to get away with it
Is this really a 'set'?
So, this kinda assumes that the elements are only modified from the provided interface for the set
When you wrap the base class of the element into the set, it should probably make a deep copy of the element to help prevent an element getting modifications from a non-registering reference object
So its not just a 'set', but rather imposes a requirement on the type of element being passed
It adds an interface layer to the element class
As such, the elements themselves are part of a new object in a sense I guess
Other thoughts
So of course, if one time an element can become the same as another element, then in the future it could also change to being different again
You are implying that a solution being searched for would be needed in a specific problem where that kind property is needed: Elements that are transiently duplicate need to be eliminated
java.util.Set specifies only methods that return all records (via Iterator or array).
Why is there no option to return any value from Set?
It has a lot of sense in the real life. For example, I have a bowl of strawberries and I want to take just one of them. I totally don't care which one.
Why I can't do the same in java?
This is not answerable. You'd have to ask the original designers of the Java collections framework.
One plausible reason is that methods with non-deterministic behavior tend to be problematic:
They make unit testing harder.
They make bugs harder to track down.
They are more easily misunderstood and misused by programmers who haven't bothered to read the API documentation.
For hashtable-based set organizations, the behavior a "get some element" method is going to be non-deterministic, or at least difficult to determine / predict.
By the way, you can trivially get some element of a non-empty set as follows:
Object someObject = someSet.iterator().next();
Getting a truly (pseudo-)random element is a bit more tricky / expensive because you can't index the elements of a set. (You need to extract all of the set elements into an array ...)
On revisiting this, I realized that there is another reason. It is simply that Set is based on the mathematical notion of a set, and the elements of a set in mathematics have no order. It is simply meaningless to talk about the first element of a mathematical set.
A java.util.Set is an unordered collection; you can see it as a bag that contains things, but not in any particular order. It would not make sense to have a get(int index) method, because elements in a set don't have an index.
The designers of the standard Java library didn't include a method to get a random element from a Set. If you want to know why, that's something you can only speculate about. Maybe they didn't think it was necessary, or maybe they didn't even think about it.
It's easy to write a method yourself that gets a random element out of a Set.
If you don't care about the index of the elements, try using Queue instead of Set.
Queue q = new ArrayDeque();
q.element(); // retrieves the first object but doesn't remove
q.poll(); // retrieves and removes first object
While a plain Set is in no particular, SortedSet and NavigableSet provide a guaranteed order and methods which support this. You can use first() and last()
SortedSet<E> set = ...
E e1 = set.first(); // a value
E e2 = set.last(); // also a value.
Actually the iterator is a lot better then using get(position) (which is something you can do on a java.util.List). It allows for collection modifications during the iterations for one thing. The reason you don't have them in sets is probably because most of them don't guarantee order of insertion. You can always do something like new ArrayList<?>(mySet).get(position)
If you are not concerned with performance you can create a new type and back the data in an arraylist.
( Please note before donwvoting this is just an naive implementation of the idea and not the proposed final solution )
import ...
public class PickableSet<E> extends AbstractSet<E>{
private final List<E> arrayList = new ArrayList<E>();
private final Set<E> hashSet = new HashSet<E>();
private final Random random = new Random();
public boolean add( E e ) {
return hashSet.add( e ) && arrayList.add( e );
}
public int size() {
return arrayList.size();
}
public Iterator<E> iterator() {
return hashSet.iterator();
}
public E pickOne() {
return arrayList.get( random.nextInt( arrayList.size() ) );
}
}
Of course, since you're using a different interface you'll have to cast to invoke the method:
Set<String> set = new PickableSet<String>();
set.add("one");
set.add("other");
String oneOfThem = ((PickableSet)set).pickOne();
ie
https://gist.github.com/1986763
Well, you can with a little bit of work like this
Set<String> s = new HashSet<String>();
Random r = new Random();
String res = s.toArray(new String[0])[r.nextInt(s.toArray().length)];
This grabs a randomly selected object from the set.
I have a list. The list can contain multiple items of the same enum type.
Lets say i have an enum : TOY which has values: BALL, DOLL, PLAYSTATION. I want to know how many PLAYSTATION items are in a list with the type TOY. (ie, List<Toy> toys)
What is the best possible solution for this? I don't want to keep iterating through the list everytime.
You can use Apache commons-collections' HashBag. It has a getCount(Object) method which will suit you.
java.util.Collections has a method called frequency(Collection c, Object type).
Usage in my question:
int amountOfPlayStations = Collections.frequency(toys, TOY.PLAYSTATION);
Why don't you create a decorator for the type of list you're using which stores a list of counts for each enum type have been added/removed internally. That way you could use it as a normal list but also add some extra functionality for querying how many of which type are currently contained.
All you'd need to do would be to override the add/remove/addAll etc methods and increment your counters before passing it on to the real list type. The best part about it would be that you could decorate any list type with your new wrapper.
At the very least, a utility method like:
public int count(List<Toy> haystack, Toy needle) {
int result;
for (Toy t : haystack) {
if (t == needle) {
result++;
}
}
return result;
}
Would let you concisely refer to the number of PLAYSTATIONs from elsewhere in the code. Alternatively if you knew the list was unlikely to change, building a Map<Toy, Integer> would let you build up the counts for all items once.
If you don't want to have to iterate over the entire collection each time, another alternative would be to write a ForwardingList implementation. The main benefits of this over the HashBag suggestion are:
it supports generics
it implements the List interface, so you can pass it to any method that expects a List
There is a downside to this approach however, in that you have to write a bit of plumbing code to get it up and running.
Below is a quick example of how you could do it. Note that if you do this you should override all methods that add/delete from the list, otherwise you may end up in an inconsistent state:
import com.google.common.collect.ForwardingList;
public class CountingList<E> extends ForwardingList<E> {
private List<E> backingList = new LinkedList<E>();
private Map<E, Integer> countMap = new HashMap<E, Integer>();
#Override
protected List<E> delegate() {
return backingList;
}
#Override
public boolean add(E element) {
backingList.add(element);
if(countMap.containsKey(element)) {
countMap.put(element, countMap.get(element) + 1);
} else {
countMap.put(element, 1);
}
return true;
}
public int getCount(E element) {
Integer count = countMap.get(element);
return count != null ? count.intValue() : 0;
}
}
Extend java.util.List method and override all mutator methods, i.e. the ones that are used for add or delete elements and also ones used to clear the list. Add a reference to a private java.util.Map which will hold the number of items per type. Add accessor methods which will return current number of elements per type.
The HashBag (by Bozho) seems to be your best bet. But a bit more general would be Googles Collections 2 with an appropriate Predicate:
List<Toy> toys;
List<Toy> playstations = Collections2.filter( toys, new Predicate() {
boolean apply(TOY toy){
return toy == TOY.PLAYSTATION;
}
});
Besides all those solutions (I have a weakness for the Collections.Frequency call), i would recommend you to take a look at google collections, and particularly to [Collections2.transform][2], which could give you a live view on items.
[2]: http://google-collections.googlecode.com/svn/trunk/javadoc/com/google/common/collect/Collections2.html#transform(java.util.Collection, com.google.common.base.Function)