Need to Remove Duplicate from List - java

I have a list of objects in ArrayList.I want to remove the duplicate object in the list based on old paymentDate.For an Example, if the member (Vishal) repeated two times I need to remove the Vishal object based on old paymnetDate from the list.
[{CreditCardNum,name,Amount,DueDate,PaymentDate}]
masterlist = [{4123456789123456,Vishal,80000,03/06/2015,07/06/2015},
{4123456789123456,Vivek,80000,07/06/2015,11/06/2015},
{4123456789123456,Vishal,80000,03/06/2015,09/06/2015}];
Removable Object from List =
{4123456789123456,Vishal,80000,03/06/2015,07/06/2015}
List<CreditcardVo> masterlist =new ArrayList<CreditcardVo>();
public class CreditCardVO {
public String creditNumber;
public String name;
public int amount;
public Date dueDate;
public Date paymentDate;
public String getCreditNumber() {
return creditNumber;
}
public void setCreditNumber(String creditNumber) {
this.creditNumber = creditNumber;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAmount() {
return amount;
}
public void setAmount(int amount) {
this.amount = amount;
}
public Date getDueDate() {
return dueDate;
}
public void setDueDate(Date dueDate) {
this.dueDate = dueDate;
}
public Date getPaymentDate() {
return paymentDate;
}
public void setPaymentDate(Date paymentDate) {
this.paymentDate = paymentDate;``
}
}

Here is the algorithm that you can use to do that:
First You need a unique identifier for each of the object in the ArrayList. The identifier can me the name if you are sure that the name does not repeat.
Step 1: Create an empty map where the key is the object identifier and the value will be the object itself
Step 2: For each element, in ArrayList :
Check if the map contains the identifier of the object
If yes then get the value val associated to that identifier in the map and compare it its date with the date of your current object curr:
if val has the latest date then do nothing
if curr has the latest date then call map.put(identifier, curr) to update the value in the map
If no, then map.put(identifier, curr) to add the current object to the map
At the end, the result will be the values of the map. And you can get that by using map.values()

You can create a method as such:
List<CreditCardVO> getDistinctObjectsByName(List<CreditCardVO> cardVOS){
Collection<CreditCardVO> resultSet =
cardVOS.stream()
.collect(Collectors.toMap(CreditCardVO::getName, Function.identity(),
(left, right) ->
left.getPaymentDate().after(right.getPaymentDate()) ?
left : right
)).values();
return new ArrayList<>(resultSet);
}
which given a list of CreditCardVO will return a new list with distinct objects with the latest payment date.

Related

Find element matching in 2 lists using java 8 stream

My case is:
class Person {
String id ;
String name;
String age;
}
List<Person> list1 = {p1,p2, p3};
List<Person> list2 = {p4,p5, p6};
I want to know if there is person in list1 that has the same name and age in list2 but don't mind about id.
What is best and fast way?
Define yourself a key object that holds and compares the desired properties. In this simple case, you may use a small list whereas each index corresponds to one property. For more complex cases, you may use a Map (using property names as keys) or a dedicated class:
Function<Person,List<Object>> toKey=p -> Arrays.asList(p.getName(), p.getAge());
Having such a mapping function. you may use the simple solution:
list1.stream().map(toKey)
.flatMap(key -> list2.stream().map(toKey).filter(key::equals))
.forEach(key -> System.out.println("{name="+key.get(0)+", age="+key.get(1)+"}"));
which may lead to poor performance when you have rather large lists. When you have large lists (or can’t predict their sizes), you should use an intermediate Set to accelerate the lookup (changing the task’s time complexity from O(n²) to O(n)):
list2.stream().map(toKey)
.filter(list1.stream().map(toKey).collect(Collectors.toSet())::contains)
.forEach(key -> System.out.println("{name="+key.get(0)+", age="+key.get(1)+"}"));
In the examples above, each match gets printed. If you are only interested in whether such a match exists, you may use either:
boolean exists=list1.stream().map(toKey)
.anyMatch(key -> list2.stream().map(toKey).anyMatch(key::equals));
or
boolean exists=list2.stream().map(toKey)
.anyMatch(list1.stream().map(toKey).collect(Collectors.toSet())::contains);
A simple way to do that is to override equals and hashCode. Since I assume the equality between Person must also consider the id field, you can wrap this instance into a PersonWrapper which will implement the correct equals and hashCode (i.e. only check the name and age fields):
class PersonWrapper {
private Person person;
private PersonWrapper(Person person) {
this.person = person;
}
public static PersonWrapper wrap(Person person) {
return new PersonWrapper(person);
}
public Person unwrap() {
return person;
}
#Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (obj == null || getClass() != obj.getClass()) {
return false;
}
PersonWrapper other = (PersonWrapper) obj;
return person.name.equals(other.person.name) && person.age.equals(other.person.age);
}
#Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + person.name.hashCode();
result = prime * result + person.age.hashCode();
return result;
}
}
With such a class, you can then have the following:
Set<PersonWrapper> set2 = list2.stream().map(PersonWrapper::wrap).collect(toSet());
boolean exists =
list1.stream()
.map(PersonWrapper::wrap)
.filter(set2::contains)
.findFirst()
.isPresent();
System.out.println(exists);
This code converts the list2 into a Set of wrapped persons. The goal of having a Set is to have a constant-time contains operation for better performance.
Then, the list1 is filtered. Every element found in set2 is kept and if there is an element left (that is to say, if findFirst() returns a non empty Optional), it means an element was found.
Brute force, but pure java 8 solution will be this:
boolean present = list1
.stream()
.flatMap(x -> list2
.stream()
.filter(y -> x.getName().equals(y.getName()))
.filter(y -> x.getAge().equals(y.getAge()))
.limit(1))
.findFirst()
.isPresent();
Here, flatmap is used to join 2 lists. limit is used as we are interested in first match only, in which case, we do not need to traverse further.
Well if you don't care about the id field, then you can use the equals method to solve this.
Here's the Person class code
public class Person {
private String id ;
private String name;
private String age;
#Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Person sample = (Person) o;
if (!name.equals(sample.name)) return false;
return age.equals(sample.age);
}
#Override
public int hashCode() {
int result = name.hashCode();
result = 31 * result + age.hashCode();
return result;
}
}
Now, you can use stream to get the intersection like so. common will contain all Person objects where name and age are the same.
List<Person> common = list1
.stream()
.filter(list2::contains)
.collect(Collectors.toList());
<h3>Find List of Object passing String of Array Using java 8?</h3>
[Faiz Akram][1]
<pre>
public class Student {
private String name;
private Integer age;
public Student(String name, Integer age) {
super();
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
}
</pre>
// Main Class
<pre>
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;
public class JavaLamda {
public static void main(String[] k)
{
List<Student> stud = new ArrayList<Student>();
stud.add(new Student("Faiz", 1));
stud.add(new Student("Dubai", 2));
stud.add(new Student("Akram", 5));
stud.add(new Student("Rahul", 3));
String[] name= {"Faiz", "Akram"};
List<Student> present = Arrays.asList(name)
.stream()
.flatMap(x -> stud
.stream()
.filter(y -> x.equalsIgnoreCase(y.getName())))
.collect(Collectors.toList());
System.out.println(present);
}
}
</pre>
OutPut //[Student#404b9385, Student#6d311334]
[1]: http://faizakram.com/blog/find-list-object-passing-string-array-using-java-8/
This would work:
class PresentOrNot { boolean isPresent = false; };
final PresentOrNot isPresent = new PresentOrNot ();
l1.stream().forEach(p -> {
isPresent.isPresent = isPresent.isPresent || l2.stream()
.filter(p1 -> p.name.equals(p1.name) && p.age.equals(p1.age))
.findFirst()
.isPresent();
});
System.err.println(isPresent.isPresent);
Since forEach() takes Consumer, we have no way of returning and PresentOrNot {} is a workaround.
Aside : Where did you get such a requirement ? :)
You need to iterate over the two lists and compare the atributtes.
for(Person person1 : list1) {
for(Person person2 : list2) {
if(person1.getName().equals(person2.getName()) &&
person1.getAge().equals(person2.getAge())) {
//your code
}
}
}
public static void main(String[] args) {
OTSQuestions ots = new OTSQuestions();
List<Attr> attrs = ots.getAttrs();
List<String> ids = new ArrayList<>();
ids.add("101");
ids.add("104");
ids.add("102");
List<Attr> finalList = attrs.stream().filter(
attr -> ids.contains(attr.getId()))
.collect(Collectors.toList());
}
public class Attr {
private String id;
private String name;
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
private List<Attr> getAttrs() {
List<Attr> attrs = new ArrayList<>();
Attr attr = new Attr();
attr.setId("100");
attr.setName("Yoga");
attrs.add(attr);
Attr attr1 = new Attr();
attr1.setId("101");
attr1.setName("Yoga1");
attrs.add(attr1);
Attr attr2 = new Attr();
attr2.setId("102");
attr2.setName("Yoga2");
attrs.add(attr2);
Attr attr3 = new Attr();
attr3.setId("103");
attr3.setName("Yoga3");
attrs.add(attr3);
Attr attr4 = new Attr();
attr4.setId("104");
attr4.setName("Yoga4");
attrs.add(attr4);
return attrs;
}

Create field of predefined type with string and value, java

I want to be able to write a method with a string and integer as the parameters for example, and I want to then create a variable inside that class with the integer value in which I can later recall. For example:
public void setInt(String identifier, Integer) {
}
if I then call
setInt("age", 25); //stores 25 with identifier "age"
it would create a variable called age, which I could later access by calling
getInt("age") //would return 25
How would I go about doing this?
You could hold a Map data member, and use it to store values:
public class SomeClass {
// could (should?) be initialized in the ctor
private Map<String, Integer> map = new HashMap<>();
public void setInt (String identifier, int value) {
// This assumes identifier != null, for clarity
map.put (identifier, value);
}
public int getInt (String identifier) {
return map.get (identifier);
}
If you had a Map you could do that or if you used reflection. The best way is to just create a getter and setter pair per instance variable:
private int age;
public void setAge(int age) {
this.age = age;
}
public int getAge() {
return age;
}
If you had a map like the following, you could achieve this:
Map<String, Object> properties = new HashMap<>();
public void setInt(String property, int value) {
properties.put(property, value);
}
public int getInt(String property) {
return (int) properties.get(property);
}
// Usage
setInt("age", 25);
int age = getInt("age");

Most efficient way to search list of objects and also increment variable of this object in java

What is the most efficient way to search a list of objects and also increment one of its variables? Also addData() function call 10000 time and in this list have max 30 diff-diff key with increment variable .
Thanks,
public void addData(List<DataWise> wise ,String name)
{
if(wise!=null)
{
for (DataWise dataWise : wise) {
if(dataWise.getName().equals(name))
{
dataWise.setVisits(1);
return;
}
}
}
DataWise dataWise2=new DataWise(name,1);
wise.add(dataWise2);
}
public class DataWise
{
private String name;
private int visits;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getVisits() {
return visits;
}
public void setVisits(int visits) {
this.visits+= visits;
}
}
If it's guarantteed that the name of each DataWise is unique in the list, use a HashMap<String, DataWise>, where the String key is the name of the DataWise. This will lead to O(1) instead of O(n):
Map<String, DataWise> map = new HashMap<String, DataWise>();
...
DataWise wise = map.get(name);
if (wise != null) {
wise.incrementVisits();
}
else {
wise = new DataWise(name, 1);
map.put(name, wise);
}
Note that a setter (setVisits()) should set the visits value to the value of the argument. Incrementing the number of visits is really counter-intuitive. This is why I used an incrementVisits method, which is much clearer.

Searching an object in ArrayList

I am storing objects in ArrayList, where my pojo is as
public class POJOSortableContacts {
private Long id;
private String displayName;
public POJOSortableContacts(Long id, String displayName) {
super();
this.id = id;
this.displayName = displayName;
}
//Setter and Getters
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getDisplayName() {
return displayName;
}
public void setDisplayName(String displayName) {
this.displayName = displayName;
}
//This will be used to sectioned header.
public String getLabel() {
return Character.toString(displayName.charAt(0)).toUpperCase();
}
//Sortable categories
//Sort by Contact name
public static Comparator<POJOSortableContacts> COMPARE_BY_NAME = new Comparator<POJOSortableContacts>() {
public int compare(POJOSortableContacts one, POJOSortableContacts other) {
return one.getDisplayName().compareToIgnoreCase(other.getDisplayName());
//return s1.toLowerCase().compareTo(s2.toLowerCase()); //it returns lower_case word first and then upper_case
}
};
//Sort by id
public static Comparator<POJOSortableContacts> COMPARE_BY_ID = new Comparator<POJOSortableContacts>() {
public int compare(POJOSortableContacts one, POJOSortableContacts other) {
return one.id.compareTo(other.id);
}
};
}
and Arraylist structure is as
ArrayList<POJOSortableContacts> contactArrayList = new ArrayList<POJOSortableContacts>()
, I want to search an object from contactArrayList by id (for example I want an object which id is 20), I want to use binarysearch for this. So how can it will be?
You can use
POJOSortableContacts contact = Collections.binarySearch(contactArrayList,
new POJOSortableContacts(20, ""),
COMPARE_BY_ID);
The new POJOSortableContacts is just a dummy object to act as the key.
Of course, this will only work if your list is sorted by ID to start with - you can't use a binary search on an unsorted list (or on a list which is sorted in a different way).
I will rather suggest that you use a HashMap.
Map<Long,POJOSortableContacts> contactMap = new HashMap<Long,POJOSortableContacts>();
Fill up your contactMap like this:
contactMap.put(myContact.getId(), myContact);
Searching then becomes trivial:
POJOSortableContacts myContact = contactMap.get(myID);
To be able to use binary search, your collection must be sorted. You could sort your ArrayList each time before your search, but that would negate the advantage of using binary search (you could just do a linear search over the unsorted list and still be faster).
ArrayList has a method - BinarySearch, which takes object to search as a parameter.
POJOSortableContacts contactToSearch = new POJOSortableContacts(someId, "Name");
POJOSortableContacts myContact = contactArrayList.BinarySearch(contactToSearch);
Hope this helps.
Sidestepping the question a bit, if you can't have duplicates in the list you'd likely be better served by using a SortedSet to store the contacts. No sorting before using binarySearch anymore...

Collection with multiple values in key

I'm looking for a Collection type data structure to implement the following. Say I have a class like this:
class Person() {
String homeTown; // key
String sex; // key
String eyeColour; // key
String name;
long height;
// other stuff....
}
I am processing multiple Person objects. I want to organise them into sets whereby each set contains Person objects with the same homeTown, sex and eyeColour. At the moment I am implementing something like this:
Map<String, HashSet<Person>> = new HashMap<String, HashSet<Person>>;
where the key is a concatanation of the homeTown, sex and eyeColour. This works but seems a bit untidy - can anyone suggest a more elegant solution or a better data structure to use, thanks?
You could restructure your class to make the key explicit. This is more robust than simply concatenating the key values and avoids any additional object creation overhead at the point when you wish to store your Person instance in a Map, because you've eagerly created the key in advance.
public class Person {
public class Key {
private final String homeTown;
private final String sex;
private final String eyeColour;
public Key(String homeTown, String sex, String eyeColour) { ... }
public boolean equals(Object o) { /* Override to perform deep equals. */ }
public int hashCode() { /* Could pre-compute in advance if the key elements never change. */ }
}
private final Key key;
private final String name;
private final long height;
public Person(String homeTown, String sex, String eyeColour, String name, long height) {
this.key = new Key(homeTown, sex, eyeColour);
this.name = name;
this.height = height;
}
public Key getKey() {
return key;
}
public String getName() { return name; }
public long getHeight() { return height; }
}
Create an object to model your key. For example class PersonKey { String homeTown, sex, eyeColour } (getters and setters omitted for brevity)
Implement the equals and hashCode method for this object.
Use this object as the key in your Map.
Either remove the attributes from your Person object or replace them with a reference to your PersonKey object.
In addition, consider making the type of your map the following i.e. you don't need to specify what type of Set you are using as the key to your map.
Map<String, Set<Person>> = new HashMap<String, Set<Person>>();
And, if you are using a Set<Person> then you'll need to override equals and hashCode for the Person as well, otherwise the Set cannot correctly determine if two Person objects represent the same person or not, which is needed to make sure the collection contains only unique elements.
org.apache.commons.collections.map.MultiValueMap
You can use guava's Sets.filter method to filter the person objects.
Example:
Person class:
public class Person {
String name;
String hometown;
int age;
public Person(String name, String hometown, int age) {
this.name = name;
this.age = age;
this.hometown = hometown;
}
#Override
public int hashCode() {
int hash = 17;
hash = 37 * hash + name.hashCode();
hash = 37 * hash + hometown.hashCode();
hash = 37 * hash + age;
return hash;
}
#Override
public boolean equals(Object obj) {
if (this == obj)
return true;
Person p;
if (obj instanceof Person)
p = (Person) obj;
else
return false;
if (this.name.equals(p.name) && this.hometown.equals(p.hometown)
&& this.age == p.age)
return true;
return false;
}
#Override
public String toString() {
StringBuilder b = new StringBuilder();
b.append("[name = ").append(name).append("\n");
b.append("home town = ").append(hometown).append("\n");
b.append("age = ").append(age).append("]");
return b.toString();
}
}
TestGuavaFilter class:
public class TestGuavaFilter {
public static void main(String[] args) {
Set<Person> set = new HashSet<Person>();
set.add(new Person("emil", "NY", 24));
set.add(new Person("Sam", "NY", 50));
set.add(new Person("george", "LA", 90));
System.out.println(Sets.filter(set, new FilterHomeTown("NY")));
}
}
class FilterHomeTown implements Predicate<Person> {
String home;
public FilterHomeTown(String home) {
this.home = home;
}
#Override
public boolean apply(Person arg0) {
if (arg0.hometown.equals(this.home))
return true;
return false;
}
}
The advantage of using a filter is that you can filter Person object in any way ,suppose you want to filter only using home-town and not the other 2 attributes this will helpful.More over since guava's filter only produces a view of the the real Set,you can save memory.

Categories