So I have this class which reads from 2 files and fills 2 Arraylists
with Contact Objects. Now I want to Merge these Arraylists to a new
Arraylist which then I want to Sort and eliminate duplicates. My
problem is: How do I get the filled Arraylists to another method so I
can do the sorting?
Here is my Code:
import java.util.List;
import java.util.Scanner;
final class Addressbook{
public List<Contact> contacts1 = new ArrayList<Contact>();
public List<Contact> contacts2= new ArrayList<Contact>();
public List<Contact> allcontacts = new ArrayList<Contact>();
public void readContacts1(Scanner scanner1) {
scanner1.useDelimiter(";");
while (scanner1.hasNext()) {
final Contact contact= readContacts1(scanner1);
contacts1.add(Contact);
}
}
public void readContacts2(Scanner scanner2) {
while (scanner2.hasNext()) {
final Contact contact = readContacts2(scanner2);
contacts.add(contact);
}
}
public int ContactSearch1(Contact c) {
for (int i = 0; i < contacts1.size(); i++)
if (contacts1.get(i).equals(c))
return i;
return -1;
}
public int ContactSearch2(Contact c) {
for (int i = 0; i < contacts2.size(); i++)
if (contacts2.get(i).equals(c))
return i;
return -1;
}
private static Contact readContact1(Scanner scanner1) {
scanner1.useDelimiter(";");
final String name= scanner1.next();
final String lastname = scanner1.next();
final String address = scanner1.next();
final String number = scanner1.next();
final Contact contact= new Contact(name, lastname, address, number);
return contact;
}
private static Contact ReadContact2(Scanner scanner2) {
scanner2.useDelimiter(";");
final String name= scanner2.next();
final String lastname = scanner2.next();
final String address = scanner2.next();
final String number = scanner2.next();
final Contact contact= new Contact(name, lastname, address, number);
return contact;
}
}
First, the provided code contains a lot of duplicated parts which may easily be encapsulated in a separate helper class which takes care of reading and searching the lists.
final class Addressbook{
private List<Contact> contacts1;
private List<Contact> contacts2;
private List<Contact> allContacts;
private static class ContactHelper {
public static List<Contact> readContacts(Scanner scanner) {
// scanner.setDelimiter(";"); // it's better to set this parameter in the call
List<Contact> result = new ArrayList<>();
boolean hasData = scanner.hasNext();
while (hasData) {
final String name= scanner.next();
final String lastname = (hasData &= scanner.hasNext()) ? scanner.next() : "NO_LAST_NAME";
final String address = (hasData &= scanner.hasNext()) ? scanner.next() : "NO_ADDRESS";
final String number = (hasData &= scanner.hasNext()) ? scanner.next() : "NO_NUMBER";
result.add(new Contact(name, lastname, address, number));
hasData = scanner.hasNext();
}
return result;
}
public static int indexOfContact(Contact contact, List<Contact> list) {
Objects.requireNonNull(contact);
Objects.requireNonNull(list);
for (int i = 0, n = list.size(); i < n; i++) {
if (contact.equals(list.get(i))) {
return i;
}
}
return -1;
}
}
}
Then appropriate methods to set fields contacts1, contacts2 should use the helper's methods:
// class AddressBook
public void readContacts1(Scanner scanner) {
contacts1 = ContactHelper.readContacts(scanner);
}
public void readContacts2(Scanner scanner) {
contacts2 = ContactHelper.readContacts(scanner);
}
A method to join the lists, sort them, and remove the duplicates can be implemented using TreeSet if class Contact implements interface Comparable required for sorting the contacts in their natural order, otherwise custom comparator must be provided.
// another helper method
public static List<Contact> joinContacts(List<Contact> ... contactLists) {
Set<Contact> sortedWithoutDups = new TreeSet<>();
for (List<Contact> list : contactLists) {
if (null != list) {
sortedWithoutDups.addAll(list);
}
}
return new ArrayList<>(sortedWithoutDups);
}
// setting allContacts
public void joinContacts() {
allContacts = AddressBook.joinContacts(contacts1, contacts2);
}
This task can be resolved using Stream API (allowing for joining more than 2 lists any of which may be null):
// AddressBook
public void joinContacts() {
allContacts = ContactHelper.joinContactLists(contacts1, contacts2);
}
// ContactHelper
public static List<Contact> joinContactLists(List<Contact> ... lists) {
return Arrays.stream(lists) // Stream<List<Contact>>
.filter(Objects::nonNull) // filter out null lists
.flatMap(List::stream) // convert to Stream<Contact>
.sorted() // sort
.distinct() // _and then_ remove duplicates
.collect(Collectors.toList());
}
contacts1.addAll(contacts2);
contacts1.sort((o1, o2) -> o1 < o2 ? o1 : o2);
contacts1.addAll(contacts2)
This adds all contacts2 to contacts1 and contacts1 List will have all the contacts.
Here u can replace o1 < o2 can be replaced with the logic u need to sort.
The easiest way to ensure, that you do not have duplicates in your ArrayList is to copy your list into a Collection that does not allow duplicates (for example a set) and then copy it back into the ArrayList you need. I would recommend to check out this post for this:
Answers to Question: I have an ArrayList, and I want to remove repeated strings from it. How can I do this?
Ultimately your problem could be answered the following way (using the code of mentioned blog post):
allcontacts.addAll(contacts1);
allcontacts.addAll(contacts2);
Set<Contact> set = new HashSet<>(allcontacts);
allcontacts.clear();
allcontacts.addAll(set);
Now you got rid of all duplicates and merged the ArrayLists contacts1 and contacts2 into allcontacts.
You now only have to sort allcontacts, which can be done like this (if Contact implements Comparable):
Collections.sort(allcontacts);
Related
i have two lists (personList From DB and inputPersonList from UI).
I want to make sure each row in personList find (matches) corresponding row in inputPersonList according to id(without sort)
Person person1=new Person();
Person person2=new Person();
Person person1=new Person();
List<Person> personList=new ArrayList();
List<Person> inputPersonList=new ArrayList();
person1.Id(1);
person1.setName("A");
person1.setFamily("B");
person2.Id(2);
person2.setName("C");
person2.setFamily("D");
person3.Id(3);
person3.setName("E");
person3.setFamily("F");
personList.add(person1);
personList.add(person2);
personList.add(person3);
inputPersonList.add(person1);
inputPersonList.add(person3);
inputPersonList.add(person2);
Assuming your list contains a custom Object. If so just overwrite the compareTo method in your custom Object and then iterate through the List, checking each corresponding element.
For example:
Here is a custom Book object that implements Comparable:
public class Book implements Comparable {
String isbn;
String title;
public Book(String id, String title) {
this.isbn = id;
this.title = title;
}
String getIsbn() {
return isbn;
}
String getTitle() {
return title;
}
#Override
public int compareTo(Object o) {
return Comparator
.comparing(Book::getIsbn)
.thenComparing(Book::getTitle)
.compare(this, (Book) o);
}
#Override
public String toString() {
String output = new StringBuilder()
.append(isbn).append(":").append(title)
.toString();
return output;
}
}
The following creates two lists (to represent the DB list and the UI lists) and then compares them based on position in the list (namely "corresponding row"):
public void CompareTwoLists(){
List<Book> libraryUI = new ArrayList<>();
libraryUI.add(new Book("9780593098240", "Children of Dune"));
libraryUI.add(new Book("9780593098233", "Dune Messiah"));
libraryUI.add(new Book("9780441172719", "Dune"));
List<Book> libraryDB = new ArrayList<>();
libraryDB.add(new Book("9780593098240", "Children of Dune"));
libraryDB.add(new Book("9780593098233", "Dune Messiah"));
libraryDB.add(new Book("9788886845687", "God Emperor of Dune"));
boolean theSame = Boolean.TRUE;
if(libraryDB.size() != libraryUI.size()) {
theSame = Boolean.FALSE;
} else {
for(int i = 0; i < libraryDB.size(); i++) {
if (libraryDB.get(i).compareTo(libraryUI.get(i)) != 0) {
theSame = Boolean.FALSE;
break;
}
}
}
if(theSame) {
System.out.println("The same");
} else {
System.out.println("Not the same");
}
}
What you can do is check if each of the two lists contains all the elements of the other list and their size is equal:
public static void main(String[] args) throws ParseException {
Person person1 = new Person();
Person person2 = new Person();
Person person3 = new Person();
List<Person> personList = new ArrayList<>();
List<Person> inputPersonList = new ArrayList<>();
person1.Id(1);
person1.setName("A");
person1.setFamily("B");
person2.Id(2);
person2.setName("C");
person2.setFamily("D");
person3.Id(3);
person3.setName("E");
person3.setFamily("F");
personList.add(person1);
personList.add(person2);
personList.add(person3);
inputPersonList.add(person1);
inputPersonList.add(person3);
inputPersonList.add(person2);
// compare the lists using the built-in "equals()" method, which considers order of elements
System.out.println(personList.equals(inputPersonList) ?
"equal (considering order)" : "not equal (considering order)");
// then compare them with the other possibility
System.out.println(areEqual(personList, inputPersonList) ?
"equal (without considering order)" : "not equal (without considering order)");
}
public static boolean areEqual(List<Person> persons, List<Person> personsToo) {
if (persons.containsAll(personsToo) && personsToo.containsAll(persons)
&& persons.size() == personsToo.size()) {
return true;
} else {
return false;
}
}
Keep in mind that this does not consider the case of duplicate elements correctly, because it only checks if an element is present in both lists, not if their count in the lists is equal. You could add person1 a second time to personList and person3 a second time to imputPersonList and the result would still be true respectively equality.
As says Ambro-r you need use the Comparable interface but if you don't have access to the Entity, you should extends Book Class.
public class MyBook extends Book implements Comparable {
#Override
public int compareTo(Object o) {
//compare with other book with the attributes what you want maybe could:
return this.isbn > ((MyBook) o).isbn
}
#Override
public String toString() {
//return super.toString() or your own toString
}
Then you should create lists of MyBook objects.
I have the following loop in a controller class:
for (int i = 0; i <= locationArr.length - 1; i++) {
data.put(idArr[i], locationArr[i]);
locationBean.setLocation_name(locationArr[i]);
}
My Bean looks like :
public class LocationBean {
private String region_id;
private String region_name;
private String location_id;
private String location_name;
//getters and setters
}
I am trying to set location_name as setLocation_name(locationArr[i]);
But only getting last values of the loop [i] is being assigned.
If you like to have multiple location names you can do that by e.g. a List or more general any Collection if order does not matter.
Here an example:
public class LocationBean {
private String region_id;
private String region_name;
private String location_id;
private List<String> locationNames = new ArrayList<>();
//getters and setters
public List<String> getLocationNames() {
return locationNames;
}
}
usage in your loop:
locationBean.getLocationNames().add(locationArr[i]);
I did not refactor all your example code to be complient to the java naming convention. You should name your variables in camel case.
Either u can create a list of LocationBean objects :
ArrayList <LocationBean> locationBeanList = new ArrayList <LocationBean>)();
for (int i = 0; i <= locationArr.length - 1; i++) {
data.put(idArr[i], locationArr[i]);
locationBean = new LocationBean();
locationBean.setLocation_name(locationArr[i]);
locationBeanList.add(locationBean);
}
Or, u can create list of locations in single location bean
public class LocationBean {
private String region_id;
private String region_name;
private String location_id;
private List<String> location_name_list = new ArrayList<String>();
//getters and setters
}
List<String> locationList = new ArrayList <String>();
for (int i = 0; i <= locationArr.length - 1; i++) {
data.put(idArr[i], locationArr[i]);
locationList.add(locationArr[i]);
}
locationBean.setLocation_name_list(locationList );
LocationBean with a List
You want to store every location name, not set ONE value. So you want a method addLocationName store it into a Collection
locationBean.addLocationName(locationArr[i]);
That method is simple, it will add every String into a List<String>
private List<String> locationsName;
private List<String> locationsId;
public LocationBean (){
locationsName = new ArrayList<String>();
locationsId= new ArrayList<String>();
}
public boolean addLocationName(string locationName){
return this.locationsName.add(locationName);
}
public boolean addLocationId(string locationId){
return this.locationsId.add(locationId);
}
Of course, you would need to do the same with location_id, so a Bean would be smarter :
public class Location{
private String id;
private String name;
public Location(String id, String name){ ... }
//constructor and getter
}
and simply use a List<Location> instead. That way, both id and name are stored together.
public boolean addLocation(Location location){
return this.locations.add(location);
}
or passing the values
public boolean addLocation(String id, String name){
return this.locations.add(new Location(id, name));
}
List of LocationBean
Or your bean should only have one location and then this is in your loop that you need to store every instance of LocationBean into a List<LocationBean> (don't forget to create a new instance each time`
List<LocationBean> locations = new ArrayList<>();
for (int i = 0; i <= locationArr.length - 1; i++) {
locationBean = new LocationBean(); //new instance each time
locationBean.setLocation_name(locationArr[i]);
locations.add(locationBean); //add into the list
}
I have four ArrayLists. I want to sort one of them alphabetically with case ignored and do the same changes in the other three ArrayLists.
ArrayList<String> arrPackage = new ArrayList<>();
ArrayList<String> arrPackageDates = new ArrayList<>();
ArrayList<String> arrPackageDuration = new ArrayList<>();
ArrayList<String> arrPackageFileSize = new ArrayList<>();
// Code to add data to ArrayLists (data is not coming from sqlite database)
...
// Code to sort arrPackage alphabatically with case ignored
Collections.sort(arrPackage, new Comparator<String>() {
#Override
public int compare(String s1, String s2) {
return s1.compareToIgnoreCase(s2);
}
});
but how do I know which indexes were changed?
One approach would be to create a wrapper object Package which contains the four types of metadata which appears in the four current lists. Something like this:
public class Package {
private String name;
private String date;
private String duration;
private String fileSize;
public Package() {
// can include other constructors as well
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
// other getters and setters
}
Then sort using a custom comparator which works on Package objects:
List<Package> packages = new ArrayList<>();
Collections.sort(packages, new Comparator<Package>() {
#Override
public int compare(Package p1, Package p2) {
String name1 = p1.getName();
String name2 = p2.getName();
return name1.compareToIgnoreCase(name2);
}
});
As a general disclaimer, the above operation would most likely be performed must more efficiently in a database. So if your data is ultimately coming from a database, you should try to do such heavy lifting there.
A simple easy way would be backing up your ArrayList.
ArrayList<String> backupPackage = arrPackage;
And then use your code to sort the array. Then use a for loop to compare the two arrays.
for (int i = 0; i < backupArray.size(); i++) {
if (!aar.get(i).equals(aar.get(i))) { // then the item has been changed
// ... YOUR CODE
// at this point you know which indexes have been changed and can modify your other arrays in any way you need
}
}
I used this approach:
ArrayList<String> backupPackage = new ArrayList<>();
ArrayList<String> backupPackageDates = new ArrayList<>();
ArrayList<String> backupPackageDuration = new ArrayList<>();
ArrayList<String> backupPackageFileSize = new ArrayList<>();
for(int j=0;j<arrPackage.size();j++) {
backupPackage.add(arrPackage.get(j));
}
for(int j=0;j<arrPackageDates.size();j++) {
backupPackageDates.add(arrPackageDates.get(j));
}
for(int j=0;j<arrPackageDuration.size();j++) {
backupPackageDuration.add(arrPackageDuration.get(j));
}
for(int j=0;j<arrPackageFileSize.size();j++) {
backupPackageFileSize.add(arrPackageFileSize.get(j));
}
Collections.sort(arrPackage, new Comparator<String>() {
#Override
public int compare(String s1, String s2) {
return s1.compareToIgnoreCase(s2);
}
});
int newindex;
for(int i=0; i<backupPackage.size(); i++) {
newindex = backupPackage.indexOf(arrPackage.get(i));
if(newindex != i) {
arrPackageDates.set(i, backupPackageDates.get(newindex));
arrPackageDuration.set(i, backupPackageDuration.get(newindex));
arrPackageFileSize.set(i, backupPackageFileSize.get(newindex));
}
}
backupPackage.clear();
backupPackageDuration.clear();
backupPackageDuration.clear();
backupPackageFileSize.clear();
how to save arraylist after the app is closed.
This is my global class
public class GlobalClass extends Application {
ArrayList<Trip> allTrips = new ArrayList<>();
public ArrayList<String> allTripsString() {
ArrayList<String> allTripsString = new ArrayList<String>();
for (Trip trip : allTrips){
allTripsString.add(trip.getName());
}
return allTripsString;
}
}
This is my trip class
public class Trip {
/** A map with category as key and the associed list of items as value */
Map<String,List<Item>> expanses;
private String name;
public ArrayList<String> ExpensesCategory = new ArrayList<>();
public ArrayList<String> Adults = new ArrayList<>();
public ArrayList<String> Children = new ArrayList<>();
public ArrayList<String> ShoppingName = new ArrayList<>();
public ArrayList<Double> ShoppingPrice = new ArrayList<>();
public ArrayList<String> ShoppingCategory = new ArrayList<>();
public double budget = 0;
/** An item in the expanses list */
static class Item {
final String name;
final double cost;
final String Category;
public Item(String name, double cost, String Category) {
this.name = name;
this.cost = cost;
this.Category = Category;
}
#Override public String toString() {
return this.name + " (" + this.cost + "$)";
}
public String getName(){
return name;
}
public String getCategory(){
return Category;
}
public double getCost(){
return cost;
}
}
public Trip(String name) {
this.name = name;
this.expanses = new HashMap<String,List<Item>>();
for (String cat: ExpensesCategory) { // init the categories with empty lists
this.expanses.put(cat, new ArrayList<Item>());
}
}
public String getName(){
return name;
}
/** Register a new expanse to the trip. */
public void add(String item, double cost, String category) {
List<Item> list = this.expanses.get(category);
if (list == null)
throw new IllegalArgumentException("Category '"+category+"' does not exist.");
list.add( new Item(item, cost, category) );
}
/** Get the expanses, given a category.
* #return a fresh ArrayList containing the category elements, or null if the category does not exists
*/
public List<Item> getItems(String category) {
List<Item> list = this.expanses.get(category);
if (list == null)
return null;
return new ArrayList<Item>(list);
}
/** Get the expanses, given a category.
* #return a fresh ArrayList containing all the elements
*/
public List<Item> getItems() {
List<Item> list = new ArrayList<Item>();
for (List<Item> l: this.expanses.values()) // fill with each category items
list.addAll(l);
return list;
}
public ArrayList<String> getItemsString() {
List<Item> list = new ArrayList<Item>();
for (List<Item> l: this.expanses.values()) // fill with each category items
list.addAll(l);
ArrayList<String> listString = new ArrayList<String>();
for (Item item : list){
listString.add(item.getName());
}
return listString;
}
public ArrayList<Double> getItemsCost(){
List<Item> list = new ArrayList<Item>();
for (List<Item> l: this.expanses.values()) // fill with each category items
list.addAll(l);
ArrayList<Double> listDouble = new ArrayList<>();
for (Item item : list){
listDouble.add(item.getCost());
}
return listDouble;
}
public ArrayList<String> getItemsCategory() {
List<Item> list = new ArrayList<Item>();
for (List<Item> l: this.expanses.values()) // fill with each category items
list.addAll(l);
ArrayList<String> listString = new ArrayList<String>();
for (Item item : list){
listString.add(item.getCategory());
}
return listString;
}
/** Get the total cost, given a category. */
public double getCost(String category) {
List<Item> list = this.expanses.get(category);
if (list == null)
return -1;
double cost = 0;
for (Item item: list)
cost += item.cost;
return cost;
}
/** Get the total cost. */
public double getCost() {
double cost = 0;
for (List<Item> l: this.expanses.values())
for (Item item: l)
cost += item.cost;
cost *= 1000;
cost = (int)(cost);
cost /= 1000;
return cost;
}
}
I want to save the array list and when I close and open the app the array list (alltrips) is saved. How to do this?
I want to use shared preferences but I don't know how to do this because it is not a string it array list with Trip. Can anyone help me to save the arraylist in shared preferences?
SharedPreferences allows you to save a Set of Strings, so your best scenario is to convert every object into a String and then save this collection of String into sharedpreferences, and then when needed you can rebuild the objects from these Strings.
Or you can save it in file system or DB, but SharedPreferences is lighter and easier if all you want is this. Either way you will need to construct/deconstruct the saved content of your list.
//Retrieve the values
Set<String> set = myScores.getStringSet("key", null);
//Set the values
Set<String> set = new HashSet<String>();
set.addAll(listOfExistingScores);
scoreEditor.putStringSet("key", set);
scoreEditor.commit();
EDIT
simple example
public void saveToSharedPreferences(Context context, List<String> list){
Set<String> set =
list.stream()
.collect(Collectors.toSet()); // Returns in this case a Set, if you need Iterable or Collection it is also available.
PreferenceManager.getDefaultSharedPreferences(context) // Get Default preferences, you could use other.
.edit()
.putStringSet("myKey", set) // Save the Set of Strings (all trips but as Strings) with the key "myKey", this key is up to you.
.apply(); // When possible commit the changes to SharePreferences.
}
public void saveToSharedPreferences(Context context, List<Trip> list){
List<String> stringList = list.stream()
.map(Trip::getName) // This uses this method to transform a Trip into a String
// you could use other method to transform into String but if all you need to save is the name this suffices
// examples: .map( trip -> trip.getName()), .map(trip -> trip.toString()), etc. you choose how to save.
// It should save every state that a Trip has, so when you are reading the saved Strings
// you will be able to reconstruct a Trip with its state from each String.
.collect(Collectors.toList());
saveToSharedPreferences(context, stringList);
}
NOTE i did not test this but it should be ok (currently i do not have Android Studio so there might be some little errors, but from this solution you should be able to finish this. If needed i could give you the complete solution working. As of now i do not have access to my IDE and WorkStation.
I think the most easiest way to so this is you can save your data in SharedPrefences and populate your arraylist from the sharedPrefernces. As sharedPrefernces only store primitive types you can use Gson for converting your object into String and then store that in the sharedPrefrence. Hope that helps!.
You need to save your data into the database or you can follow this Stackoverflow question
Question
You can save serialized object and read them by using those methods :
public static boolean writeObjectInCache(Context context, String key, Object object) {
try {
FileOutputStream fos = context.openFileOutput(key, Context.MODE_PRIVATE);
ObjectOutputStream oos = new ObjectOutputStream(fos);
oos.writeObject(object);
oos.close();
fos.close();
} catch (IOException ex) {
return false;
}
return true;
}
public static Object readObjectFromCache(Context context, String key) {
try {
FileInputStream fis = context.openFileInput(key);
ObjectInputStream ois = new ObjectInputStream(fis);
Object object = ois.readObject();
return object;
} catch (Exception ex) {
return null;
}
}
To read the list , you should cast the Object by your type :
ArrayList<TypeOfYourObject> list = new ArrayList<>();
list = (ArrayList<TypeOfYourObject>) readObjectFromCache(context, CACHE_KEY);
Don't forget to add those permission in your manifest :
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /> <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
I dont think there is lifecyle method which will be called in production mode . the user just moves out of the activity page . you should probably do whatever you want in onPause method .
I have two array list. Each has list of Objects of type User.
The User class looks like below
public class User {
private long id;
private String empCode;
private String firstname;
private String lastname;
private String email;
public User( String firstname, String lastname, String empCode, String email) {
super();
this.empCode = empCode;
this.firstname = firstname;
this.lastname = lastname;
this.email = email;
}
// getters and setters
}
import java.util.ArrayList;
import java.util.List;
public class FindSimilarUsersWithAtLeastOneDifferentProperty {
/**
* #param args
*/
public static void main(String[] args) {
// TODO Auto-generated method stub
List<User> list1 = new ArrayList<User>();
list1.add(new User("F11", "L1", "EMP01", "u1#test.com"));
list1.add(new User("F2", "L2", "EMP02", "u222#test.com"));
list1.add(new User("F3", "L3", "EMP03", "u3#test.com"));
list1.add(new User("F4", "L4", "EMP04", "u4#test.com"));
list1.add(new User("F5", "L5", "EMP05", "u5#test.com"));
list1.add(new User("F9", "L9", "EMP09", "u9#test.com"));
list1.add(new User("F10", "L10", "EMP10", "u10#test.com"));
List<User> list2 = new ArrayList<User>();
list2.add(new User("F1", "L1", "EMP01", "u1#test.com"));
list2.add(new User("F2", "L2", "EMP02", "u2#test.com"));
list2.add(new User("F6", "L6", "EMP06", "u6#test.com"));
list2.add(new User("F7", "L7", "EMP07", "u7#test.com"));
list2.add(new User("F8", "L8", "EMP08", "u8#test.com"));
list2.add(new User("F9", "L9", "EMP09", "u9#test.com"));
list2.add(new User("F100", "L100", "EMP10", "u100#test.com"));
List<User> resultList = new ArrayList<User>();
// this list should contain following users
// EMP01 (common in both list but differs in firstname)
// EMP02 (common in both list but differs in email)
// EMP10 (common in both list but differs in firstname, lastname and email)
}
}
If you see the sample code, the two lists have four users with emp code EMP01, EMP02, EMP09 and EMP10 common.
So, we only need to compare the properties of these four users.
If any of the users have at least one different property it should be added in the result list.
Please advise on how do I go about this?
Implement equals, hashcode in User
#Override
public boolean equals(Object obj) {
if (obj == null)
return false;
if (!(obj instanceof User))
return false;
User u = (User) obj;
return this.empCode == null ? false : this.empCode
.equals(u.empCode);
}
#Override
public int hashCode() {
return this.empCode == null ? 0 : this.empCode.hashCode();
}
#Override
public String toString() {
return "Emp Code: " + this.empCode;
}
Then use retainAll
list2.retainAll(list1);-->EMP01, EMP02, EMP09, EMP10
I think this what you should do -
for(User user1 : list1) {
for(User user2 : list2) {
if(user1.getEmpCode().equals(user2.getEmpCode())) {
if(!user1.getFirstName().equals(user2.getFirstName()) ||
!user1.getLastName().equals(user2.getLastName()) ||
!user1.getEmail().equals(user2.getEmail())) {
resultList.add(user1);
}
}
}
}
It might not make sense for the User to override equal and hashCode only to serve this purpose. They should be overriden in the way in which it makes more sense domain-wise.
This is simple. Override equal method in your User class. One very simple implementation(you can enhance it by using null checks etc) can be like below:
#override
public boolean equals(Object obj) {
User other = (User) obj;
if(this.id==other.id
&& this.empCode.equals(other.empCode)
&& this.firstname.equals(other.firstname)
&& this.lastname.equals(other.lastname)
&& this.email.equals(other.email)){
return true;
}else{
return false;
}
}
Once done, you can use:
for(user user: list1){
if(!resultList.contains(user)){
resultList.add(user);
}
}
for(user user: list2){
if(!resultList.contains(user)){
resultList.add(user);
}
}
The canonical approach is as follows:
Write a method countDifferences that counts the number of differences between users
For each object in one list, find the minimum when compared to the other lists objects
Report all objects where the minimum is not 0.
If you put weights on the different properties you can also control that e.g. a match in the ID attribute is stronger than a match in the name.
Update: sorry, misread your comment that the ID attribute must match.
Replace 2) with "find object which has the same ID". Other than that, I still recommend counting the number of differences. It is more flexible, as you can define thresholds for good or bad matches etc.
Add this method to your User class:
public boolean isSimilarButNotEqual(User other) {
if(!this.empCode.equals(other.empCode))
return false;
return !(this.firstname + this.lastname + this.email).equals(other.firstname + other.lastname + other.email);
}
Then, in the main() do:
for(User user1: list1){
for(User user2: list2){
if(user1.isSimilarButNotEqual(user2)){
resultList.add(user1);
resultList.add(user2);
}
}
}
I have used the following way to compare two custom ArrayList.
List<SinglePostData> allPosts = new ArrayList<>();
List<SinglePostData> noRepeatAllPosts = new ArrayList<>();
for (int i = 0; i < allPosts.size(); i++) {
boolean isFound = false;
for (int j = i+1; j < allPosts.size(); j++) {
if (allPosts.get(i).getTitle().equals(allPosts.get(j).getTitle())) {
isFound = true;
break;
}
}
if (!isFound) noRepeatAllPosts.add(allPosts.get(i));
}