Removing first case insensitive duplicate of an ArrayList - java

I have an arraylist containing some strings:
ArrayList<String> strList = new ArrayList<String>();
strList.addAll(Arrays.asList("interface", "list", "Primitive", "class", "primitive", "List", "Interface", "lIst", "Primitive"));
I have wrote a method to remove the case insensitive strings of the arraylist:
public static ArrayList<String> removeDuplicates(ArrayList<String> strList) {
for(int i = 0; i < strList.size(); i++) {
for(int j = i + 1; j < strList.size(); j++) {
if(strList.get(i).equalsIgnoreCase(strList.get(j))){
strList.remove(j);
j--;
}
}
}
return strList;
}
Ouput:
[interface, list, Primitive, class]
However, I am trying to remove just the first occurance of the strings. I am trying to make it so my output would equal:
[Interface, lIst, Primitive, class]
Which would be the last occurrences of the duplicates in the arraylist
What I'm trying to do specifically:
The version of the string that remains is the same as the last occurrence. In other words, the
version of the last occurrence stays at the location of the first occurrence

I think that remove from the ArrayList is not good idea. It is better using Map to create new list:
public static List<String> removeDuplicates(List<String> strList) {
Map<String, String> map = new LinkedHashMap<>();
strList.forEach(item -> map.put(item.toLowerCase(), item));
return new ArrayList<>(map.values());
}
Input: [interface, list, Primitive, class, primitive, List, Interface, lIst, Primitive]
Output: [Interface, lIst, Primitive, class]
P.S.
Same with one line Stream, but a bit not so clear:
public static List<String> removeDuplicates(List<String> strList) {
return new ArrayList<>(strList.stream().collect(Collectors.toMap(String::toLowerCase, str -> str, (prev, next) -> next, LinkedHashMap::new)).values());
}

