Finding number of occurance of an element in a list - java

Is there a direct way to find out if the list contains duplicates?
Direct API method in some third party utils?
And if the list contains duplicates how many such duplicate elements exist in the list?
Code we can write but I want to know if any direct API exists?

You can count occurrences with
List<T> list =
Map<T, Integer> count = new HashMap<T,Integer>();
for(T t: list) {
Integer i = count.get(t);
if (i == null) i = 0;
count.put(t, i + 1);
}

No you'll have to do it by yourself. But you can use objects that won't allow to insert duplicate data (here)

It looks like you want something like this:
public int getNumOfElementInList(List<Object> myList, Object myElement){
int count = 0;
for(Object element: myList){
if(element.equals(myElement)) //or use instanceof instead, depending
count++;
}
return count;
}
This will give you the number of an element in a list. Alternatively, you could make a List instead of using count, and add the duplicate elements to the List, and return that.
Such as:
public List<DuplicateStats> getTotalNumOfElementInList(List<Object> myList){
List<DuplicateStats> dups = new ArrayList<DuplicateStats>();
int i;
for(Object element: myList){
if((i = dups.indexOf(element) != -1)
dups.get(i).addOne();
else
List.add(new DuplicateStats(element));
}
return count;
}
public class DuplicateStats {
private Object element;
private int count;
public DuplicateStats(Object o){
element = o;
}
public boolean equals(String compare){
return element.toString.equals(compare);
}
public void addOne(){
count++;
}
}
You can add getters, setters, etc. to the class DuplicateStats, but it will keep track of duplicates for you.

If you want an API you can find duplicates with Guava's Multiset.
Just add your list do the set and use the count method.

If you want to find out how many duplicates there are you could keep the list with duplicates, together with a set without duplicates. The number of duplicates is then just the size of the list minus the size of the set.

There are no built-in methods to do this. However you can use LinkedHashSet for example to solve this problem. It does not allow duplicates (as it acts like a set) but it preserves an order of elements (as it acts like a list). You can iterate over all of elements from your list and add them to LinkedHashSet, checking if add method returns true or false.

Related

best way to Iterate over a collection and array consecutively

Its a very trivial question and related to coding Style and I am just asking to make my coding style more readable
Suppose I have a Collection like linkedList and an Array and I need to iterate over both simultaneously.
currently the best way I know is to get a iterator over list and define a index variable outside the iterator loop and increment the index variable simultaneously to access both next elements {list and array}. Please refer the example below
LinkedList<Integer> list = new LinkedList<Integer>();
Integer[] arr = new Array[25];
// lets suppose both have 25 elements.
// My Iteration method will be
int index =0;
for (Integer val : list) {
System.out.println(val);
System.out.println(arr[index++]);
}
so is it the only way or is there any other way I can perform this iteration in more readable and more relatable manner, where I don't have to take index variable separately.
I know it can be possible that array might have less or more elements than collection but I am only talking about the cases where they have equal and we need to iterate over Both of them.
PS : anybody can write a code that a computer can understand, actual challenge is to write code which humans can understand easily.
What you have is essentially fine: it's simple, and simple can be sufficient to make code readable.
The only thing I would caution about is the side effect of index++ inside arr[index++]: if, say, you want to use the same value multiple times in the loop body, you couldn't simply copy+paste.
Consider pulling out a variable as the first thing in the loop to store the "current" array element (which is essentially what the enhanced for loop does for the list element).
for (Integer val : list) {
Integer fromArr = arr[index++];
// ...
}
Just to point out an alternative without having a separate variable for the index, you can use ListIterator, which provides you with the index of the element.
// Assuming list and are have same number of elements.
for (ListIterator<Integer> it = list.listIterator();
it.hasNext();) {
// The ordering of these statements is important, because next() changes nextIndex().
Integer fromArr = arr[it.nextIndex()];
Integer val = it.next();
// ...
}
ListIterator is not an especially widely-used class, though; its use may in and of itself be confusing.
One of the downsides of the ListIterator approach is that you have to use the it correctly: you shouldn't touch it inside the loop (after getting the values), you have to put the statements in the right order, etc.
Another approach would be to create a library method analogous to Python's enumerate:
static <T> Iterable<Map.Entry<Integer, T>> enumerate(Iterable<? extends T> iterable) {
return () -> new Iterator<T>() {
int index = 0;
Iterator<? extends T> delegate = iterable.iterator();
#Override public boolean hasNext() { return delegate.hasNext(); }
#Override public Map.Entry<Integer, T> next() {
return new AbstractMap.SimpleEntry<>(index++, delegate.next());
}
};
}
This returns an iterable of map entries, where the key is the index and the value is the corresponding value.
You could then use this in an enhanced for loop:
for (Map.Entry<Integer, Integer> entry : enumerate(list)) {
Integer fromList = entry.getValue();
Integer fromArr = arr[entry.getKey()];
}
One option is to have 2 iterators, but I don't think it is any clearer:
for (Iterator<Integer> i1 = list.iterator(), i2 = Arrays.asList(arr).iterator();
i1.hasNext() && i2.hasNext();) {
System.out.println(i1.next());
System.out.println(i2.next());
}
But it is more robust in that it finishes at the shorter of the 2 collections.
I tried to simplify and handle size wise collections where both need not be of the same size. I believe this would work even if the sizes are not same and just one loop would suffice. Code snippet below:
LinkedList<Integer> list = new LinkedList<Integer>();
Integer[] arr = new Array[25];
int maxLength= Math.max(list.size(),arr.size());
//Looping over the lengthy collection( could be Linkedlist or arraylist)
for(int i=0;i<maxLength;i++){
if(list.size()>i)
System.out.println(list[i]);
if(arr.size()>i)
System.out.println(arr[i]);
}
Hope this helps! Thanks

