How to remove duplicate elements from list<String>? [duplicate] - java

This question already has answers here:
How do I remove repeated elements from ArrayList?
(40 answers)
Closed 3 years ago.
List list = ["f1,f2","f2,f3","f4,f5","f2,f1","f5,f4"];
output list would be
List uniqueList = ["f1,f2","f2,f3","f4,f5"]

I have another solution . If you dont want to prepare another class to compare values inside List . You can separete each value by comma and sort those data. After that you can again converte them to Set of String
public static void main(String[] args) {
List<String> stringList = Arrays.asList("f1,f2", "f2,f3", "f4,f5", "f2,f1", "f5,f4");
Set<String> result = new HashSet<>();
for (String s : stringList) {
String[] elements = s.split(",");
Arrays.sort(elements);
result.add(Arrays.toString(elements));
}
for (String e : result){
System.out.println(e);
}
}

Using an additional class:
static class Pair {
String a, b;
Pair(String s) {
String[] arr = s.split(",");
this.a = arr[0];
this.b = arr[1];
}
static String pairToString(Pair p) {
return p.a + "," + p.b;
}
#Override
public int hashCode() {
return Objects.hash(a, b) + Objects.hash(b, a);
}
#Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Pair p = (Pair) o;
return (p.a.equals(a) && p.b.equals(b)) || (p.b.equals(a) && p.a.equals(b));
}
}
Now you can use:
public static void main(String[] args) {
List<String> list = Arrays.asList("f1,f2", "f2,f3", "f4,f5", "f2,f1", "f5,f4");
List<String> strings = list
.stream()
.map(Pair::new)
.distinct()
.map(Pair::pairToString)
.collect(Collectors.toList());
}

I have created a class to model the pairs and override the equals method to treat "f1,f2" and "f2,f1" as equals and then found out the duplicates using HashSet.
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
public class so1 {
public static void main(String[] args) {
List<String> list = Arrays.asList(new String[] {"f1,f2","f2,f3","f4,f5","f2,f1","f5,f4"});
List<pair> plist = new ArrayList<pair>();
for (int i = 0; i < list.size(); i++) {
plist.add(new pair(list.get(i)));
}
HashSet<pair> hs = new HashSet<pair>();
for (int i = 0; i < plist.size(); i++) {
if(!hs.add(plist.get(i))){
System.out.println("Found duplicate "+plist.get(i).toString());
}
}
List<String> uniqueItems = new ArrayList<String>();
for (Iterator iterator = hs.iterator(); iterator.hasNext();) {
pair pair = (pair) iterator.next();
uniqueItems.add(pair.toString());
}
System.out.println(uniqueItems);
}
}
class pair{
pair(String inp){
String[] tokens = inp.split(",");
Arrays.sort(tokens);
for(String t: tokens){
elements.add(t);
}
}
List<String> elements = new ArrayList<>();
#Override
public String toString() {
return ""+elements;
}
#Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((elements == null) ? 0 : elements.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;
pair other = (pair) obj;
if (elements == null) {
if (other.elements != null)
return false;
} else if (!elements.equals(other.elements))
return false;
return true;
}
}

Here are a couple answers from https://www.geeksforgeeks.org/how-to-remove-duplicates-from-arraylist-in-java/
Java 7
// Create a new ArrayList
ArrayList<String> uniqueList = new ArrayList<String>();
// Traverse through the first list
for ( element : list) {
// If this element is not present in uniqueList
// then add it
if (!uniqueList.contains(element)) {
uniqueList.add(element);
}
}
Java 8
List<String> uniqueList = list.stream()
.distinct()
.collect(Collectors.toList());

Related

Remove duplicate Tuples from an ArrayList- Java

