For loop inside for loops code optimisation - java

I have an loop inside loop to remove the elements from the seconde loop, and what is present in the list has to perform certain actions. I wish to optimize the iteration and comparisons, can it be done?
How do I optimize my logic shown below to avoid so many lines of code
public MEntity getBuffer(String entityName, String Buffer, String... ignoreFields) {
McgEntity entity = getElementsByEntityFromXml(entityName);
int minLenghtOfEntities = 0;
List<McgField> fieldsToRemove = new ArrayList<>();
if (ignoreFields != null && ignoreFields.length > 0) {
for (int i = 0; i < ignoreFields.length; i++) {
for (McgField field : entity.getFieldList()) {
if (field.getFieldName().contains(ignoreFields[i])) {
minLenghtOfEntities += field.getFieldLength();
fieldsToRemove.add(field);
}
}
}
entity.setLengthBuffer(entity.getLengthBuffer() - minLenghtOfEntities);
entity.getFieldList().removeAll(fieldsToRemove);
}
....
}

After minLenghtOfEntities += field.getFieldLength(); a break is missing.
With streams the code becomes a bit more structured, first collecting the fields to remove and then the entity lengths to correct.
public MEntity getBuffer(String entityName, String buffer, String... ignoreFields) {
Objects.requireNonNull(ignoreFields);
McgEntity entity = getElementsByEntityFromXml(entityName);
List<McgField> fieldsToRemove = entity.getFieldList().stream()
.filter(f -> Arrays.stream(ignoreFields)
.anyMatch(f.getFieldName()::contains))
.collect(Collectors.toList());
int minLenghtOfEntities = fieldsToRemove.stream()
.mapToInt(McgField::getFieldLength).sum();
entity.setLengthBuffer(entity.getLengthBuffer() - minLenghtOfEntities);
entity.getFieldList().removeAll(fieldsToRemove);
...
}
Unfortunately because of contains a Set<String> ignoreFields is not better.

Related

What's a cleaner way to write this Java code or optimize it to build a string from an ArrayList?