Selenium: Help to verify that elements are sorted by price

Basically, I understand how it works but I can't get it together.
So I have cssSelector for all sorted elements.
I know the exact amount of those elements (12). I use findElements() to find them all, it returns List. But List of what? - int, String ?
Selector leads right to a price in numbers but won't understand how and where should I use that List ?
How can I put it in the cycle to check that elements are sorted?
I use Selenide but if you provide me with tips\guides how to do that in Selenium it will be OK.
Thanks!
If you want to verify that the found price list are in sorted order or not use as below :-
Guava provides this functionality to verify sorting by it's Ordering class :-
Assuming you already have a price list from page that contains [1,2,3,4,5,6,7,8] values, you could verify it by using Guava library that this list is sorted or not in just one line as below :-
boolean isSorted = Ordering.natural().isOrdered(list);
System.out.println(isSorted);
Or
You could also make your own generic method to verify as below :-
private static <T extends Comparable<? super T>> boolean isSorted(List<T> list){
for (int i = 0; i < list.size()-1; i++) {
if(list.get(i).compareTo(list.get(i+1))> 0){
return false;
}
}
return true;
}
boolean isSorted = isSorted(list);
System.out.println(isSorted);
Note :- if it prints true means your list is in sorted order otherwise not
Hope it will help you...:)
(This is in Selenium)
findElements() will provide you with a list of WebElements. You can take actions on each of these.
Since you want to sort them I am assuming the elements you are getting have some sort of text in them. Let's say we have this HTML.
<span>3</span>
<span>7</span>
<span>6</span>
<span>4</span>
<span>8</span>
findElements() can return all these spans. So I will get a List containing 5 WebElements. I can get the text of these WebElements with getText(). Example:
List<Integer> values = new ArrayList<Integer>();
List<WebElement> elements = driver.findElements(By.cssSelector('span'));
for (WebElement element : elements) {
values.add(Integer.parseInt(element.getText());
}
Now you'll have a list with values. I'll leave the sorting up to you as there is so many ways you could do this.
public boolean VerifyingSort() {
List<WebElement> theList=driver.findElements(By.xpath("//*[#id=\"qv-drop\"]/li"));
int FisrtfinalPrice=0;
String FirstPrice=driver.findElement(By.xpath("//*[#id=\"qv-drop\"]/li[1]/div[1]/div[2]/a/div[2]/div[1]")).getText();
FirstPrice=FirstPrice.replaceAll("[\\-\\?\\+\\.\\^:,\\\u20B9]","");
FirstPrice = FirstPrice.split(" ")[1];
FisrtfinalPrice=Integer.parseInt(FirstPrice);
for(int SortCheckNumber=2;SortCheckNumber<theList.size()-1;SortCheckNumber++) {
String nextPrice=driver.findElement(By.xpath("//*[#id=\"qv-drop\"]/li["+SortCheckNumber+"]/div[1]/div[2]/a/div[2]/div[1]")).getText();
nextPrice=nextPrice.replaceAll("[\\-\\?\\+\\.\\^:,\\\u20B9]","");
nextPrice = nextPrice.split(" ")[1];
int finalNextPrice=Integer.parseInt(nextPrice);
if(finalNextPrice>FisrtfinalPrice) {
System.out.println("notSorted");
return false;
}else {
FisrtfinalPrice=finalNextPrice;
}
}
System.out.println("allSorted");
return true;
}

Remove object from ArrayList with some Object property

I am maintaining one ArrayList of objects. And my object structure is Id, name, some other details. I need to remove one the object with some id value say(10) and I don't want to iterate over the list. Is there any solution for this?
Using Java-8 Collection#removeIf
myList.removeIf(obj -> obj.id == 10);
With Java-7 you'll have to use iterator:
for(Iterator<MyType> iterator = myList.iterator(); iterator.hasNext(); ) {
if(iterator.next().id == 10)
iterator.remove();
}
Note that list iteration is necessary in any case. In Java-8 removeIf method it's just performed internally.
Maybe I don't understand the question but why nobody suggested to use override equals and hashcode for that user class?
class MyObject {
final String id;
final String name;
MyObject(String id, String name) {
this.id = id;
this.name = name;
}
#Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
return Objects.equals(id, ((MyObject) o).id);
}
#Override
public int hashCode() {
return id != null ? id.hashCode() : 0;
}
#Override
public String toString() {
return "MyObject{id='" + id + "', name='" + name + "'}";
}
}
in this case you can easy remove any object from list
final ArrayList<MyObject> list = new ArrayList<>();
list.add(new MyObject("id1", "name1"));
list.add(new MyObject("id2", "name2"));
list.add(new MyObject("id3", "name3"));
MyObject removeCandidate = new MyObject("id2", "name2");
list.remove(removeCandidate);
System.out.println(list);
code above prints
[MyObject{id='id1', name='name1'}, MyObject{id='id3', name='name3'}]
If you really do not want to iterate over the list, you could use a stream but I personnally prefer Collection#removeIf like #TagirValeev suggested
myList = myList.stream()
.filter(x -> x.id() != 10)
.collect(Collectors.toList());
It is not possible1 to remove instances of an element from an ArrayList without iterating the list in some way2. The ArrayList is an array under the hood, and you need to examine each element in the array to see whether it matches the criteria for removal. At the fundamental level, that entails a loop ... to iterate over the elements.
Also note that when you remove a single element from an array, all elements with positions after the removed elements need to be moved. On average, that will be half of the array elements.
Now, you can code these operations in ways that avoid you using an explicit for loop, but the iteration will be happening behind the scenes, no matter how you code it.
1 - Not strictly true. Hypothetically, if you had a separate data structure that (for instance) mapped values to the indexes of elements in the ArrayList, then you could remove the elements without iterating. But I can't see how you could manage that data structure efficiently.
2 - Iteration doesn't just mean using an Iterator. For loops, Stream, Collections.removeIf and other solutions all entail iterating the elements of the list under the hood.
You could not do that without iterator, you should you Hashmap for this.
public class ObjectStructure{
private int Id;
private String name;
//and any data field you need
}
generate all setters and getters.
Use this class in
Hashmap<Integer, ObjectStructure> data = new HashMap<>();
you can add and delete data with only key which is Integer.
data.remove(10);