I want to have an unique List of tuples without duplicates.
List <Tuple> newNonZeros = new ArrayList<>();
and in newNonZeroes is the result: [(0,2)(1,2)(1,2)(1,1)(2,2)(2,2)(2,1)]
Here's what I tried:
List <Tuple> newList = new ArrayList<>();
newList.add(newNonZeros.get(0));
for(int i=1; i < newNonZeros.size();i++){
if(newNonZeros.get(i-1)!= newNonZeros.get(i)){
newList.add(newNonZeros.get(i));
}
}
It doesn't work. Can someone help me...it's a very simple problem
I also tried the following method:
...newNonZeros.stream().distinct().collect(Collectors.toList());
Override equals and hashCode in your Tuple class:
#Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Tuple tuple = (Tuple) o;
return first == tuple.first &&
second == tuple.second;
}
#Override
public int hashCode() {
return Objects.hash(first, second);
}
Then you can use:
List<Tuple> newList = newNonZeros.stream()
.distinct()
.collect(Collectors.toList());
Or with a for-each loop:
List<Tuple> newList = new ArrayList<>();
for(Tuple tuple : newNonZeros) {
if(!newList.contains(tuple)) {
newList.add(tuple);
}
}

Removing an instance from a linked list which is using pairs

I am trying to remove an instance from my linked list however when i try searching for the object in the list it returns a value of -1 because it says its not there. what am i doing wrong. my application class is below and that calls the methods in my DataSet class
public class Application {
public static void main(String[] args) {
DataSet<String, Integer> db = new DataSet<>();
db.add("Theo", 4);
db.add("Maria", 5);
db.add("Adam", 4);
db.add("James", 5);
db.add("Charles", 7);
db.add("Nikki", 5);
db.add("Lynne", 5);
db.add("Kendal", 6);
db.add("Kerry", 5);
db.add("Janet", 5);
db.add("Gordon", 6);
db.add("Stepher", 7);
db.add("Sue", 3);
db.add("Ed", 2);
db.add("Adam", 4);
db.displayItems();
/*
System.out.println();
db.sortByFirst();
db.displayItems();
System.out.println();
db.sortBySecond();
db.displayItems();
System.out.println();
(db.findBySecond(5)).displayItems();
System.out.println();
(db.findByFirst("Adam")).displayItems();
System.out.println();
*/ System.out.println(db.remove("Adam", 4));
db.displayItems();
//System.out.println("size = " + db.size());
}
}
and the dataset is:
import java.util.LinkedList;
/**
*
* #param <T>
* #param <S>
*/
public class DataSet<T, S> {
LinkedList<Pair> datastructure = new LinkedList<>();
// Adds a new instance/item to the data structure.
public void add(T first, S second) {
Pair p = new Pair(first, second);
datastructure.add(p);
}
// Displays all itmes in the data structure.
public void displayItems() {
for (int i = 0; i < datastructure.size(); i++) {
System.out.println(datastructure.get(i));
}
}
// Removes all instances with matching criteria (first and second attribute values) and returns the number of instances removed.
public int remove(T first, S second) {
int count = 0;
Pair p = new Pair(first, second);
for (Pair datastructure1 : datastructure) {
Integer num = datastructure.indexOf(p);
System.out.println(num);
Boolean removed = datastructure.remove(p);
System.out.println(removed);
}
//will return count of how many removed
return count;
}
}
and the final class is the pair class
class Pair<T,S> {
private T first;
private S second;
public Pair(T theFirst, S theSecond) {
first = theFirst;
second = theSecond;
}
public T getFirst() {
return first;
}
public S getSecond() {
return second;
}
#Override
public String toString() {
return "(" + first + ", " + second + ")";
}
}
Like Adam pointed out the problem is that you're creating a new pair that is not in the list. What you want to do is to create an equals method in your Pair class and then iterate through your list comparing the elements using this equals method. The method should look like this:
#Override
public boolean equals(Object obj) {
if (obj == null) {
return false;
}
if (getClass() != obj.getClass()) {
return false;
}
final Pair other = (Pair) obj;
if (this.first != other.first) {
return false;
}
if (this.second != other.second) {
return false;
}
return true;
}
public int remove(T first, S second) {
int count = 0;
Pair p = new Pair(first, second);
for (Pair datastructure1 : datastructure) {
Integer num = datastructure.indexOf(p);
System.out.println(num);
Boolean removed = datastructure.remove(p);
System.out.println(removed);
}
//will return count of how many removed
return count;
}
In above remove method, you are creating a new Pair object. New object means new reference, So datastructure.indexOf(p) will always result -1.
Example:
datastructure contains three pairs:
Pair1 - reference 0x00000001 - "Theo",4
Pair2 - reference 0x00000002 - "Theo",5
Pair3 - reference 0x00000003 - "Theo",6
And we asked to remove "Theo",4. So `p` will be a new object like:
p - reference 0x00000004 - "Theo",4
This means that the reference of p will not match and it will not check the data. Modify the equals method of Pair class as follows:
#Override
public boolean equals(Object obj) {
if(this == obj)
return true;
if(obj instanceof Pair)
{
Pair pair = (Pair)obj;
if(pair.first.equals(this.first) && pair.second.equals(this.second)){
return true;
}
}
return false;
}