I'm creating a java scraping program using selenium and inserting the data into a database. I'm actively looking to improve my skillset but I don't find instructional videos too helpful since I lose interest, but I really enjoy learning through doing. This code below works as needed, but it looks really really ugly and I feel there must be a better/cleaner solution. For reference it builds a comma separated string with data such as "Value1", or "Value1, Value2", etc depending on the keyword count. My original logic was outputting ", Value1, Value2" which is why I added the "if (x ==0)" logic. I have a lot of methods that are just sloppy like this, so any pointers for improving my code is appreciated, thanks!
ArrayList<String> keywords = new ArrayList<String>();
keywords = keywordChecker(title);
for (int x = 0; x < keywords.size(); x++) {
String list = keywords.get(x);
if (x == 0) {
keywordListBuilder = list;
} else if (x > 0) {
keywordListBuilder = keywordListBuilder + ", " + list;
}
}
keywordValues.add(keywordListBuilder);
public ArrayList<String> keywordChecker(String title) {
ArrayList<String> keywordList = new ArrayList<String>();
String keyword1 = "";
String keyword2 = "";
String keyword3 = "";
String[] keywordTextCombinations = { "Value1", "Value2", "Value3", [imagine a list of 20 items]};
for (int i = 0; i < keywordTextCombinations.length; i++) {
if (title.toLowerCase().contains(keywordTextCombinations[i].toLowerCase())) {
keyword1 = keywordTextCombinations[i];
keywordList.add(keyword1);
break;
}
}
for (int i = 0; i < keywordTextCombinations.length; i++) {
if (title.toLowerCase().contains(keywordTextCombinations[i].toLowerCase())
&& !keywordTextCombinations[i].toLowerCase().equals(keyword1.toLowerCase())
&& !keywordTextCombinations[i].toLowerCase().equals(keyword2.toLowerCase())) {
keyword2 = keywordTextCombinations[i];
keywordList.add(keyword2);
break;
}
}
for (int i = 0; i < keywordTextCombinations.length; i++) {
if (title.toLowerCase().contains(keywordTextCombinations[i].toLowerCase())
&& !keywordTextCombinations[i].toLowerCase().equals(keyword1.toLowerCase())
&& !keywordTextCombinations[i].toLowerCase().equals(keyword2.toLowerCase())) {
keyword3 = keywordTextCombinations[i];
keywordList.add(keyword3);
break;
}
}
return keywordList;
}
ArrayList<String> keywords = new ArrayList<String>();
keywords = keywordChecker(title);
This will:
Create a new variable, named keywords, that can point at arraylists.
Makes a new arraylist object.
Assigns the reference to this newly created object to the keywords variable.
Then tosses that reference away and makes that created object instant garbage, as you then immediately assign some other reference to it.
In other words, that new ArrayList<String>(); does nothing whatsoever but waste time and space. Get rid of it. Let's also be like other java coders and use the most general type that we're interested in. For beginners, that basically means, 'the variable should be of type List, not ArrayList. It's good to write code in similar style to other java coders; makes it easier to read their code and it makes it easier for them to read your code.
List<String> keywords = keywordChecker(title);
for (int x = 0; x < keywords.size(); x++) {
String list = keywords.get(x);
if (x == 0) {
keywordListBuilder = list;
} else if (x > 0) {
keywordListBuilder = keywordListBuilder + ", " + list;
}
}
keywordValues.add(keywordListBuilder);
You're getting a single keyword and you call this list? Names are important. When they lie, your code becomes unreadable.
You're turning a list of strings into a single string with all the values, separated by a comma. That sounds like a common job. When something sounds common enough, search the web. You'll usually find that there's a one-liner. So it is here:
keywordValues.add(String.join(", ", keywords));
Oof, that's way less code.
The keywordChecker method
It helps to document code, especially when asking for help. Evidently, this method is to scan the provided title variable, and search for any of a list of keywords, then it is to return each matching keyword. However, you've limited to return at most 3. I assume you didn't want that. But if you do, I'll show you how, with a one-liner of course.
String keyword1 = "";
String keyword2 = "";
String keyword3 = "";
When you start naming variables like this, stop. There's no way that's correct. Think for a moment. You're already using them, you know how to do this properly: Lists. Once you use a list, this becomes near trivial. Also, method names should generally be a verb; common java style. Let's also make constants, well, constant. Let's also avoid arrays, they are unwieldy and annoying.
private static final List<String> KEYWORDS = List.of("Value1", "Value2", "Value3", [imagine a list of 20 items]);
public List<String> findMatchingKeywords(String title) {
var out = new ArrayList<String>();
String lowercased = title.toLowerCase();
for (String keyword : KEYWORDS) {
if (lowercased.contains(keyword.toLowerCase()) out.add(keyword);
}
return out;
}
That eliminated a ton of lines, that's nice. If you want to return no more than 3 keywords at most... all you need to do is abort looping when you're 'full'. As last line within the for loop:
if (out.length() == 3) break;
Putting it all together:
keywordValues.add(String.join(", ", findMatchingKeywords(title)));
...
private static final List<String> KEYWORDS = List.of("Value1", "Value2", "Value3", [imagine a list of 20 items]);
public List<String> findMatchingKeywords(String title) {
var out = new ArrayList<String>();
String lowercased = title.toLowerCase();
for (String keyword : KEYWORDS) {
if (lowercased.contains(keyword.toLowerCase()) {
out.add(keyword);
if (out.length() == 3) break;
}
}
return out;
}
You can try to do everything in one for loop. Also, I recommend that you use a HashSet since you are comparing elements. A HashSet cannot contain duplicate elements, so if you try to add an element that already exists it doesn't do it and it returns false (Yes, the add function in HashSet returns a boolean).

java8 List get object based on index, if not create

I'm trying to replace the below code using stream API, Optional API. I'm unable to think of a solution. Kindly help me on this.
Note: Please don't bother with the FUNCTIONALITY. This is not the exact client code and hence some of the operations doesn't make sense from the outside perspective.
public class Person {
private String fName;
private String lName;
private String empId;
// constructors, setters, getters
}
.. MAIN CLASS..
private boolean indexExists(final List <Person> list, final int index) {
return index >= 0 && index < list.size();
}
public void mainFunction() {
Person per1 = new Person("fname1", "lname1", "101");
Person per2 = new Person("fname2", "lname2", "102");
List<Person> allPersons = new ArrayList<>();
allPersons.add(per1);
allPersons.add(per2);
System.out.println(allPersons);
List<String> lNamesAppend = Arrays.asList("123","456","789");
// CAN THE BELOW BE REPLACED IN JAVA8 ?
int index = 0;
Person person = null;
for(String str : lNamesAppend) {
if(indexExists(allPersons, index)) {
person = allPersons.get(index++);
} else {
person = new Person("fname" + index++ , "lname" + index++, "10" + index++);
allPersons.add(person);
}
person.setlName(str + index);
}
System.out.println(allPersons);
}
You can create code using the Stream API following the same logic, but there is no sense in doing that without revising the logic. After all, the Stream API allows you to express the intent instead of an iteration logic, at least when you have a suitable task. If not suitable, there is no advantage in changing the code.
In your case, the logic is flawed right from the start, as you are polling indices for validity, despite you know in advance that the valid indices of a list form a range from zero to the list’s size, just to do two entirely different operations, updating old entries or creating new entries, within the same loop.
Compare with a straight-forward approach not doing two things in one:
int existing = Math.min(allPersons.size(), lNamesAppend.size());
for(int index = 0; index < existing; index++)
allPersons.get(index).setlName(lNamesAppend.get(index)+index);
for(int index = existing, end = lNamesAppend.size(); index < end; index++)
allPersons.add(new Person("fname"+index, lNamesAppend.get(index)+index, "10"+index));
I assumed doing index++ three times for a new Person was a bug.
You can do the same using the Stream API:
int existing = Math.min(allPersons.size(), lNamesAppend.size());
IntStream.range(0, existing)
.forEach(index -> allPersons.get(index).setlName(lNamesAppend.get(index)+index));
allPersons.addAll(IntStream.range(existing, lNamesAppend.size())
.mapToObj(index -> new Person("fname"+index,lNamesAppend.get(index)+index,"10"+index))
.collect(Collectors.toList()));
Following is one of the options. Note that the code is not CLEAN, given that the functionality isn't clear, but you can get an idea on how to achieve it
//mainMethod
{
....
AtomicInteger index = new AtomicInteger();
lNamesAppend.stream()
.map(str-> indexExists(allPersons, index.get()) ?
new ImmutablePair<>(str, allPersons.get(index.getAndIncrement())) :
new ImmutablePair<>(str, getPerson(allPersons, index)))
.forEach(p->p.getRight().setlName(p.getLeft()+index));
}
private Person getPerson(List<Person> allPersons, AtomicInteger index) {
Person person = new Person("fname" + index.getAndIncrement(), "lname" + index.getAndIncrement(), "10" + index.getAndIncrement());
allPersons.add(person);
return person;
}

How to check if two objects in a ArrayList are the same? [duplicate]

How could I go about detecting (returning true/false) whether an ArrayList contains more than one of the same element in Java?
Many thanks,
Terry
Edit
Forgot to mention that I am not looking to compare "Blocks" with each other but their integer values. Each "block" has an int and this is what makes them different.
I find the int of a particular Block by calling a method named "getNum" (e.g. table1[0][2].getNum();
Simplest: dump the whole collection into a Set (using the Set(Collection) constructor or Set.addAll), then see if the Set has the same size as the ArrayList.
List<Integer> list = ...;
Set<Integer> set = new HashSet<Integer>(list);
if(set.size() < list.size()){
/* There are duplicates */
}
Update: If I'm understanding your question correctly, you have a 2d array of Block, as in
Block table[][];
and you want to detect if any row of them has duplicates?
In that case, I could do the following, assuming that Block implements "equals" and "hashCode" correctly:
for (Block[] row : table) {
Set set = new HashSet<Block>();
for (Block cell : row) {
set.add(cell);
}
if (set.size() < 6) { //has duplicate
}
}
I'm not 100% sure of that for syntax, so it might be safer to write it as
for (int i = 0; i < 6; i++) {
Set set = new HashSet<Block>();
for (int j = 0; j < 6; j++)
set.add(table[i][j]);
...
Set.add returns a boolean false if the item being added is already in the set, so you could even short circuit and bale out on any add that returns false if all you want to know is whether there are any duplicates.
Improved code, using return value of Set#add instead of comparing the size of list and set.
public static <T> boolean hasDuplicate(Iterable<T> all) {
Set<T> set = new HashSet<T>();
// Set#add returns false if the set does not change, which
// indicates that a duplicate element has been added.
for (T each: all) if (!set.add(each)) return true;
return false;
}
With Java 8+ you can use Stream API:
boolean areAllDistinct(List<Block> blocksList) {
return blocksList.stream().map(Block::getNum).distinct().count() == blockList.size();
}
If you are looking to avoid having duplicates at all, then you should just cut out the middle process of detecting duplicates and use a Set.
Improved code to return the duplicate elements
Can find duplicates in a Collection
return the set of duplicates
Unique Elements can be obtained from the Set
public static <T> List getDuplicate(Collection<T> list) {
final List<T> duplicatedObjects = new ArrayList<T>();
Set<T> set = new HashSet<T>() {
#Override
public boolean add(T e) {
if (contains(e)) {
duplicatedObjects.add(e);
}
return super.add(e);
}
};
for (T t : list) {
set.add(t);
}
return duplicatedObjects;
}
public static <T> boolean hasDuplicate(Collection<T> list) {
if (getDuplicate(list).isEmpty())
return false;
return true;
}
I needed to do a similar operation for a Stream, but couldn't find a good example. Here's what I came up with.
public static <T> boolean areUnique(final Stream<T> stream) {
final Set<T> seen = new HashSet<>();
return stream.allMatch(seen::add);
}
This has the advantage of short-circuiting when duplicates are found early rather than having to process the whole stream and isn't much more complicated than just putting everything in a Set and checking the size. So this case would roughly be:
List<T> list = ...
boolean allDistinct = areUnique(list.stream());
If your elements are somehow Comparable (the fact that the order has any real meaning is indifferent -- it just needs to be consistent with your definition of equality), the fastest duplicate removal solution is going to sort the list ( 0(n log(n)) ) then to do a single pass and look for repeated elements (that is, equal elements that follow each other) (this is O(n)).
The overall complexity is going to be O(n log(n)), which is roughly the same as what you would get with a Set (n times long(n)), but with a much smaller constant. This is because the constant in sort/dedup results from the cost of comparing elements, whereas the cost from the set is most likely to result from a hash computation, plus one (possibly several) hash comparisons. If you are using a hash-based Set implementation, that is, because a Tree based is going to give you a O( n log²(n) ), which is even worse.
As I understand it, however, you do not need to remove duplicates, but merely test for their existence. So you should hand-code a merge or heap sort algorithm on your array, that simply exits returning true (i.e. "there is a dup") if your comparator returns 0, and otherwise completes the sort, and traverse the sorted array testing for repeats. In a merge or heap sort, indeed, when the sort is completed, you will have compared every duplicate pair unless both elements were already in their final positions (which is unlikely). Thus, a tweaked sort algorithm should yield a huge performance improvement (I would have to prove that, but I guess the tweaked algorithm should be in the O(log(n)) on uniformly random data)
If you want the set of duplicate values:
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
public class FindDuplicateInArrayList {
public static void main(String[] args) {
Set<String> uniqueSet = new HashSet<String>();
List<String> dupesList = new ArrayList<String>();
for (String a : args) {
if (uniqueSet.contains(a))
dupesList.add(a);
else
uniqueSet.add(a);
}
System.out.println(uniqueSet.size() + " distinct words: " + uniqueSet);
System.out.println(dupesList.size() + " dupesList words: " + dupesList);
}
}
And probably also think about trimming values or using lowercase ... depending on your case.
Simply put:
1) make sure all items are comparable
2) sort the array
2) iterate over the array and find duplicates
To know the Duplicates in a List use the following code:It will give you the set which contains duplicates.
public Set<?> findDuplicatesInList(List<?> beanList) {
System.out.println("findDuplicatesInList::"+beanList);
Set<Object> duplicateRowSet=null;
duplicateRowSet=new LinkedHashSet<Object>();
for(int i=0;i<beanList.size();i++){
Object superString=beanList.get(i);
System.out.println("findDuplicatesInList::superString::"+superString);
for(int j=0;j<beanList.size();j++){
if(i!=j){
Object subString=beanList.get(j);
System.out.println("findDuplicatesInList::subString::"+subString);
if(superString.equals(subString)){
duplicateRowSet.add(beanList.get(j));
}
}
}
}
System.out.println("findDuplicatesInList::duplicationSet::"+duplicateRowSet);
return duplicateRowSet;
}
best way to handle this issue is to use a HashSet :
ArrayList<String> listGroupCode = new ArrayList<>();
listGroupCode.add("A");
listGroupCode.add("A");
listGroupCode.add("B");
listGroupCode.add("C");
HashSet<String> set = new HashSet<>(listGroupCode);
ArrayList<String> result = new ArrayList<>(set);
Just print result arraylist and see the result without duplicates :)
This answer is wrriten in Kotlin, but can easily be translated to Java.
If your arraylist's size is within a fixed small range, then this is a great solution.
var duplicateDetected = false
if(arrList.size > 1){
for(i in 0 until arrList.size){
for(j in 0 until arrList.size){
if(i != j && arrList.get(i) == arrList.get(j)){
duplicateDetected = true
}
}
}
}
private boolean isDuplicate() {
for (int i = 0; i < arrayList.size(); i++) {
for (int j = i + 1; j < arrayList.size(); j++) {
if (arrayList.get(i).getName().trim().equalsIgnoreCase(arrayList.get(j).getName().trim())) {
return true;
}
}
}
return false;
}
String tempVal = null;
for (int i = 0; i < l.size(); i++) {
tempVal = l.get(i); //take the ith object out of list
while (l.contains(tempVal)) {
l.remove(tempVal); //remove all matching entries
}
l.add(tempVal); //at last add one entry
}
Note: this will have major performance hit though as items are removed from start of the list.
To address this, we have two options. 1) iterate in reverse order and remove elements. 2) Use LinkedList instead of ArrayList. Due to biased questions asked in interviews to remove duplicates from List without using any other collection, above example is the answer. In real world though, if I have to achieve this, I will put elements from List to Set, simple!
/**
* Method to detect presence of duplicates in a generic list.
* Depends on the equals method of the concrete type. make sure to override it as required.
*/
public static <T> boolean hasDuplicates(List<T> list){
int count = list.size();
T t1,t2;
for(int i=0;i<count;i++){
t1 = list.get(i);
for(int j=i+1;j<count;j++){
t2 = list.get(j);
if(t2.equals(t1)){
return true;
}
}
}
return false;
}
An example of a concrete class that has overridden equals() :
public class Reminder{
private long id;
private int hour;
private int minute;
public Reminder(long id, int hour, int minute){
this.id = id;
this.hour = hour;
this.minute = minute;
}
#Override
public boolean equals(Object other){
if(other == null) return false;
if(this.getClass() != other.getClass()) return false;
Reminder otherReminder = (Reminder) other;
if(this.hour != otherReminder.hour) return false;
if(this.minute != otherReminder.minute) return false;
return true;
}
}
ArrayList<String> withDuplicates = new ArrayList<>();
withDuplicates.add("1");
withDuplicates.add("2");
withDuplicates.add("1");
withDuplicates.add("3");
HashSet<String> set = new HashSet<>(withDuplicates);
ArrayList<String> withoutDupicates = new ArrayList<>(set);
ArrayList<String> duplicates = new ArrayList<String>();
Iterator<String> dupIter = withDuplicates.iterator();
while(dupIter.hasNext())
{
String dupWord = dupIter.next();
if(withDuplicates.contains(dupWord))
{
duplicates.add(dupWord);
}else{
withoutDupicates.add(dupWord);
}
}
System.out.println(duplicates);
System.out.println(withoutDupicates);
A simple solution for learners.
//Method to find the duplicates.
public static List<Integer> findDublicate(List<Integer> numList){
List<Integer> dupLst = new ArrayList<Integer>();
//Compare one number against all the other number except the self.
for(int i =0;i<numList.size();i++) {
for(int j=0 ; j<numList.size();j++) {
if(i!=j && numList.get(i)==numList.get(j)) {
boolean isNumExist = false;
//The below for loop is used for avoid the duplicate again in the result list
for(Integer aNum: dupLst) {
if(aNum==numList.get(i)) {
isNumExist = true;
break;
}
}
if(!isNumExist) {
dupLst.add(numList.get(i));
}
}
}
}
return dupLst;
}

