I have an array which looks like this:
array = { Person1, Person2, Person3, Person1, Person2, Person3};
Now how can I get an int with the total count of unique Persons? That means a Person which was already counted, shouldn't be counted again.
In the give example above should return the int value of 3
int uniq = 3;
How can I do this task?
If all you want is the size, this is a correct version of one of the other answers:
Set<Person> set = new HashSet<Person>(Arrays.asList(array));
int count = set.size();
This assumes that either your Person type has an equals method that will tell you whether two persons are the same, or if there's no equals, the default equals is OK (the default returns true if the references are equal).
P.S.: if you've defined your own Person in equals, you must also define hashCode or else this solution won't work. hashCode must be defined so that if two Persons are equal then they also have the same hash code. See What issues should be considered when overriding equals and hashCode in Java?.
the easiest way is to avoid doublon when you add the person in your array.
To do that, when you add a Person in the array, you go through all the array and verify that you don't already have it :)
If you need to have the doublon in the list, then you should create a tempArray and only add the different person in this new array like described in the other method, so in the end you will have your good number in the tempArray.size()
Try:
List<Person> uniqueList = new ArrayList<Person>(new LinkedHashSet<Person>( array.asList() ).sort() );
uniqueList.size(); //Number of unique objects
Related
I ran into a seemingly simple problem that I haven't been able to figure out. Basically, my list holds a number of ints which represent different items, which works fine, but I need to be able to check if the list contains the same integer more than once and then remove them from the list.
if (myList.contains(100)) { // I want to check if the int '100' exists in myList twice
myList.remove(new Integer(100)); // I want to remove the 2 aforementioned duplicate integers
}
Apologies if my explanation wasn't the clearest. Thanks in advance!
EDIT: To clarify, I want the list to contain duplicates but I want to be able to check if the duplicate exists X times and then remove those instances from the list.
i.e.
I might want to add the int 100 7 times, and then later check if it exists twice and then remove 2 instances of it from the list only.
you can create a method to accomplish the task at hand, something along the lines of this:
private static boolean removeSpecfiedNumber(int number,int numberOfTimes, List<Integer> integerList){
if(integerList.stream().filter(x -> x == number).count() >= numberOfTimes){
for (int i = 0; i < numberOfTimes; i++) {
integerList.remove((Integer)number);
}
return true;
}
return false;
}
The parameter number is the number you want to check its occurrences i.e. 100 in your case.
The parameter numberOfTimes is the number of times you want to remove that element from the list.
The parameter integerList is, of course, the list you want to remove the elements from.
Let's take the code below as an example:
List<Integer> myList = new ArrayList<>();
myList.add(100);
myList.add(200);
myList.add(100);
myList.add(100);
myList.add(100);
myList.add(100);
myList.add(100);
myList.add(100);
removeSpecfiedNumber(100,2,myList);
System.out.println(myList);
this will remove 100 twice from myList and should, therefore, yield the elements below:
[200, 100, 100, 100, 100, 100]
The method return type can be void if you want, However, the return type of boolean can come in handy at times hence I've used that approach.
Also, you need not use the static modifier if you're dealing with objects, therefore you can remove it.
1) myList.remove(new Integer(100)); will remove only the first occurrence that is equals to 100.
You should loop on remove() while the list contains still an object with the same value.
2) To know if the list contains more than once the object, you could use indexOf() and lastIndexOf() .
If these are distinct, it means that you have more than one element.
So according to your requirement, you can remove all of them with the method described in the point 1.
Integer valueToCheck = 100;
if ( myList.indexOf(valueToCheck) != myList.lastIndexOf(valueToCheck) ) {
while (myList.contains(valueToCheck)){
myList.remove(valueToCheck);
}
}
You can use a Set which does not allowed duplicate keys e.g.
Set<Ineger> foo = new HashSet<>(myList);
And you can create a new List from that or use it as it is.
Starting java 8 you can use java stream api in such way:
List<Integer> i = new ArrayList<Integer>();
i.add(1);
i.add(2);
i.add(3);
i.add(1);
List<Integer> collect = i.stream().distinct().collect(Collectors.toList());
NOTE: new list will be created.
I have this class:
class Employee {
String name;
int type; // 0 = ADMIN, 1 = NON-ADMIN
}
Now I have a List of Employees
List<Employee> liste;
Can I sort the list in a way that all ADMIN employees are sorted, and appear before all NON-ADMIN sorted employees in the result?
Use a comparator, and sort first by type and then by name (assuming that's what you want).
java.util.Collections.sort(list, (a,b)->
a.type != b.type ? a.type - b.type : a.name.compareTo(b.name);)
Something like that should work assuming that's actually what you want.
String's compare to
This is the definition of lexicographic ordering. If two strings are
different, then either they have different characters at some index
that is a valid index for both strings, or their lengths are
different, or both. If they have different characters at one or more
index positions, let k be the smallest such index; then the string
whose character at position k has the smaller value, as determined by
using the < operator, lexicographically precedes the other string. In
this case, compareTo returns the difference of the two character
values at position k in the two string -- that is, the value:
this.charAt(k)-anotherString.charAt(k)
If there is no index
position at which they differ, then the shorter string
lexicographically precedes the longer string. In this case, compareTo
returns the difference of the lengths of the strings -- that is, the
value:
this.length()-anotherString.length()
That's from the docs. Don't rely on compareTo returning exactly 1,0,-1. Instead just remember +,0,-. Your comparator would be wrong if the difference in length is 1 and the difference in types is -1, for example.
You could make a composite comparator:
list.sort(Comparator.comparingInt(Employee::getType).thenComparing(Employee::getName));
this way, non admin appears first :
List<Employee> temp = new ArrayList<Employee>();
while(it.hasNext()){
Employee employee = it.next();
if (employee.getType() == 0){
it.remove();
temp.add(employee);
}
}
staff.addAll(temp);
I'm doing a method that takes the value from a lot of objects with double getDelay(). But I need some help because I don't know how to save the 6 higher values. I thought to make a loop and save values in an array but I don't know how to insert a new value and delete the smallest and reordering the array. Any suggestions to save and order the values?
EDIT:
Thanks to all, I forgot to say that I have to save the object (or the name in a String with getName(), I don't care) too. I thought use queues but I don't control them a lot. How can I order it? Because if I use Array.sort I don't know of what objects are this values
You can just use Arrays.sort(yourArr) and then take the last N entries.
See answer: Java - Ordering array values from highest to lowest
You can add all values in an double[] array. Then use Arrays.sort() like this:
Arrays.sort(array,Collections.reverseOrder()); // this will sort array in descending order
Now you can access first 6 elements of this array to get largest 6 values.
EDIT: If you want to keep objects as well, you can use TreeMap<Double,Object>. Populate it with ids and objects. The elements in TreeMap are sorted by key which is Double here.
You can then retreive last 6 elements in TreeMap like this:
List<Object> highest = new ArrayList<Object>;
for(int i=0; i<6; i++){
Double last = treemap.getLastKey();
Object objLast = treemap.get(last);
hightest.put(objLast);
treemap.remove(last);
}
Note: I have used ArrayList to store objects with highest double if you want to keep both you can instead use Map implementation to save both double and Object. Hope this helps.
You'll actually want to create a Comparator<MyObject> and sort an array of MyObject directly:
Comparator<MyObject> myComparator = (o1, o2) -> {
o1.getDelay() > o2.getDelay() ? -1 : (o1.getDelay() < o2.getDelay() ? 1 : 0);
} // Reverse order by getDelay()
MyObject[] stuff;
Arrays.sort(stuff, myComparator);
for (int i = 0; i < 6; i++) {
doSomething(stuff[i]);
}
I am looking for a java data structure similar to an ArrayList that when I do an add or a push with only a value argument an index will be returned for me automatically.
For example:
ArrayList<String> elements = new ArrayList<String>();
String element = "foo";
String elementTwo = "bar";
int index1 = elements.add(element); //note this does not exist, i.e. returns bool in api
int index2 = elements.add(elementTwo);
System.out.println(elements.get(index1)); //would give "foo"
I could see writing a wrapper class around ArrayList that manages a counter that is incremented on every add operation and invoking:
ArrayList.add(int index, E element)
Do you really need to write a wrapper around ArrayList for this? This seems like something simple enough to be provided out of the box somewhere?
Edit:
I need the index (key) to be fixed and unique for this usecase. A map was suggested and I agree with that. Does anyone know of a map implementation that gives you an automatically (uniquely) generated key on a value insert? I am just trying to decide if I need to implement my own wrapper for this.
The element will be added at the end of the list. So you can use elements.size()-1 to get the new elements index.
Note that this will not work reliable if multiple threads are modifying the list at the same time.
EDIT: Also note that it might not be a good idea to use an ArrayLists index as a unique ID because an elements index can change (for example when you remove an element or insert a new one using add(int, Object)). If this is a problem depends on what you want to do with the index: If you only need it for a short time after adding an element and can be sure that the list is not modified in the meantime, there is no problem. In the other case even a method returning the index when calling add(Object) would not help because the index does not get updated in anyway. To prevent this issue you can:
Make sure you never remove elements from the list and never add elements using add(int, Object).
Instead of removing elements you could also set them to null using the method set(int, null). This way no elements index will change.
Use some other data structure like for example a map with a custom ID like helloannalil suggests in his answer.
EDIT 2: I did not find a appropriate, ready to use implementation (but this does not mean there is none, of course). To suggest a good solution, more information on the intended use of the data structure is needed, but here are some ideas and notes:
If the maximum number of elements is not to large, an ArrayList could be used and the elements index represents the ID. As stated above, to remove an element it can be set to null so that no indices are changed. When inserting, positions with null values can be reused.
You can also use one of the two methods show in this answer: https://stackoverflow.com/a/8939049/1347968 (keywords AtomicLong or IdentityHashMap)
Do not depend on the "uniqueness" of Object.hashCode() or System.identityHashCode(Object) as it is not guaranteed (try it by running the example at the bottom of Suns/Oracles Bug #6321873).
Well what I do in that cases (I love ArrayLists) is to get the last index by asking the size of the list:
String thing = "theThing";
List<String> strList = new ArrayList<String>();
strList.add(thing);
int indexOfThing = strList.size() - 1;
I mean, is easier than implement your own List and just works.
if you really want this function, you can use map but not list
Based on your comments and edited question I think you can extend a HashMap for your use like this:
public class MyMap<V> extends HashMap<Integer, V> {
private static final long serialVersionUID = 1L;
public int add(V elem) {
int key = System.identityHashCode(elem);
super.put(key, elem);
return key;
}
}
Then inside your class declare MyMap like this:
private MyMap<String> map = new MyMap<String>();
And then add your elements to MyMap like this:
.....
.....
String element = "foo";
String elementTwo = "bar";
int index1 = map.add(element);
int index2 = map.add(elementTwo);
Now you have index1 and index2 as indices of you inserted strings that you can use or pass around for the lifetime of your application. You can insert or remove elements in MyMap as many times you want but your indices (index1 and index2) will give you back your inserted elements like this:
String elem1 = map.get(index1); // will return "foo"
String elem2 = map.get(index2); // will return "bar"
String thing = "theThing";
List<String> strList = new ArrayList<String>();
strList.add(thing);
int indexOfThing = strList.size() - 1;
If you remove an item, this will no longer work.
I have an ArrayList<MyObject> that may (or may not) contain duplicates of MyObject I need to remove from the List. How can I do this in a way that I don't have to check duplication twice as I would do if I were to iterate the list in two for-loops and cross checking every item with every other item.
I just need to check every item once, so comparing A:B is enough - I don't want to compare B:A again, as I already did that.
Furthermore; can I just remove duplicates from the list while looping? Or will that somehow break the list and my loop?
Edit: Okay, I forgot an important part looking through the first answers: A duplicate of MyObject is not just meant in the Java way meaning Object.equals(Object), but I need to be able to compare objects using my own algorithm, as the equality of MyObjects is calculated using an algorithm that checks the Object's fields in a special way that I need to implement!
Furthermore, I can't just override euqals in MyObject as there are several, different Algorithms that implement different strategies for checking the equality of two MyObjects - e.g. there is a simple HashComparer and a more complex EuclidDistanceComparer, both being AbstractComparers implementing different algorithms for the public abstract boolean isEqual(MyObject obj1, MyObject obj2);
Sort the list, and the duplicates will be adjacent to each other, making them easy to identify and remove. Just go through the list remembering the value of the previous item so you can compare it with the current one. If they are the same, remove the current item.
And if you use an ordinary for-loop to go through the list, you control the current position. That means that when you remove an item, you can decrement the position (n--) so that the next time around the loop will visit the same position (which will now be the next item).
You need to provide a custom comparison in your sort? That's not so hard:
Collections.sort(myArrayList, new Comparator<MyObject>() {
public int compare(MyObject o1, MyObject o2) {
return o1.getThing().compareTo(o2.getThing());
}
});
I've written this example so that getThing().compareTo() stands in for whatever you want to do to compare the two objects. You must return an integer that is zero if they are the same, greater than 1 if o1 is greater than o2 and -1 if o1 is less than o2. If getThing() returned a String or a Date, you'd be all set because those classes have a compareTo method already. But you can put whatever code you need to in your custom Comparator.
Create a set and it will remove the duplicates automatically for you if the ordering is not important.
Set<MyObject> mySet = new HashSet<MyObject>(yourList);
Instantiate a new set-based collection HashSet. Don't forget to implement equals and hashcode for MyObject.
Good Luck!
If object order is insignificant
If the order is not important, you can put the elements of the list into a Set:
Set<MyObject> mySet = new HashSet<MyObject>(yourList);
The duplicates will be removed automatically.
If object order is significant
If ordering is significant, then you can manually check for duplicates, e.g. using this snippet:
// Copy the list.
ArrayList<String> newList = (ArrayList<String>) list.clone();
// Iterate
for (int i = 0; i < list.size(); i++) {
for (int j = list.size() - 1; j >= i; j--) {
// If i is j, then it's the same object and don't need to be compared.
if (i == j) {
continue;
}
// If the compared objects are equal, remove them from the copy and break
// to the next loop
if (list.get(i).equals(list.get(j))) {
newList.remove(list.get(i));
break;
}
System.out.println("" + i + "," + j + ": " + list.get(i) + "-" + list.get(j));
}
}
This will remove all duplicates, leaving the last duplicate value as original entry. In addition, it will check each combination only once.
Using Java 8
Java Streams makes it even more elegant:
List<Integer> newList = oldList.stream()
.distinct()
.collect(Collectors.toList());
If you need to consider two of your objects equal based on your own definition, you could do the following:
public static <T, U> Predicate<T> distinctByProperty(Function<? super T, ?> propertyExtractor) {
Set<Object> seen = ConcurrentHashMap.newKeySet();
return t -> seen.add(propertyExtractor.apply(t));
}
(by Stuart Marks)
And then you could do this:
List<MyObject> newList = oldList.stream()
.filter(distinctByProperty(t -> {
// Your custom property to use when determining whether two objects
// are equal. For example, consider two object equal if their name
// starts with the same character.
return t.getName().charAt(0);
}))
.collect(Collectors.toList());
Futhermore
You cannot modify a list while an Iterator (which is usually used in a for-each loop) is looping through an array. This will throw a ConcurrentModificationException. You can modify the array if you are looping it using a for loop. Then you must control the iterator position (decrementing it while removing an entry).
Or http://docs.oracle.com/javase/6/docs/api/java/util/SortedSet.html if you need sort-order..
EDIT: What about deriving from http://docs.oracle.com/javase/6/docs/api/java/util/TreeSet.html, it will allow you to pass in a Comparator at construction time. You override add() to use your Comparator instead of equals() - this will give you the flexibility of creating different sets that are ordered according to your Comparator and they will implement your "Equality"-Strategy.
Dont forget about equals() and hashCode() though...