Converting a delimited file into a Tree

I'm working on converting a delimited file into an ordered tree structure. Below is a sample input...
1.2.3.4.5
1.3.2.4.5
1.2.4.5.6
I need to be able to convert this into an output like the following (in a searchable tree structure)...
1
-2
--3
---4
----5
--4
---5
----6
-3
--2
---4
----5
My thoughts on a solution to this was to...
Iterate the text file and create an arraylist that represents each row
Use Collections.sort() to make the arraylist sorted
Use a TreeMap to store the "base" record as a key (1 in this case) and an arrayList of strings to contain all the records
Iterate the TreeMap's keys and convert its arrayList to a LinkedHashSet that contains Nodes that represent each entry
Iterate the Tree's keys and print each node buy its index value
I thought everything was working well but when I started testing this approach, I found my output looks like below...
1
-2
--3
---4
----5
--4
---5
----6
-3
--2
As can be seen, the Nodes under 3/2/xx are not present, this is due to the logic I am using to build the LinkedHashSet for my Node values (Node(3, 4)) will simply be ignore because its a duplicate Node. I thought I was going in the right direction with this but now I can see my logic is clearly flawed. Does anyone have any suggestions for an approach for something like this? My current code is below...
TreeBuilder.java
public class TreeBuilder {
public static void main(String[] args) {
// Get a list of records
List<String> data = new ArrayList<String>();
data.add("1.2.3.4.5");
data.add("1.3.2.4.5");
data.add("1.2.4.5.6");
Collections.sort(data);
// Build the "Base" tree
TreeMap<String, List<String>> tree = buildBaseTree(data);
// Build the target tree structure
TreeMap<String, LinkedHashSet<Node>> finalTree = convertListToSet(tree);
printRecords(finalTree);
}
public static void printRecords(
TreeMap<String, LinkedHashSet<Node>> recordTree) {
System.out.println("---------Records---------");
for (Map.Entry<String, LinkedHashSet<Node>> entry : recordTree
.entrySet()) {
System.out.println(entry.getKey());
// Print out the structured data
StringBuilder stringBuilder = new StringBuilder();
Iterator<Node> iterator = entry.getValue().iterator();
while (iterator.hasNext()) {
Node node = iterator.next();
for (int i = 0; i < node.index; i++) {
stringBuilder.append("-");
}
System.out.println(stringBuilder.toString() + node.value);
// "reset" the builder
stringBuilder.setLength(0);
}
}
}
private static TreeMap<String, LinkedHashSet<Node>> convertListToSet(
TreeMap<String, List<String>> tree) {
TreeMap<String, LinkedHashSet<Node>> finalMap = new TreeMap<String, LinkedHashSet<Node>>();
LinkedHashSet<Node> linkedHashSet = new LinkedHashSet<Node>();
// Iterate the entry set
for (Map.Entry<String, List<String>> entry : tree.entrySet()) {
List<String> records = entry.getValue();
for (String record : records) {
String[] recordArray = record.split("\\.");
for (int i = 1; i < recordArray.length; i++) {
Node node = new Node(i, Integer.parseInt(recordArray[i]));
linkedHashSet.add(node);
}
}
finalMap.put(entry.getKey(), linkedHashSet);
// reset our linkedHashSet
linkedHashSet = new LinkedHashSet<Node>();
}
System.out.println("Final map " + finalMap);
return finalMap;
}
/**
* Builds a tree with base record keys and a list of records for each key.
*
* #param data
* #return
*/
private static TreeMap<String, List<String>> buildBaseTree(List<String> data) {
TreeMap<String, List<String>> tree = new TreeMap<String, List<String>>();
List<String> recordList = null;
// First find all base records
for (String record : data) {
String[] baseEntry = record.split("\\.");
if (!tree.containsKey(baseEntry[0])) {
recordList = new ArrayList<String>();
tree.put(baseEntry[0], recordList);
}
}
// Now place all sub-records in each base record
for (String record : data) {
String[] baseEntry = record.split("\\.");
tree.get(baseEntry[0]).add(record);
}
System.out.println("------------------Base Tree---------------");
System.out.println(tree);
System.out.println("------------------------------------------");
return tree;
}
private static List<String> readData(String file) {
BufferedReader bufferedReader = null;
try {
bufferedReader = new BufferedReader(new FileReader(new File(file)));
} catch (FileNotFoundException e) {
e.printStackTrace();
}
List<String> data = new ArrayList<String>();
// Get a list of all the records
String line = null;
try {
while ((line = bufferedReader.readLine()) != null) {
data.add(line);
}
} catch (IOException e) {
e.printStackTrace();
}
// Sort the list so its ordered
System.out.println("-------------Sorted Data Set-----------");
Collections.sort(data);
for (String record : data) {
System.out.println(record);
}
System.out.println("---------------------------------------");
return data;
}
}
Node.java
public class Node implements Comparable<Node> {
int index;
int value;
public Node(int index, int value) {
this.index = index;
this.value = value;
}
public int getIndex() {
return index;
}
#Override
public String toString() {
return "Node [index=" + index + ", value=" + value + "]";
}
public void setIndex(int index) {
this.index = index;
}
public int getValue() {
return value;
}
public void setValue(int value) {
this.value = value;
}
#Override
public int compareTo(Node o) {
Node otherNode = (Node) o;
if (this.index > otherNode.index)
return 1;
if (this.index < otherNode.index) {
return -1;
}
return 0;
}
#Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + index;
result = prime * result + value;
return result;
}
#Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
Node other = (Node) obj;
if (index != other.index)
return false;
if (value != other.value)
return false;
return true;
}
}
It doesn't have to be complicated. All you need is a SortedMap of SortedMap instances and there's only one trick to it: Parameterizing it recursively for type safety (if desired).
package com.acme;
import java.util.ArrayList;
import java.util.List;
import java.util.Map.Entry;
import java.util.TreeMap;
public class Main {
public static void main(String[] args) {
List<String> rows = new ArrayList<>();
rows.add("1.2.3.4.5");
rows.add("1.3.2.4.5");
rows.add("1.2.4.5.6");
MyTreeMap root = new MyTreeMap();
for (String row : rows) {
MyTreeMap n = root;
String[] cells = row.split("\\.");
for (String cell : cells) {
MyTreeMap child = n.get(cell);
if (child == null) {
n.put(cell, child = new MyTreeMap());
}
n = child;
}
}
print(root, "", "-");
}
static void print(MyTreeMap m, String indentationStr, String indentationStrAddition) {
for (Entry<String, MyTreeMap> o : m.entrySet()) {
System.out.println(indentationStr + o.getKey());
print(o.getValue(), indentationStr + indentationStrAddition, indentationStrAddition);
}
}
/**
* This is just a construct that helps us to parameterize recursively.
*/
static class MyTreeMap extends TreeMap<String, MyTreeMap> {private static final long serialVersionUID = 1L;}
}
If I understand your problem you want to create search trees from a list of integers that share common prefixes. If that's the case then I think you can achieve this with a lot less code:
private static class TreeNode {
private final Map<Integer, TreeNode> children = new HashMap<>();
public void insert(List<Integer> values) {
if (!values.isEmpty()) {
children.putIfAbsent(values.get(0), new TreeNode());
children.get(values.get(0)).insert(values.subList(1, values.size()));
}
}
public void print(int level) {
for (Map.Entry<Integer, TreeNode> entry : children.entrySet()) {
System.out.print(String.join("", Collections.nCopies(level, "-")));
System.out.println(entry.getKey());
entry.getValue().print(level + 1);
}
}
}
I'm not certain if you intend to sort the list of integers. If so you can add a Collections.sort at the appropriate place in the code.