Filter List<Object[]> to retain consistent values

First, I had a list with several arrays of type Object, e.g.:
Object[] arr1 = new Object[] {"FIM4R1500030", BigInteger.valueOf(5272456l), "A10328E00074531842"};
Object[] arr2 = new Object[] {"FIM4R1500031", BigInteger.valueOf(886445384123l), "A10328E00074531842"};
final List<Object[]> arrs = Arrays.asList(arr1, arr2);
Then, I wrote a logic that filters them to retain the consistent values and fills in null for the inconsistent ones. The result looked something like this:
List[
Object[][null,null,"A10328E00074531842"],
Object[][null,null,"A10328E00074531842"]
]
Now, my problem is that the logic for this turned out rather convoluted and difficult to read and I am not sure whether I can live with it. Also, I don't really want to start writing a fully-blown utility class, since the functionality seems small for this. Here is my code:
final Predicate<Integer> isConsistant = index -> {
for (Object[] arr : arrs) {
if (!arr[index].equals(arrs.get(0)[index])) {
return false;
}
}
return true;
};
List<Object[]> filtered = arrs.stream().map(arr -> {
Object[] returnList = new Object[arrs.get(0).length];
for (int i = 0; i < arrs.get(0).length; i++) {
if (isConsistant.test(i)) {
returnList[i] = arrs.get(0)[i];
} else {
returnList[i] = null;
}
}
return returnList;
})
.collect(toList());
My question is, how to make this simpler!
Why do you want a List<Object[]> as the result of your filter? If I understood your problem well, all the Object[] inside that list will look the same. So the code could just be:
Object[] filtered = IntStream.range(0, arrs.get(0).length)
.mapToObj(i -> arrs.stream().allMatch(arr -> arr[i] != null && arr[i].equals(arrs.get(0)[i])) ? arrs.get(0)[i] : null)
.toArray();
The problem with this code is not that it's too complex, but that it is unnecessarily slow: for each pair of (row, column) of arrs you walk the entire array again, trying to determine if all values in the column are equal to each other. Essentially, you are running isConsistant on the same column N times - once for each row, even though the predicate always returns the same value. This may be very significant when the number of rows is high.
The process always ends up with N identical rows, so you might as well construct that row once, and make N copies of it:
Object[] row = new Object[arrs.get(0).length];
for (int i = 0 ; i != arrs.get(0).length ; i++) {
if (isConsistant.test(i)) {
row[i] = arrs.get(0)[i];
}
}
// Now we make N copies of that row:
List<Object[]> filtered = new ArrayList<Object[]>();
for (int i = 0 ; i != arrs.length() ; i++) {
filtered.add((Object[])row.clone());
}
If you are not planning on modifying elements of filtered, you may skip the clone part, and insert the same object N times.