Right now it keeps the first occurrence, so if you want to keep the last occurrence you can just go through the list in reverse:
for(int i = strList.size() - 1; i >= 0; i--) {
for(int j = i - 1; j >= 0; j--) {
...

Related

Arraylist remove

Need to do a method which takes ArrayList<ArrayList<<Integer>> and an Integer which then returns an ArrayList<ArrayList<<Integer>> from the orginal ArrayList<ArrayList<<Integer>> which do not contain the Integer argument e.g
ArrayList<ArrayList<<Integer>>
[[1,2,3],[7,5],[4,4,2],[8,12,3]] and Integer 2 should return
[[7,5],[8,12,3]]. arraylist of arraylist integers.
not entirely sure how to access the inner loop
You can use contains() rather than worrying about writing an inner loop yourself.
Also, removing elements from lists while iterating is tricky. So, since you are not modifying the list and seem to be expected to return one, then just make a new list and add rather than remove.
public static ArrayList<ArrayList<Integer>> removeTheNumber(ArrayList<ArrayList<Integer>> n , Integer p){
ArrayList<ArrayList<Integer>> a = new ArrayList<>();
for(int i=0; i < n.size(); i++){
ArrayList<Integer> innerList = n.get(i);
if (!innerList.contains(p)) a.add(innerList);
}
return a;
}
You can use .contains of the inner lists to check as Integer class supports this. Below is a function and its test.
public ArrayList<ArrayList<Integer>> removeTheNumber(ArrayList<ArrayList<Integer>> lists, Integer n) {
ArrayList<ArrayList<Integer>> result = new ArrayList<>();
for (ArrayList<Integer> list: lists ) {
if (!list.contains(n))
result.add(list);
}
return result;
}
#Test
public void testRemoveNumber() {
ArrayList<ArrayList<Integer>> lists = new ArrayList<>();
lists.add(Lists.newArrayList(2,7,8));
lists.add(Lists.newArrayList(6,7,9));
lists.add(Lists.newArrayList(3,2,6));
ArrayList<ArrayList<Integer>> result = removeTheNumber(lists, 2);
Assert.assertArrayEquals(lists.get(1).toArray(new Integer[]{}), result.get(0).toArray(new Integer[]{}));
result = removeTheNumber(lists, 7);
Assert.assertArrayEquals(lists.get(2).toArray(new Integer[]{}), result.get(0).toArray(new Integer[]{}));
result = removeTheNumber(lists, 6);
Assert.assertArrayEquals(lists.get(0).toArray(new Integer[]{}), result.get(0).toArray(new Integer[]{}));
}
If you want to use two loops you can write it like this (where array is your input array, and toSearch is your integer):
ArrayList<ArrayList<Integer>> arrayToReturn = new ArrayList<>();
for(ArrayList<Integer> listInner : array){
boolean found = false;
for(Integer elem : listInner) {
if (elem == toSearch)
found=true;
}
if(found!=true)
arrayToReturn.add(listInner);
}
arrayToReturn.stream().forEach(System.out::println);
Of course i reccomend to use java 8, and then you can simply write it like this:
arrayToReturn = array.stream().filter(elem ->
!elem.contains(toSearch)).collect(
Collectors.toCollection(ArrayList<ArrayList<Integer>>::new));
arrayToReturn.stream().forEach(System.out::println);
Let's pretend you have
ArrayList<ArrayList<Integer>> myArrayList = [[1,2,3],[7,5],[4,4,2],[8,12,3]];
for (int i = 0; i < myArrayList.length; i++) {
//...
}
Your variable i is iterating through the initial ArrayList, which contains another ArrayList. So, myArrayList[i] will yield another ArrayList, which also has a length.
Building on this we have:
for (int i = 0; i < myArrayList.length; i++) {
ArrayList<Integer> inner = myArrayList.get(i);
for (int j = 0; j < inner.length; j++) {
//now we may check for the existence of our integer
}
}

Modify String objects in a static array

I want to make a for-loop to add a letter to each string object in my list. I'm just not sure how to edit the objects in the list and not the actual list.
for instance, if I wanted to add "ing" to the end of each object in my list..
I feel like it's something simple, but I've been looking through oracle forever and haven't been able to figure it out if anyone can point me in the right direction?
I could use any kind of list really.. just anything that works.
I was thinking something like,
String[] stringArray = tools.toArray(new String[0]);
for (int i = 0; i < stringArray.length; i++)
{
stringArray[i] = stringArray[i].*part that would modify would go here*
}
You cannot edit a String. They are immutable. However, you can replace the entry in the list.
ArrayList<String> list = new ArrayList<>();
list.add("load");
list.add("pull");
for (int i = 0; i < list.size(); ++i) {
list.set(i, list.get(i) + "ing");
You updated your question to specify a static array:
stringArray[i] = stringArray[i] + "ing";
The right side of the assignment is performing a String concatenation which can be done with the + operator in Java.
You can use StringBuilder for this purpose.
public static void addIng(String[] arr) {
StringBuilder sb = new StringBuilder();
for (int i = 0; i < arr.length; i++) {
sb.setLength(0);
sb.append(arr[i] + "ing");
arr[i] = sb.toString();
}
}
Strings are immutable in java; they can't be modified once created.
Here it seems you have a few options; you can create a method that takes your list and returns a new list, by appending 'ing' to the end of each string in the list.
Alternatively, if you need to keep a reference to the original list, you can loop over the contents of the list (ArrayList?) and pop each string out, create a new string with the appended 'ing', and replace in the list.
Something like
List<String> list = new ArrayList<>();
list.add("testing");
for(String s:list){
s=s+"ing";
}
Please take a look below samples.
//Java 8 code.
List<String> oldList = Arrays.asList("a", "b");
List<String> newList = oldList.stream().map(str -> new StringBuilder(str).append("ing").toString()).collect(Collectors.toList());
System.out.println(oldList); // [a, b]
System.out.println(newList); // [aing, bing]
// Java 7 or below.
List<String> oldList = Arrays.asList("a", "b");
List<String> newList = new LinkedList<String>();
for (String str : oldList) {
newList.add(new StringBuilder(str).append("ing").toString());
}
System.out.println(oldList); // [a, b]
System.out.println(newList); // [aing, bing]

How to find index of ArrayList item in String Array

I want to find ArrayList<String> item's index in String Array but every time indexOf() give -1 index .
I cant understand where is wrong? Please check my code and guide me.
public static void arrangeUiComponent() {
ArrayList<String> packageName = new ArrayList<String>();
packageName.add("com.example.dummy");
packageName.add("edu.app.reading");
ArrayList<Integer> index = getIndex(packageName);
}
// searching method
private static ArrayList<Integer> getIndex(ArrayList<String> searchName) {
ArrayList<Integer> indexList = new ArrayList<Integer>();
String[] collectionData = new String[] { "com.example.app",
"com.example.appdemo", "com.example.dummy", "edu.app.reading",
"edu.app.knowledge" };
/*
* for iterating each and every item of list
*/
for (int i = 0; i < searchName.size(); i++) {
Log.i("MISSION", "value will be: " + searchName.get(i).toString());
/*
* for searching listItem in package name array
*/
for (int j = 0; j < collectionData.length; j++) {
indexList.add(collectionData.toString().indexOf(searchName.get(i).toString()));
break;
}
}
return indexList;
}
Replace
for (int j = 0; j < collectionData.length; j++) {
indexList.add(collectionData.toString().indexOf(searchName.get(i).toString()));
break;
}
with
indexList.add(Arrays.asList(collectionData).indexOf(searchName.get(i)));
Here is the working demo of your code. Arrays.asList converts your string array to a list. Why don't you use a list instead of string collectionData array?
Use a debugger and look the value of collectionData.toString().
It returns something that is not your list of strings. That the object representation.
Quote from javadoc:
The toString method for class Object returns a string consisting of the name of the class of which the object is an instance, the at-sign character `#', and the unsigned hexadecimal representation of the hash code of the object.
EDIT:
whoops, collectionDatais an array, not a List, you should use
java.util.Arrays.asList(collectionData).indexOf(searchName.get(i))
It will search for the searchName.get(i)string inside the collectionDataList and not inside the collectionData representation which is a String (that's why indexOf is valid).
As searchName is a list of String, you don't need to add the toString() on searchName.get(i)
I'm assuming that in the indexLIst you want corresponding packageName's index values.
I don't think this will work in the way you want it.
The indexList being an Arraylist(data is not stored in the input order) might not have corresponding index values.
Ex:
packageName list:
"com.example.dummy", "edu.app.reading"
so the indexList should have values:
2 , 3
but it might contain:
3, 2 as well because data is not stored in the order in which it is entered.
You should probably use a linkedList if you want to preserve the order.
use a Hashmap<String, integer>.
You can do something like this using a hashmap:
public static void arrangeUiComponent() {
ArrayList<String> packageName = new ArrayList<String>();
packageName.add("com.example.dummy");
packageName.add("edu.app.reading");
HashMap<String, Integer> indexMap = getIndex(packageName);
for (String s : packageName) {
int index = indexMap.get(s);
}
}
private static HashMap<String, Integer> getIndex(ArrayList<String> searchName) {
HashMap<String, Integer> indexMap = new HashMap<String, Integer>();
String[] collectionData = new String[] { "com.example.app", "com.example.appdemo", "com.example.dummy",
"edu.app.reading", "edu.app.knowledge" };
for (String search : searchName) {
for (int i = 0; i < collectionData.length; i++) {
if (search.equals(collectionData[i])) {
indexMap.put(search, i);
break;
}
}
}
return indexMap;
}
You use collectionData.toString() which return [Ljava.lang.String;#15db9742. So collectionData.toString().indexof() always find nothing and return -1
To solve this you can use:
Declare arraylist as
ArrayList<String>cd = new ArrayList<String>(Arrays.asList(collectionData));
which convert String[] to ArrayList then ArrayList gives us facility of finding element with indexof().
Then in your inner for loop
for (int j = 0; j < collectionData.length; j++) {
indexList.add(cd.indexOf(searchName.get(i).toString()));
break;
}
toString() method of an array returns something similar to [Ljava.lang.String;#2a139a55. This is the reason you were getting index value as -1.
Other than the solution sam2090 provided, you can try 2 more options.
Replace
indexList.add(collectionData.toString().indexOf(searchName.get(i).toString()))
with
indexList.add(java.util.Arrays.binarySearch(collectionData, searchName.get(i)))
or
Replace collectionData.toString() with java.util.Arrays.toString(values)

removing duplicated words from an array

I am trying to remove duplicated words from an array, and I keep getting null values. I'm not allowed to use java sorting methods so I have to develop my own. Here's my code:
public class Duplicate{
public static void main(String[] args){
String[] test = {"a", "b", "abvc", "abccc", "a", "bbc", "ccc", "abc", "bbc"};
removeDuplicate(test);
}
public static String[] removeDuplicate(String[] words){
boolean [] isDuplicate = new boolean[words.length];
int i,j;
String[] tmp = new String[words.length];
for (i = 0; i < words.length ; i++){
if (isDuplicate[i])
continue;
for(j = 0; j < words.length ; j++){
if (words[i].equals(words[j])) {
isDuplicate[j] = true;
tmp[i] = words[i];
}
}
}
for(i=0;i<words.length;i++)
System.out.println(tmp[i]);
return tmp;
}
}
I tried doing
if(words == null)
words == "";
But it doesn't work. I also want to return the tmp array with a new size.
For example, test array length = 9, after removing the duplicates,I should get a new array with a length of 7.Thank you for your help.
EDIT:
result i get:
a
b
abvc
abccc
null
bbc
ccc
abc
null
You're getting nulls because the result array contains fewer words than the input array. However, you're constructing the arrays of the same length.
You don't have to sort to solve this problem. However, if you're not allowed to use the tools provided by java.utils, then this is either a poorly contrived test question or whomever told you not to use the Java utility classes is poorly informed.
You can solve without sorting by doing (assuming Java 1.5+):
public class Duplicate {
public static void main(String[] args) {
String[] test = {"a", "b", "abvc", "abccc", "a", "bbc", "ccc", "abc", "bbc"};
String[] deduped = removeDuplicate(test);
print(deduped);
}
public static String[] removeDuplicate(String[] words) {
Set<String> wordSet = new LinkedHashSet<String>();
for (String word : words) {
wordSet.add(word);
}
return wordSet.toArray(new String[wordSet.size()]);
}
public static void print(String[] words) {
for (String word : words) {
System.out.println(word);
}
}
}
The output will be:
a
b
abvc
abccc
bbc
ccc
abc
I would go for hashset to remove duplicates, it will remove duplicates since hash function for the same string will give same value, and duplicates will be eliminated. Then you can convert it to a string.
I would recommend doing this with a different approach. If you can use an ArrayList, why not just create one of those, and add the non-duplicate values to it, like this:
ArrayList<String> uniqueArrayList = new ArrayList<String>();
for(int i = 0; i < words.length; i++){
if(!uniqueArrayList.contains(words[i])){ // If the value isn't in the list already
uniqueArrayList.add(words[i]);
}
}
Now, you have an array list of all of your values without the duplicates. If you need to, you can work on converting that back to a regular array.
EDIT
I really think you should use the above option if you can, as there is no clean or decently efficient way to do this only using arrays. However, if you must, you can do something like this:
You can use the code you have to mark values as null if they are duplicates, and also create a counter to see how many unique values you have, like this:
int uniqueCounter = 0;
for(int i = 0; i < isDuplicate.length; i++){
if(!isDuplicate[i]){
uniqueCounter++;
}
}
Then, you can create a new array of the size of unique items, and loop through the words and add non-duplicate values.
String[] uniqueArray = new String[uniqueCounter];
int uniqueIndex = 0;
int wordsIndex = 0;
while(index < uniqueArray.length){
// Check if words index is not a duplicate
if(!isDuplicate[wordsIndex]){
// Add to array
uniqueArray[uniqueIndex] = words[wordsIndex];
uniqueIndex++; // Need to move to next spot in unique.
}
// Need to move to next spot in words
wordsIndex++;
}
Again, I HIGHLY recommend against something like this. It is very poor, and pains me to write, but for the sake of example on how it could be done using an array, you can try it.
I don't have the time to write functioning code, but I would reccomend to first sort the array using Arrays.sort(stringArray) and then loop throug the array coparing one string to the previous. Strings that match the previous one are duplicates.
Note: This method is probably not the fastest one and though only should be used on small arrays or in tasks where performance does not matter.
What about this approach?
public static String[] removeDuplicate(String[] words){
// remember which word is a duplicate
boolean[] isDuplicate = new boolean[words.length];
// and count them
int countDuplicate = 0;
for (int i = 0; i < words.length ; i++){
// only check "forward" because "backwards checked" duplicates have been marked yet
for(int j = i + 1; j < words.length ; j++){
if (words[i].equals(words[j])) {
isDuplicate[j] = true;
countDuplicate++;
}
}
}
// collect non-duplicate strings
String[] tmp = new String[words.length - countDuplicate];
int j = 0;
for (int i = 0; i < isDuplicate.length; i++) {
if (isDuplicate[i] == false) {
tmp[j] = words[i];
j++;
}
}
// and return them
return tmp;
}

Java - Removing duplicates in an ArrayList

I'm working on a program that uses an ArrayList to store Strings. The program prompts the user with a menu and allows the user to choose an operation to perform. Such operations are adding Strings to the List, printing the entries etc. What I want to be able to do is create a method called removeDuplicates(). This method will search the ArrayList and remove any duplicated values. I want to leave one instance of the duplicated value(s) within the list. I also want this method to return the total number of duplicates removed.
I've been trying to use nested loops to accomplish this but I've been running into trouble because when entries get deleted, the indexing of the ArrayList gets altered and things don't work as they should. I know conceptually what I need to do but I'm having trouble implementing this idea in code.
Here is some pseudo code:
start with first entry;
check each subsequent entry in the list and see if it matches the first entry;
remove each subsequent entry in the list that matches the first entry;
after all entries have been examined, move on to the second entry;
check each entry in the list and see if it matches the second entry;
remove each entry in the list that matches the second entry;
repeat for entry in the list
Here's the code I have so far:
public int removeDuplicates()
{
int duplicates = 0;
for ( int i = 0; i < strings.size(); i++ )
{
for ( int j = 0; j < strings.size(); j++ )
{
if ( i == j )
{
// i & j refer to same entry so do nothing
}
else if ( strings.get( j ).equals( strings.get( i ) ) )
{
strings.remove( j );
duplicates++;
}
}
}
return duplicates;
}
UPDATE: It appears that Will is looking for a homework solution that involves developing the algorithm to remove duplicates, rather than a pragmatic solution using Sets. See his comment:
Thx for the suggestions. This is part of an assignment and I believe the teacher had intended for the solution to not include sets. In other words, I am to come up with a solution that will search for and remove duplicates without implementing a HashSet. The teacher suggested using nested loops which is what I'm trying to do but I've been having some problems with the indexing of the ArrayList after certain entries are removed.
Why not use a collection such as Set (and an implementation like HashSet) which naturally prevents duplicates?
You can use nested loops without any problem:
public static int removeDuplicates(ArrayList<String> strings) {
int size = strings.size();
int duplicates = 0;
// not using a method in the check also speeds up the execution
// also i must be less that size-1 so that j doesn't
// throw IndexOutOfBoundsException
for (int i = 0; i < size - 1; i++) {
// start from the next item after strings[i]
// since the ones before are checked
for (int j = i + 1; j < size; j++) {
// no need for if ( i == j ) here
if (!strings.get(j).equals(strings.get(i)))
continue;
duplicates++;
strings.remove(j);
// decrease j because the array got re-indexed
j--;
// decrease the size of the array
size--;
} // for j
} // for i
return duplicates;
}
You could try this one liner to take a copy of the String preserving order.
List<String> list;
List<String> dedupped = new ArrayList<String>(new LinkedHashSet<String>(list));
This approach is also O(n) amortized instead of O(n^2)
Just to clarify my comment on matt b's answer, if you really want to count the number of duplicates removed, use this code:
List<String> list = new ArrayList<String>();
// list gets populated from user input...
Set<String> set = new HashSet<String>(list);
int numDuplicates = list.size() - set.size();
List<String> lst = new ArrayList<String>();
lst.add("one");
lst.add("one");
lst.add("two");
lst.add("three");
lst.add("three");
lst.add("three");
Set se =new HashSet(lst);
lst.clear();
lst = new ArrayList<String>(se);
for (Object ls : lst){
System.out.println("Resulting output---------" + ls);
}
I've been trying to use nested loops to accomplish this but I've been running into trouble because when entries get deleted, the indexing of the ArrayList gets altered and things don't work as they should
Why don't you just decrease the counter each time you delete an entry.
When you delete an entry the elements will move too:
ej:
String [] a = {"a","a","b","c" }
positions:
a[0] = "a";
a[1] = "a";
a[2] = "b";
a[3] = "c";
After you remove your first "a" the indexes are:
a[0] = "a";
a[1] = "b";
a[2] = "c";
So, you should take this into consideration and decrease the value of j ( j--) to avoid "jumping" over a value.
See this screenshot:
public Collection removeDuplicates(Collection c) {
// Returns a new collection with duplicates removed from passed collection.
Collection result = new ArrayList();
for(Object o : c) {
if (!result.contains(o)) {
result.add(o);
}
}
return result;
}
or
public void removeDuplicates(List l) {
// Removes duplicates in place from an existing list
Object last = null;
Collections.sort(l);
Iterator i = l.iterator();
while(i.hasNext()) {
Object o = i.next();
if (o.equals(last)) {
i.remove();
} else {
last = o;
}
}
}
Both untested.
Assuming you can't use a Set like you said, the easiest way of solving the problem is to use a temporary list, rather than attempting to remove the duplicates in place:
public class Duplicates {
public static void main(String[] args) {
List<String> list = new ArrayList<String>();
list.add("one");
list.add("one");
list.add("two");
list.add("three");
list.add("three");
list.add("three");
System.out.println("Prior to removal: " +list);
System.out.println("There were " + removeDuplicates(list) + " duplicates.");
System.out.println("After removal: " + list);
}
public static int removeDuplicates(List<String> list) {
int removed = 0;
List<String> temp = new ArrayList<String>();
for(String s : list) {
if(!temp.contains(s)) {
temp.add(s);
} else {
//if the string is already in the list, then ignore it and increment the removed counter
removed++;
}
}
//put the contents of temp back in the main list
list.clear();
list.addAll(temp);
return removed;
}
}
You could do something like this, must of what people answered above is one alternative, but here's another.
for (int i = 0; i < strings.size(); i++) {
for (int j = j + 1; j > strings.size(); j++) {
if(strings.get(i) == strings.get(j)) {
strings.remove(j);
j--;
}`
}
}
return strings;
Using a set is the best option to remove the duplicates:
If you have a list of of arrays you can remove the duplicates and still retain array list features:
List<String> strings = new ArrayList<String>();
//populate the array
...
List<String> dedupped = new ArrayList<String>(new HashSet<String>(strings));
int numdups = strings.size() - dedupped.size();
if you can't use a set, sort the array (Collections.sort()) and iterate over the list, checking if the current element is equal to the previous element, if it is, remove it.
Using a set is the best option (as others suggested).
If you want to compare all elements in a list with eachother you should slightly adapt your for loops:
for(int i = 0; i < max; i++)
for(int j = i+1; j < max; j++)
This way you don't compare each element only once instead of twice. This is because the second loop start at the next element compared to the first loop.
Also when removing from a list when iterating over them (even when you use a for loop instead of an iterator), keep in mind that you reduce the size of the list. A common solution is to keep another list of items you want to delete, and then after you finished deciding which to delete, you delete them from the original list.
public ArrayList removeDuplicates(ArrayList <String> inArray)
{
ArrayList <String> outArray = new ArrayList();
boolean doAdd = true;
for (int i = 0; i < inArray.size(); i++)
{
String testString = inArray.get(i);
for (int j = 0; j < inArray.size(); j++)
{
if (i == j)
{
break;
}
else if (inArray.get(j).equals(testString))
{
doAdd = false;
break;
}
}
if (doAdd)
{
outArray.add(testString);
}
else
{
doAdd = true;
}
}
return outArray;
}
You could replace the duplicate with an empty string*, thus keeping the indexing in tact. Then after you've completed you can strip out the empty strings.
*But only if an empty string isn't valid in your implementation.
The problem you are seeing in your code is that you remove an entry during iteration, thus invalidating the iteration location.
For example:
{"a", "b", "c", "b", "b", "d"}
i j
Now you are removing strings[j].
{"a", "b", "c", "b", "d"}
i j
The inner loop ends and j is incremented.
{"a", "b", "c", "b", "d"}
i j
Only one duplicate 'b' detected...oops.
best practice in these cases is to store the locations that have to be removed, and remove them after you have finished iterating through the arraylist. (One bonus, the strings.size() call can be optimized outside of the loops by you or the compiler)
Tip, you can start iterating with j at i+1, you've already checked the 0 - i!
The inner for loop is invalid. If you delete an element, you cannot increment j, since j is now pointing at the element after the one you deleted, and you will need to inspect it.
In other words, you should use a while loop instead of a for loop, and only increment j if the elements at i and j do not match. If they do match, remove the element at j. size() will decrease by 1 and j will now be pointing at the following element, so there is no need to increase j.
Also, there is no reason to inspect all elements in the inner loop, just the ones following i, since duplicates before i have already been removed by prior iterations.
public <Foo> Entry<Integer,List<Foo>> uniqueElementList(List<Foo> listWithPossibleDuplicates) {
List<Foo> result = new ArrayList<Foo>();//...might want to pre-size here, if you have reliable info about the number of dupes
Set<Foo> found = new HashSet<Foo>(); //...again with the pre-sizing
for (Foo f : listWithPossibleDuplicates) if (found.add(f)) result.add(f);
return entryFactory(listWithPossibleDuplicates.size()-found.size(), result);
}
and then some entryFactory(Integer key, List<Foo> value) method. If you want to mutate the original list (possibly not a good idea, but whatever) instead:
public <Foo> int removeDuplicates(List<Foo> listWithPossibleDuplicates) {
int original = listWithPossibleDuplicates.size();
Iterator<Foo> iter = listWithPossibleDuplicates.iterator();
Set<Foo> found = new HashSet<Foo>();
while (iter.hasNext()) if (!found.add(iter.next())) iter.remove();
return original - found.size();
}
for your particular case using strings, you may need to deal with some additional equality constraints (e.g., are upper and lower case versions the same or different?).
EDIT: ah, this is homework. Look up Iterator/Iterable in the Java Collections framework, as well as Set, and see if you don't come to the same conclusion I offered. The generics part is just gravy.
I am bit late to join this question, but I have come with a better solution regarding the same using GENERIC type. All the above provided solutions are just a solution. They are increasing a lead to the complexity of whole runtime thread.
RemoveDuplicacy.java
We can minimize it using a technique which should do the required , at the Load Time.
Example : For suppose when you are using a arraylist of the class type as :
ArrayList<User> usersList = new ArrayList<User>();
usersList.clear();
User user = new User();
user.setName("A");
user.setId("1"); // duplicate
usersList.add(user);
user = new User();
user.setName("A");
user.setId("1"); // duplicate
usersList.add(user);
user = new User();
user.setName("AB");
user.setId("2"); // duplicate
usersList.add(user);
user = new User();
user.setName("C");
user.setId("4");
usersList.add(user);
user = new User();
user.setName("A");
user.setId("1"); // duplicate
usersList.add(user);
user = new User();
user.setName("A");
user.setId("2"); // duplicate
usersList.add(user);
}
The Class for which is the base for the arraylist used above : User class
class User {
private String name;
private String id;
/**
* #param name
* the name to set
*/
public void setName(String name) {
this.name = name;
}
/**
* #return the name
*/
public String getName() {
return name;
}
/**
* #param id
* the id to set
*/
public void setId(String id) {
this.id = id;
}
/**
* #return the id
*/
public String getId() {
return id;
}
}
Now in java there are two Overrided methods present of Object (parent) Class, which can help here in the means to serve our purpose better.They are :
#Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((id == null) ? 0 : id.hashCode());
return result;
}
#Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
User other = (User) obj;
if (id == null) {
if (other.id != null)
return false;
} else if (!id.equals(other.id))
return false;
return true;
}
You have to override these methods in the User class
Here is the complete code :
https://gist.github.com/4584310
Let me know if you have any queries.
You can add the list into a HashSet and then again convert that hashset into list to remove the duplicates.
public static int removeDuplicates(List<String> duplicateList){
List<String> correctedList = new ArrayList<String>();
Set<String> a = new HashSet<String>();
a.addAll(duplicateList);
correctedList.addAll(a);
return (duplicateList.size()-correctedList.size());
}
here it will return the number of duplicates. You can also use the correctList with all unique values
Below is the code to remove duplicate elements from a list without changing the order of the list,without using temporary list and without using any set variables.This code saves the memory and boosts performance.
This is a generic method which works with any kind of list.
This was the question asked in one of the interviews.
Searched in many forums for the solution but could not find one,so thought this is the correct forum to post the code.
public List<?> removeDuplicate(List<?> listWithDuplicates) {
int[] intArray = new int[listWithDuplicates.size()];
int dupCount = 1;
int arrayIndex = 0;
int prevListIndex = 0; // to save previous listIndex value from intArray
int listIndex;
for (int i = 0; i < listWithDuplicates.size(); i++) {
for (int j = i + 1; j < listWithDuplicates.size(); j++) {
if (listWithDuplicates.get(j).equals(listWithDuplicates.get(i)))
dupCount++;
if (dupCount == 2) {
intArray[arrayIndex] = j; // Saving duplicate indexes to an array
arrayIndex++;
dupCount = 1;
}
}
}
Arrays.sort(intArray);
for (int k = intArray.length - 1; k >= 0; k--) {
listIndex = intArray[k];
if (listIndex != 0 && prevListIndex != listIndex){
listWithDuplicates.remove(listIndex);
prevListIndex = listIndex;
}
}
return listWithDuplicates;
}

Categories

Resources