If only one element in a hashset, how can I get it out?

I have a set like below:
HashSet<Integer> set = new HashSet<Integer>();
set.add(1);
How can I get the 1 out? I can do it by for(integer i : set). My specified problem is "Given an array of integers, every element appears twice except for one. Find that single one."
I want to use add elements into the set if the set doesn't contain it and remove existing elements during the loop. And the last remaining element is the answer. I don't know how to return it.
public static int singleNumber(int[] A) {
HashSet<Integer> set = new HashSet<>();
for (int a : A) {
if (!set.contains(a)) {
set.add(a);
} else {
set.remove(a);
}
}
/**
* for(Integer i : set) { return i; }
*return A[0]; //need one useless return
/**
* while(set.iterator().hasNext()) { return set.iterator().next(); }
* return A[0]; //need one useless return
*/
return set.toArray(new Integer[1])[0];
}
set.iterator().next()
Do so only if you are sure there is an element in the set. Otherwise next() will throw an exception.
Simply try using HashSet#toArray() method
HashSet<Integer> set = new HashSet<Integer>();
set.add(1);
if (set.size() == 1) { // make sure that there is only one element in set
Integer value = set.toArray(new Integer[1])[0];
System.out.println(value);//output 1
}
The typical solution includes a check if the current iterator position has any left element through setIterator.hasNext() which returns true only if there is an extra element unchecked. For example
HashSet set = new HashSet();
Iterator setIterator = set.iterator();
while(setIterator.hasNext()){
String item = setIterator().next();
...
}
If you know what the element is and you just want to empty the set, you can use remove(Object o) (or clear() for that matter). If you don't know what it is and want to see it without removing it, use an iterator. If you don't know what it is and want to remove it, you should use an iterator using the iterator's remove() method. This is the safe (and recommended) way to remove elements from a collection. Since Set is unordered, it's difficult to specify what you want to remove. And for any collection, you would usually only know what you are removing if you iterate through the collection.
Solution Using Java Stream
If you want to use Java Stream any of the following options will give you the desired result:
Option 1
Just return the only element from the stream:
set.stream().findFirst().get()
Option 2
Or use Stream.reduce; since adding the only element to zero has no effect
(a little too much IMHO :))
set.stream().reduce(0, Integer::sum)
You can test it here.