Comparing two list of objects in Java

I have two list of Student Objects(listA & listB) which were formed by querying from two different databases. I need to iterate one list and need to make sure it is not present in the other list.
I have used the below comparison code for the same i.e overwritten the equals method and compared using for loops.
Say List A & List B could have 5000 rows each, can you suggest if there are better ways to implement this?
Comparison code:
for (Student dataA:listA) {
for (Student dataB:listB) {
if(dataB.equals(dataA))
break;
}
}
Student Object:
public class Student {
int A;
int B;
String C;
#Override
public boolean equals(Object obj) {
if (obj == this) {
return true;
}
if (obj == null || obj.getClass() != this.getClass()) {
return false;
}
Student student = (Student) obj;
return A == student.A && B == student.B && C.equals(student.C);
}
}
Edit Note: ListA & ListB can have different number of rows
I would suggest you the retainAll method:
List<Student> listC = new ArrayList();
listC.addAll(listA);
listC.retainAll(listB); //now listC contains all double students
But you should still override the equals method
You could use containsAny method from CollectionUtils (Apache Commons):
if(CollectionUtils.containsAny(listA, listB)){
break;
}
The removeAll command is the way to go, but List lookup is not efficient (linear time), so you get a O(n*m) total time (n is sizeA, m is sizeB); 5000 entries on each, it may be a bit too much.
If possible, you should change it to use Sets (and implements the hashCode and equals methods of your Student classes in case you didn't already!):
Set<Student> studentsA = new HashSet<>();
Set<Student> studentsB = new HashSet<>();
studentsA.removeAll(studentsB);
This gets you O(m*hash(n)).
The general approach is iterate through first list and check for element if it is contained in second list, if it exist add the element to the result list
Below is the complete solution
import java.util.ArrayList;
import java.util.List;
public class CompareListofObj {
public static void main(String[] args) {
List<Student> listStd1 = new ArrayList<Student>();
List<Student> listStd2 = new ArrayList<Student>();
Student std1 = new Student(1, 1, "a");
Student std2 = new Student(2, 1, "b");
Student std3 = new Student(3, 3, "c");
Student std4 = new Student(4, 4, "d");
listStd1.add(std1);
listStd1.add(std2);
listStd1.add(std3);
listStd1.add(std4);
Student std5 = new Student(1, 1, "a");
Student std6 = new Student(2, 1, "b");
Student std7 = new Student(7, 7, "c");
Student std8 = new Student(8, 8, "d");
listStd2.add(std5);
listStd2.add(std6);
listStd2.add(std7);
listStd2.add(std8);
List<Student> listResult = new ArrayList<Student>();
for (int i = 0; i < listStd1.size(); i++) {
if (listStd2.contains(listStd1.get(i))) {
listResult.add(listStd1.get(i));
} else {
}
}
for (int i = 0; i < listResult.size(); i++) {
System.out.println("common elt" + listResult.get(i).getA() + ", " + listResult.get(i).getB() + ", "
+ listResult.get(i).getC());
}
}
}
Student class
package sample;
public class Student {
int A;
int B;
String C;
public Student(int a, int b, String c) {
super();
A = a;
B = b;
C = c;
}
public int getA() {
return A;
}
public void setA(int a) {
A = a;
}
public int getB() {
return B;
}
public void setB(int b) {
B = b;
}
public String getC() {
return C;
}
public void setC(String c) {
C = c;
}
#Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + A;
result = prime * result + B;
result = prime * result + ((C == null) ? 0 : C.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;
Student other = (Student) obj;
if (A != other.A)
return false;
if (B != other.B)
return false;
if (C == null) {
if (other.C != null)
return false;
} else if (!C.equals(other.C))
return false;
return true;
}
}

Code for deleting rows from ArrayList#1 that appear in another ArrayList#2 and are non-unique in ArrayList#1

This post is the continuation of my previous post. Now I have a code that I'd like to compile. The only difference is that now I'm using lists of my own class List<Row> instead of List<Integer[]>. In particular look at hashCode in Row, because it provides a compilation error.
public class Row {
private String key;
private Integer[] values;
public Row(String k,Integer[] v) {
this.key = k;
this.values = v;
}
public String getKey() {
return this.key;
}
public Integer[] getValues() {
return this.values;
}
#Override
public boolean equals(Object obj) {
if(this == obj)
return true;
if((obj == null) || (obj.getClass() != this.getClass()))
return false;
// object must be Row at this point
Row row = (Row)obj;
return ((key == row.key) && (values == row.values));
}
#Override
public int hashCode () { // HERE I HAVE A PROBLEM. DON'T KNOW HOW TO IMPLEMENT IT
return this.key;
}
}
public class Test {
public static void main(String[] args) {
List<Row> allRows = new ArrayList<Row>();
allRows.add(new Row("0",new Integer[]{1,2,3}));
allRows.add(new Row("0",new Integer[]{1,2,2}));
allRows.add(new Row("1",new Integer[]{1,2,3}));
allRows.add(new Row("2",new Integer[]{1,1,1}));
allRows.add(new Row("2",new Integer[]{1,1,1}));
List<Row> selectedRows = new ArrayList<Row>();
selectedRows.add(new Row("0",new Integer[]{1,2,3}));
selectedRows.add(new Row("2",new Integer[]{1,1,1}));
System.out.println(allRows);
System.out.println(selectedRows);
List<Row> refreshedRows = refreshRows(allRows,selectedRows);
System.out.println(refreshedRows);
}
private static List<Row> refreshRows(List<Row> allRows,List<Row> selectedRows) {
Set<Row> set1 = new HashSet<Row>();
Iterator<Row> it = allRows.iterator();
while(it.hasNext()) {
Row curr = it.next();
if (!set1.add(curr) && selectedRows.contains(curr)) {
it.remove();
}
}
return allRows;
}
}
The result, i.e. refreshedArray, should be equal to:
key = "0", values = {1,2,3}
key = "0", values = {1,2,2};
key = "1", values = {1,2,3};
key = "2", values = {1,1,1};
Try with the following. Despite minor changes, most of the code is generated by Netbeans IDE 7.0:
#Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (obj == null) {
return false;
}
if (getClass() != obj.getClass()) {
return false;
}
final Row other = (Row) obj;
if ((this.key == null) ? (other.key != null) : !this.key.equals(other.key)) {
return false;
}
if (!java.util.Arrays.deepEquals(this.values, other.values)) {
return false;
}
return true;
}
#Override
public int hashCode() {
int hash = 3;
hash = 79 * hash + (this.key != null ? this.key.hashCode() : 0);
hash = 79 * hash + java.util.Arrays.deepHashCode(this.values);
return hash;
}
Look at the signature for hashcode(). It returns a primitive integer. You are returning key which is of type String. Try something like this:
#Override
public int hashCode() {
int hash = 1;
hash = hash * 31 + key.hashCode();
//hash = hash * 31 + otherFields.hashCode() etc
return hash;
}
which your IDE can even generate for you. You should probably read up on hashcodes. Your equals method looks wrong too. What is meant by comparing the two Integer arrays for equality?

Categories