Java: Detect duplicates in ArrayList?

How could I go about detecting (returning true/false) whether an ArrayList contains more than one of the same element in Java?
Many thanks,
Terry
Edit
Forgot to mention that I am not looking to compare "Blocks" with each other but their integer values. Each "block" has an int and this is what makes them different.
I find the int of a particular Block by calling a method named "getNum" (e.g. table1[0][2].getNum();
Simplest: dump the whole collection into a Set (using the Set(Collection) constructor or Set.addAll), then see if the Set has the same size as the ArrayList.
List<Integer> list = ...;
Set<Integer> set = new HashSet<Integer>(list);
if(set.size() < list.size()){
/* There are duplicates */
}
Update: If I'm understanding your question correctly, you have a 2d array of Block, as in
Block table[][];
and you want to detect if any row of them has duplicates?
In that case, I could do the following, assuming that Block implements "equals" and "hashCode" correctly:
for (Block[] row : table) {
Set set = new HashSet<Block>();
for (Block cell : row) {
set.add(cell);
}
if (set.size() < 6) { //has duplicate
}
}
I'm not 100% sure of that for syntax, so it might be safer to write it as
for (int i = 0; i < 6; i++) {
Set set = new HashSet<Block>();
for (int j = 0; j < 6; j++)
set.add(table[i][j]);
...
Set.add returns a boolean false if the item being added is already in the set, so you could even short circuit and bale out on any add that returns false if all you want to know is whether there are any duplicates.
Improved code, using return value of Set#add instead of comparing the size of list and set.
public static <T> boolean hasDuplicate(Iterable<T> all) {
Set<T> set = new HashSet<T>();
// Set#add returns false if the set does not change, which
// indicates that a duplicate element has been added.
for (T each: all) if (!set.add(each)) return true;
return false;
}
With Java 8+ you can use Stream API:
boolean areAllDistinct(List<Block> blocksList) {
return blocksList.stream().map(Block::getNum).distinct().count() == blockList.size();
}
If you are looking to avoid having duplicates at all, then you should just cut out the middle process of detecting duplicates and use a Set.
Improved code to return the duplicate elements
Can find duplicates in a Collection
return the set of duplicates
Unique Elements can be obtained from the Set
public static <T> List getDuplicate(Collection<T> list) {
final List<T> duplicatedObjects = new ArrayList<T>();
Set<T> set = new HashSet<T>() {
#Override
public boolean add(T e) {
if (contains(e)) {
duplicatedObjects.add(e);
}
return super.add(e);
}
};
for (T t : list) {
set.add(t);
}
return duplicatedObjects;
}
public static <T> boolean hasDuplicate(Collection<T> list) {
if (getDuplicate(list).isEmpty())
return false;
return true;
}
I needed to do a similar operation for a Stream, but couldn't find a good example. Here's what I came up with.
public static <T> boolean areUnique(final Stream<T> stream) {
final Set<T> seen = new HashSet<>();
return stream.allMatch(seen::add);
}
This has the advantage of short-circuiting when duplicates are found early rather than having to process the whole stream and isn't much more complicated than just putting everything in a Set and checking the size. So this case would roughly be:
List<T> list = ...
boolean allDistinct = areUnique(list.stream());
If your elements are somehow Comparable (the fact that the order has any real meaning is indifferent -- it just needs to be consistent with your definition of equality), the fastest duplicate removal solution is going to sort the list ( 0(n log(n)) ) then to do a single pass and look for repeated elements (that is, equal elements that follow each other) (this is O(n)).
The overall complexity is going to be O(n log(n)), which is roughly the same as what you would get with a Set (n times long(n)), but with a much smaller constant. This is because the constant in sort/dedup results from the cost of comparing elements, whereas the cost from the set is most likely to result from a hash computation, plus one (possibly several) hash comparisons. If you are using a hash-based Set implementation, that is, because a Tree based is going to give you a O( n log²(n) ), which is even worse.
As I understand it, however, you do not need to remove duplicates, but merely test for their existence. So you should hand-code a merge or heap sort algorithm on your array, that simply exits returning true (i.e. "there is a dup") if your comparator returns 0, and otherwise completes the sort, and traverse the sorted array testing for repeats. In a merge or heap sort, indeed, when the sort is completed, you will have compared every duplicate pair unless both elements were already in their final positions (which is unlikely). Thus, a tweaked sort algorithm should yield a huge performance improvement (I would have to prove that, but I guess the tweaked algorithm should be in the O(log(n)) on uniformly random data)
If you want the set of duplicate values:
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
public class FindDuplicateInArrayList {
public static void main(String[] args) {
Set<String> uniqueSet = new HashSet<String>();
List<String> dupesList = new ArrayList<String>();
for (String a : args) {
if (uniqueSet.contains(a))
dupesList.add(a);
else
uniqueSet.add(a);
}
System.out.println(uniqueSet.size() + " distinct words: " + uniqueSet);
System.out.println(dupesList.size() + " dupesList words: " + dupesList);
}
}
And probably also think about trimming values or using lowercase ... depending on your case.
Simply put:
1) make sure all items are comparable
2) sort the array
2) iterate over the array and find duplicates
To know the Duplicates in a List use the following code:It will give you the set which contains duplicates.
public Set<?> findDuplicatesInList(List<?> beanList) {
System.out.println("findDuplicatesInList::"+beanList);
Set<Object> duplicateRowSet=null;
duplicateRowSet=new LinkedHashSet<Object>();
for(int i=0;i<beanList.size();i++){
Object superString=beanList.get(i);
System.out.println("findDuplicatesInList::superString::"+superString);
for(int j=0;j<beanList.size();j++){
if(i!=j){
Object subString=beanList.get(j);
System.out.println("findDuplicatesInList::subString::"+subString);
if(superString.equals(subString)){
duplicateRowSet.add(beanList.get(j));
}
}
}
}
System.out.println("findDuplicatesInList::duplicationSet::"+duplicateRowSet);
return duplicateRowSet;
}
best way to handle this issue is to use a HashSet :
ArrayList<String> listGroupCode = new ArrayList<>();
listGroupCode.add("A");
listGroupCode.add("A");
listGroupCode.add("B");
listGroupCode.add("C");
HashSet<String> set = new HashSet<>(listGroupCode);
ArrayList<String> result = new ArrayList<>(set);
Just print result arraylist and see the result without duplicates :)
This answer is wrriten in Kotlin, but can easily be translated to Java.
If your arraylist's size is within a fixed small range, then this is a great solution.
var duplicateDetected = false
if(arrList.size > 1){
for(i in 0 until arrList.size){
for(j in 0 until arrList.size){
if(i != j && arrList.get(i) == arrList.get(j)){
duplicateDetected = true
}
}
}
}
private boolean isDuplicate() {
for (int i = 0; i < arrayList.size(); i++) {
for (int j = i + 1; j < arrayList.size(); j++) {
if (arrayList.get(i).getName().trim().equalsIgnoreCase(arrayList.get(j).getName().trim())) {
return true;
}
}
}
return false;
}
String tempVal = null;
for (int i = 0; i < l.size(); i++) {
tempVal = l.get(i); //take the ith object out of list
while (l.contains(tempVal)) {
l.remove(tempVal); //remove all matching entries
}
l.add(tempVal); //at last add one entry
}
Note: this will have major performance hit though as items are removed from start of the list.
To address this, we have two options. 1) iterate in reverse order and remove elements. 2) Use LinkedList instead of ArrayList. Due to biased questions asked in interviews to remove duplicates from List without using any other collection, above example is the answer. In real world though, if I have to achieve this, I will put elements from List to Set, simple!
/**
* Method to detect presence of duplicates in a generic list.
* Depends on the equals method of the concrete type. make sure to override it as required.
*/
public static <T> boolean hasDuplicates(List<T> list){
int count = list.size();
T t1,t2;
for(int i=0;i<count;i++){
t1 = list.get(i);
for(int j=i+1;j<count;j++){
t2 = list.get(j);
if(t2.equals(t1)){
return true;
}
}
}
return false;
}
An example of a concrete class that has overridden equals() :
public class Reminder{
private long id;
private int hour;
private int minute;
public Reminder(long id, int hour, int minute){
this.id = id;
this.hour = hour;
this.minute = minute;
}
#Override
public boolean equals(Object other){
if(other == null) return false;
if(this.getClass() != other.getClass()) return false;
Reminder otherReminder = (Reminder) other;
if(this.hour != otherReminder.hour) return false;
if(this.minute != otherReminder.minute) return false;
return true;
}
}
ArrayList<String> withDuplicates = new ArrayList<>();
withDuplicates.add("1");
withDuplicates.add("2");
withDuplicates.add("1");
withDuplicates.add("3");
HashSet<String> set = new HashSet<>(withDuplicates);
ArrayList<String> withoutDupicates = new ArrayList<>(set);
ArrayList<String> duplicates = new ArrayList<String>();
Iterator<String> dupIter = withDuplicates.iterator();
while(dupIter.hasNext())
{
String dupWord = dupIter.next();
if(withDuplicates.contains(dupWord))
{
duplicates.add(dupWord);
}else{
withoutDupicates.add(dupWord);
}
}
System.out.println(duplicates);
System.out.println(withoutDupicates);
A simple solution for learners.
//Method to find the duplicates.
public static List<Integer> findDublicate(List<Integer> numList){
List<Integer> dupLst = new ArrayList<Integer>();
//Compare one number against all the other number except the self.
for(int i =0;i<numList.size();i++) {
for(int j=0 ; j<numList.size();j++) {
if(i!=j && numList.get(i)==numList.get(j)) {
boolean isNumExist = false;
//The below for loop is used for avoid the duplicate again in the result list
for(Integer aNum: dupLst) {
if(aNum==numList.get(i)) {
isNumExist = true;
break;
}
}
if(!isNumExist) {
dupLst.add(numList.get(i));
}
}
}
}
return dupLst;
}

Categories

Resources