Remove duplicates from ArrayLists

I have an ArrayList of custom objects. I want to remove duplicate entries.
The objects have three fields: title, subtitle, and id. If a subtitle occurs multiple times, I only need the first item with thats subtitle (ignore the remaining object with that subtitle).
You can put the content of the ArrayList in a TreeSet using a custom Comparator which should return 0 if the two subtitles are the same.
After that you can convert the Set in a List and have the List without "duplicates".
Here is an example for Object, of course you should use the correct class and logic.
public void removeDuplicates(List<Object> l) {
// ... the list is already populated
Set<Object> s = new TreeSet<Object>(new Comparator<Object>() {
#Override
public int compare(Object o1, Object o2) {
// ... compare the two object according to your requirements
return 0;
}
});
s.addAll(l);
List<Object> res = Arrays.asList(s.toArray());
}
List list = (...);
//list may contain duplicates.
//remove duplicates if any
Set setItems = new LinkedHashSet(list);
list.clear();
list.addAll(setItems);
You may need to override "equals()" so that 2 elements are considered equals if they have the same subtitle (or tite and subtitle maybe ?)
List<Item> result = new ArrayList<Item>();
Set<String> titles = new HashSet<String>();
for(Item item : originalList) {
if(titles.add(item.getTitle()) {
result.add(item);
}
}
add() of the Set returns false if the element already exists.
I would suggest using a Set
http://download.oracle.com/javase/6/docs/api/java/util/Set.html
Which by its nature cannot contain duplicate items. You can create a new set from your original ArrayList using
Set myset = new HashSet(myArrayList);
Alternatively, just use a Set from the start, and don't use an ArrayList as it is not performing the function that you require.
If I understand correctly you have an ArrayList<Custom>, let's call it list. Your Custom class has a subtitle field, let's say with a getSubtitle() method that returns String. You want to keep only the first unique subtitle and remove any remaining duplicates. Here's how you can do that:
Set<String> subtitles = new HashSet<String>();
for (Iterator<Custom> it = list.iterator(); it.hasNext(); ) {
if (!subtitles.add(it.next().getSubtitle())) {
it.remove();
}
}
You can use an O(n^2) solution: Use list.iterator() to iterate the list once, and on each iteration, iterate it again to check if there are duplicates. If there are - call iterator.remove(). A variation of this is to use guava's Iterables.filter(list, predicate) where your filtering logic is in the predicate.
Another way (perhaps better) would be to define the equals(..) and hashCode(..) methods to handle your custom equality logic, and then simply construct a new HashSet(list). This will clear duplicates.
Removes any duplicates in a collection, while preserving the order if it is an ordered collection. Efficient enough for most cases.
public static <I, T extends Collection<I>> T removeDuplicates(T collection)
{
Set<I> setItems = new LinkedHashSet<I>(collection);
collection.clear();
collection.addAll(setItems);
return collection;
}
Update for Java8:
Using Java8 streams you can also do pretty trivally.
ArrayList<String> deduped;
deduped = yourArrayList.stream()
.distinct()
.collect(Collectors.toCollection(ArrayList::new));
This also has the advantage over going ArrayList → Set → ArrayList of maintaining ordering.
Use Collections.sort() to sort and use a simple for cycle to catch doubles, e.g.:
Collections.sort(myList);
A previous = null;
for (A elem: myList) {
if (elem.compareTo(previous) == 0) continue;
previous = elem;
[... process unique element ...]
}
This presumes that you'll implement Comparable in your type A.
private static List<Integer> removeDuplicates(List<Integer> list) {
ArrayList<Integer> uniqueList = new ArrayList<Integer>();
for (Integer i : list) {
if (!inArray(i, uniqueList)) {
uniqueList.add(i);
}
}
return uniqueList;
}
private static boolean inArray(Integer i, List<Integer> list) {
for (Integer integer : list) {
if (integer == i) {
return true;
}
}
return false;
}
The solution depends on circumstances.
If you don't have much data then go with a Set Set<T> unique = new HashSet<>(yourList); (use LinkedHashSet if you care about the order. It creates a new collection, but usually it's not a problem.
When you want to modify existing list and don't want to/can't create a new collection, you can remove duplicates like here:
List<Integer> numbers =
new ArrayList<>(asList(1, 1, 2, 1, 2, 3, 5));
System.out.println("Numbers: " + numbers);
ListIterator<Integer> it = numbers.listIterator();
while (it.hasNext()) {
int i = it.nextIndex();
Integer current = it.next();
for (int j = 0; j < i; ++j) {
if (current.equals(numbers.get(j))) {
it.remove();
break;
}
}
}
System.out.println("Unique: " + numbers);
It works in O(n^2), but it works. Similar implementation, but simpler, is when the list is sorted - works in O(n) time. Both implementations are explained at Farenda: remove duplicates from list - various implementations.
In Java 8, you can also do something like this:
yourList.stream().collect(
Collectors.toMap(
obj -> obj.getSubtitle(),
Function.identity(),
(o1,o2) -> o1))
.values();
The trick is to collect stream to map and provide key collision resolver lambda ((o1,o2) -> o1) which always returns its first parameter.
The result is a Collection, not a List but you can easily convert it to a List:
new ArrayList(resultCollection);
List<YourObject> all = ******** // this is the object that you have already and filled it.
List<YourObject> noRepeat= new ArrayList<YourObject>();
for (YourObject al: all) {
boolean isPresent = false;
// check if the current objects subtitle already exists in noRepeat
for (YourObject nr : noRepeat) {
if (nr.getName().equals(al.getName()) {
isFound = true;//yes we have already
break;
}
}
if (!isPresent)
noRepeat.add(al); // we are adding if we don't have already
}
take one new ArrayList Object of same type
one by one add all the old arraylists elements into this new arraylist object
but before adding every object check in the new arraylist that if there is any object with the same subtitle.if new arraylist contains such subtitle don't add it. otherwise add it
Another method using Java 8 streams you can also do pretty cool:
List<Customer> CustomerLists;
List<Customer> unique = CustomerLists.stream().collect(collectingAndThen(
toCollection(() -> new TreeSet<>(comparingLong(Customer::getId))),
ArrayList::new));

Categories

Resources