Split string to list of objects - java

I have a String like below with three or four values seperated by |||, so when split on ||| it can give three string single pipe seperated or four strings pipe seperated
james|12343|ascxZCCVVsss|||Alex|341234|asdasdUsadf|21444|||.....
I wanted to create a list of Person objects
class Person {
String name;
String id;
String accessCode;
String optionalID;
// Getters and setters left out for brevity
}
Also I have a builder class to build it.
public String getParsed(String str) throws JsonProcessingException {
String[] strSplit = str.split(Pattern.quote("|||"));
List<Person> perList = new ArrayList<>();
Arrays.stream(strSplit).forEach(item -> {
String[] val = item.split(Pattern.quote("|"));
if (val.length >= 2) {
perList.add(PersonBuilder.asPerson()
.withName(val[0])
.withId(val[1])
.withAccessCode(val[3])
.withOptionalId(val.length > 2 ? val[3] : StringUtils.EMPTY)
.build());
}
});
if (!CollectionUtils.isEmpty(perList)) {
return mapper.writeValueAsString(perList);
}
return StringUtils.EMPTY;
}
This code works. but Im wondering if there is a better way of doing this using Java 8. Also using index reference is a scary thing for me :)

Some cosmetic change is possible to replace {...} block with shorter map / filter stream methods instead of forEach:
public String getParsed(String str) throws JsonProcessingException {
List<Person> perList = Arrays.stream(str.split(Pattern.quote("|||")))
.map(item -> item.split(Pattern.quote("|"))) // Stream<String[]>
.filter(val -> val.length >= 3)
.map(val -> PersonBuilder.asPerson()
.withName(val[0])
.withId(val[1])
.withAccessCode(val[2])
.withOptionalId(val.length > 3 ? val[3] : StringUtils.EMPTY)
.build()
)
.collect(Collectors.toList());
return perList.isEmpty()
? StringUtils.EMPTY
: mapper.writeValueAsString(perList);
}
However, if a valid JSON String should be returned from this method, it may be better to return mapper.writeValueAsString(perList); which supplies "[]" for an empty list instead of "".

I think your solution is pretty well. I just can only offer to make it a bit more efficient: not using streams and process the given String only once:
public static List<Person> getPersons(String str) {
List<Person> persons = new ArrayList<>();
Queue<String> queue = new LinkedList<>();
int fromIndex = 0;
while (true) {
int index = str.indexOf('|', fromIndex);
if (index < 0)
queue.add(str.substring(fromIndex));
else if (index != fromIndex)
queue.add(str.substring(fromIndex, index));
if (index < 0 || index == fromIndex) {
String name = queue.remove();
String id = queue.remove();
String accessCode = queue.remove();
String optionalID = queue.isEmpty() ? StringUtils.EMPTY : queue.remove();
persons.add(new Person(name, id, accessCode, optionalID));
if (index < 0)
break;
index++;
}
fromIndex = index + 1;
}
return persons;
}
P.S. Below is a bit complicated alternative solution, but it looks like OOP style. It uses custom Iterator to find Person in the given String.
public final class Person {
private final String name;
private final String id;
private final String accessCode;
private final String optionalId;
public static Builder builder() {
return new Builder();
}
private Person(Builder builder) {
name = builder.name;
id = builder.id;
accessCode = builder.accessCode;
optionalId = builder.optionalId;
}
public static final class Builder {
private String name;
private String id;
private String accessCode;
private String optionalId = StringUtils.EMPTY;
public Person build() {
return new Person(this);
}
public Builder setName(String name) {
this.name = name;
return this;
}
public Builder setId(String id) {
this.id = id;
return this;
}
public Builder setAccessCode(String accessCode) {
this.accessCode = accessCode;
return this;
}
public Builder setOptionalId(String optionalId) {
this.optionalId = optionalId;
return this;
}
}
#Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
", id='" + id + '\'' +
", accessCode='" + accessCode + '\'' +
", optionalID='" + id + '\'' +
'}';
}
}
public final class PersonStream {
public static Stream<Person> createFrom(String str) {
return StreamSupport.stream(Spliterators.spliteratorUnknownSize(
new PersonIterator(str), Spliterator.ORDERED), false);
}
private PersonStream() {
}
private static final class PersonIterator implements Iterator<Person> {
private final String str;
private Person person;
private int fromIndex;
public PersonIterator(String str) {
this.str = str;
}
#Override
public boolean hasNext() {
return person != null || fromIndex >= 0;
}
#Override
public Person next() {
if (!hasNext())
throw new NoSuchElementException();
if (person == null) {
String name = readNextPart();
String id = readNextPart();
String accessCode = readNextPart();
String optionalId = readNextPart();
person = Person.builder()
.setName(name)
.setId(id)
.setAccessCode(accessCode)
.setOptionalId(optionalId)
.build();
if (fromIndex >= 0)
fromIndex += optionalId == null ? 1 : 2;
}
try {
return person;
} finally {
person = null;
}
}
private String readNextPart() {
int index = str.indexOf('|', fromIndex);
if (index == fromIndex) {
fromIndex++;
return null;
}
try {
return index < 0 ? str.substring(fromIndex)
: str.substring(fromIndex, index);
} finally {
fromIndex = index < 0 ? -1 : index + 1;
}
}
}
}
As result, the Demo will be very simple:
public static void main(String... args) {
String str = "james|12343|ascxZCCVVsss|||Alex|341234|asdasdUsadf|21444";
PersonStream.createFrom(str).forEach(System.out::println);
}

You said you wanted to Build a list of Person objects but your method is returning a String. Perhaps I am either oversimplifying or not understanding what you want. But here is what I came up with. For this demo, I am using a Person record which is basically an immutable class.
record Person(
String getName,
String getId,
String getAccessCode,
String getOptionalID) {}
String s =
"james|12343|ascxZCCVVsss|||Alex|341234|asdasdUsadf|21444";
List<Person> list = Arrays.stream(s.split("\\Q|||\\E"))
.map(r->r.split("\\|"))
.filter(arr->arr.length >= 3)
.map(v->new Person(v[0], v[1], v[2], v.length == 4 ? v[3] : ""))
.toList();
list.forEach(System.out::println);
Prints
Person[getName=james, getId=12343, getAccessCode=ascxZCCVVsss, getOptionalID=]
Person[getName=Alex, getId=341234, getAccessCode=asdasdUsadf, getOptionalID=2144
4]

Related

ArrayList occurance of object type

I have a class of orders and I want to see how many times a unique customerNumber will get mapped to a status reading "On Hold"
public class Orders {
private String status = null;
private int customerNumber = 0;
public Orders(String status, int customerNumber) {
super();
this.status = status;
this.customerNumber = customerNumber;
}
}
public int NumberOfOrdersOnHold(List<Orders> orders) {
int sum = 0;
for (Orders o : orders) {
if(o.getStatus().contentEquals("On Hold"));
}
}
I was thinking a counter method would work but it wouldnt. how will i achieve this method.I need numbers of orders in hold for each customerNumber not the total number.
Do it as follows:
import java.util.List;
enum OrderStatus {
ONHOLD("On Hold"), APPROVED("Approved"), DELIVERED("Delivered");
private final String statusCode;
private OrderStatus(String statusCode) {
this.statusCode = statusCode;
}
}
class Order {
private OrderStatus status = null;
private int customerNumber = 0;
public Order(OrderStatus status, int customerNumber) {
this.status = status;
this.customerNumber = customerNumber;
}
public OrderStatus getStatus() {
return status;
}
public void setStatus(OrderStatus status) {
this.status = status;
}
public int getCustomerNumber() {
return customerNumber;
}
public void setCustomerNumber(int customerNumber) {
this.customerNumber = customerNumber;
}
#Override
public String toString() {
return "Order [status=" + status + ", customerNumber=" + customerNumber + "]";
}
}
public class Main {
public static void main(String[] args) {
List<Order> orders = List.of(new Order(OrderStatus.ONHOLD, 1234), new Order(OrderStatus.APPROVED, 1234),
new Order(OrderStatus.ONHOLD, 2345), new Order(OrderStatus.APPROVED, 1234),
new Order(OrderStatus.ONHOLD, 1234), new Order(OrderStatus.ONHOLD, 2345));
System.out.println("Customer#1234 has " + numberOfOrdersOnHold(orders, 1234) + " order(s) on hold");
}
static int numberOfOrdersOnHold(List<Order> orders, int customerNumber) {
int count = 0;
for (Order order : orders) {
if (order.getCustomerNumber() == customerNumber && order.getStatus() == OrderStatus.ONHOLD) {
count++;
}
}
return count;
}
}
Output:
Customer#1234 has 2 order(s) on hold
Notes:
Use enum for status values as it makes easy for you to write and maintain the code. Check this to learn more about Java enum.
Follow Java naming conventions e.g. NumberOfOrdersOnHold should be named as numberOfOrdersOnHold.
The function, numberOfOrdersOnHold also requires the customer number whose order status has to be found.
You can use a Map! Try something like this:
public Map<Integer, Integer> numberOfOrdersOnHold(List<Orders> orders) {
final Map<Integer, Integer> map = new HashMap<>();
for (Orders o : orders) {
int currentNumber = o.getCustomerNumber();
// if map doesn't contain the key to the corresponding customer, were gonna add it
if (!map.containsKey(currentNumber)) {
map.put(currentNumber, 0);
}
// if the status is "On hold", increment the counter to the current customer
if ("On hold".equals(o.getStatus())) {
map.put(currentNumber, map.get(currentNumber) + 1);
}
}
return map;
}

How to Implement Binary Search Manually In My Own ADT [ JAVA ]

Alright I am stuck on how do I implement this binary search that will receive data from other classes.
I am trying to implement it in my own ADT.
I have implemented a List ADT manually but now I want to add in a search operation which utilizes binary search algorithm manually and doesn't uses any built in Java API.
Example this is my sorted list interface that I implemented manually.
public class SortedArrayList<T extends Comparable<T>> implements SortedListInterface<T>{
private boolean binarySearch(// What parameters should I receive from Student Object?) {
// This will be my binary search implementation
}
}
The problem is I will be creating a Student class where I will add the instances of the student class into the sortedArrayList above.
Like how am I going to receive the data to be put into the binary search algorithm in a generics typed sortedArrayList?
Do note I am not allowed to use any JAVA Built-IN API , everything must be implemented manually else I can finish this easily but its a pain now since its limited.
Example I want to binary search by Student name from Student's class. How will I need to implement and receive data into this manually implemented ADT of mine?
public class SortedArrayList<T extends Comparable<T>> implements SortedListInterface<T>{
private T[] list;
private boolean binarySearch(int first, int last, T desiredItem) {
int mid = (first + last) / 2;
if(desiredItem.getFullName().equals(list[mid])
// This part over here. How do I access attributes from Student class in this ADT so that I can access the data and do comparison for the binary search..
}
}
How do I access attributes from Student class into my own ADT so that I can do comparisons on binary search algorithm?!
I am literally stuck.
I would appreciate someone giving me directions.
I repeat again no BUILT-IN APIs from JAVA, implementation manually only
ADT SortedList Interface
public interface SortedListInterface <T extends Comparable<T>> {
public boolean add(T element);
public T get(int index);
public boolean search(T element);
public T remove(int index);
public void clear();
public int getLength();
public boolean isEmpty();
public boolean isFull();
}
ADT SortedList Implementation Code
public class SortedArrayList<T extends Comparable<T>> implements SortedListInterface<T>{
//Data Types
private T[] list;
private int length;
private static final int SIZE = 10;
// Constructors
public SortedArrayList() {
this(SIZE);
}
public SortedArrayList(int size) {
length = 0;
list = (T[]) new Comparable[SIZE]; // an array of instances of a class implementing Comparable interface and able to use compareto method but its overidden instead
}
// Setter & Getters
#Override
public int getLength() {
return length;
}
#Override
public boolean isEmpty() {
return length == 0;
}
#Override
public boolean isFull() {
return false;
}
#Override
public void clear() {
length = 0;
}
// Array Expansion
private boolean isArrayFull() {
return length == list.length;
}
private void expandArray() {
T[] oldList = list;
int oldSize = oldList.length;
list = (T[]) new Object[2 * oldSize];
for (int i = 0; i < oldSize; i++) // copy old array elements into new array elements
list[i] = oldList[i];
}
// ADT METHODs
// Add New Elements Function
#Override
public boolean add(T element) {
int i = 0;
while (i < length && element.compareTo(list[i]) > 0) // return 0 with equal , return more than 1 if element larger than list[i] , return -1 if less
i++;
makeRoom(i + 1);
list[i] = element;
length++;
return true;
}
private void makeRoom(int index) { // accepts given index
int newIndex = index - 1;
int lastIndex = length - 1;
for (int i = lastIndex; i >= newIndex; i--)
list[i + 1] = list[i];
}
//Remove Elements Function
#Override
public T remove(int index) { // accepts given index
T result = null;
if ( index >= 1 && index <= length ) {
result = list[index - 1];
if (index < length)
removeGap(index);
length--;
}
return result;
}
private void removeGap(int index) { // accepts given index and remove the gap where the element its removed
int removedIndex = index - 1;
int lastIndex = length - 1;
for (int i = removedIndex; i < lastIndex; i++)
list[i] = list[i + 1]; // shifts elements back to remove the gap
}
// Get Element
#Override
public T get(int index) { // accepts given index and return the object
T object = null;
if ( index >= 1 && index <= length)
object = list[index - 1];
return object;
}
// Search Algorithms
#Override
public boolean search(T element) {
return binarySearch(element);
}
private boolean binarySearch(// Implementation here) {
// Implementation here
}
//To String Method
#Override
public String toString() {
String result = "";
for (int i = 0; i < length; i++)
result += list[i] + "\n";
return result;
}
}
Student Class Implementation
public class Student implements Comparable<Student>{
// Data Types
private Name name;
private char gender;
private String icNo;
private String mobileNo;
private Course course;
private int group;
private String dOB;
// Constructors
public Student() {
}
public Student(Name name, char gender, String icNo, String mobileNo, Course course, int group, String dOB) {
this.name = name;
this.gender = gender;
this.icNo = icNo;
this.mobileNo = mobileNo;
this.course = course;
this.group = group;
this.dOB = dOB;
}
public Student(Name name) {
this.name = name;
}
// setter
public void setName(Name name) {
this.name = name;
}
public void setGender(char gender) {
this.gender = gender;
}
public void setIcNo(String icNo) {
this.icNo = icNo;
}
public void setMobileNo(String mobileNo) {
this.mobileNo = mobileNo;
}
public void setCourse(Course course) {
this.course = course;
}
public void setGroup(int group) {
this.group = group;
}
public void setdOB(String dOB) {
this.dOB = dOB;
}
// getter
public Name getName() {
return name;
}
public char getGender() {
return gender;
}
public String getIcNo() {
return icNo;
}
public String getMobileNo() {
return mobileNo;
}
public Course getCourse() {
return course;
}
public int getGroup() {
return group;
}
public String getdOB() {
return dOB;
}
#Override
public String toString() {
return "Student{" + "name=" + name + ", gender=" + gender + ", icNo=" + icNo + ", mobileNo=" + mobileNo + ", course=" + course + ", group=" + group + ", dOB=" + dOB + '}';
}
public int compareTo(Student object) { // Sort according to name if name same then sort according to gender and so on.
int c = this.name.getFullName().compareTo(object.getName().getFullName());
if(c == 0)
c = this.gender - object.getGender();
if(c == 0)
c = this.icNo.compareTo(object.getIcNo());
if(c == 0)
c = this.mobileNo.compareTo(object.getMobileNo());
if(c == 0)
c = this.group - object.getGroup();
if(c == 0)
c = this.dOB.compareTo(object.getdOB());
return c;
}
}
Course Class
public class Course {
// Data Types
private String courseCode;
private String courseName;
private double courseFee;
// Constructors
public Course() {
}
public Course(String courseCode, String courseName, double courseFee) {
this.courseCode = courseCode;
this.courseName = courseName;
this.courseFee = courseFee;
}
// setter
public void setCourseCode(String courseCode) {
this.courseCode = courseCode;
}
public void setCourseName(String courseName) {
this.courseName = courseName;
}
public void setCourseFee(double courseFee) {
this.courseFee = courseFee;
}
// getter
public String getCourseCode() {
return courseCode;
}
public String getCourseName() {
return courseName;
}
public double getCourseFee() {
return courseFee;
}
#Override
public String toString() {
return "CourseCode = " + courseCode + "Course Name = " + courseName + "Course Fee = " + courseFee;
}
}
Name Class
public class Name {
// Data Types
private String firstName;
private String lastName;
// Constructors
public Name() {
}
public Name(String firstName, String lastName) {
this.firstName = firstName;
this.lastName = lastName;
}
// setter
public void setFirstName(String firstName) {
this.firstName = firstName;
}
public void setLastName(String lastName) {
this.lastName = lastName;
}
// getter
public String getFirstName() {
return firstName;
}
public String getLastName() {
return lastName;
}
public String getFullName(){
return firstName + " " + lastName;
}
#Override
public String toString() {
return "Name{" + "firstName=" + firstName + ", lastName=" + lastName + '}';
}
The binary search algorithm relies on comparing a value being searched for with values in the list being searched. That's why the declaration of your class that implements the SortedListInterface is:
SortedArrayList<T extends Comparable<T>>
Note the extends Comparable<T>.
Comparable is an interface through which you can compare two objects. Hence in the search() method that you have to implement, you know that every object in the list defines the compareTo() method and you simply use that method to compare the object being searched for with individual objects in the list.
Here is a simple implementation of the binary search algorithm in the context of your project.
private T[] list; // The list to search.
private int count; // The number of non-null elements in 'list'.
public boolean search(T element) {
boolean found = false;
int lo = 0;
int hi = count - 1;
while (lo <= hi) {
int mid = (lo + hi) / 2;
if (list[mid].compareTo(element) < 0) {
lo = mid + 1;
}
else if (list[mid].compareTo(element) > 0) {
hi = mid - 1;
}
else {
found = true;
break;
}
}
return found;
}
With a method, you have a method parameter. In the method code you use the parameter name. But when you invoke that method from other code, you provide a value which is substituted for the parameter. In the same way, the code above uses a type parameter which is substituted with the name of an actual class when you create an instance of class SortedArrayList. In your case, T is substituted with Student and class Student must implement the compareTo() method. Hence method search(), in class SortedArrayList does not need to know about the members in class Student.
So you would first create an instance of SortedArrayList like this:
SortedArrayList<Student> theList = new SortedArrayList<>();
Then you can call the search() method like this:
Student s = new Student(/* relevant parameter values */);
theList.search(s);
EDIT
I understand that you don't necessarily want to search for a Student, you may want to search for the Name of a student or a student's mobile phone number. In that case I believe you need a Comparator. Here is the code for class SortedArrayList with the addition of a Comparator
import java.util.Comparator;
import java.util.Objects;
public class SortedArrayList<T extends Comparable<T>> implements SortedListInterface<T> {
private static final int SIZE = 10;
private Comparator<? super T> comparator;
private T[] list;
private int count;
#SuppressWarnings("unchecked")
public SortedArrayList(Comparator<? super T> c) {
comparator = c;
list = (T[]) new Comparable[SIZE]; // No way to verify that 'list' only contains instances of 'T'.
/* NOTE: Following is not allowed.
list = new T[SIZE]; // Cannot create a generic array of T
*/
}
#Override
public boolean add(T element) {
Objects.requireNonNull(element, "Cannot add null element.");
boolean result = false;
if (count == 0) {
list[0] = element;
count = 1;
result = true;
}
else {
if (!isFull()) {
int i = 0;
while (list[i] != null) {
if (element.compareTo(list[i]) < 0) {
break;
}
i++;
}
if (list[i] != null) {
for (int j = count - 1; j >= i; j--) {
list[j + 1] = list[j];
}
}
list[i] = element;
count++;
result = true;
}
}
return result;
}
#Override
public T get(int index) {
checkIndex(index);
return list[index];
}
#Override
public boolean search(T element) {
if (comparator == null) {
return binarySearchComparable(element);
}
else {
return binarySearchComparator(element);
}
}
#Override
public T remove(int index) {
checkIndex(index);
T removed = list[index];
list[index] = null;
for (int i = index; i < count; i++) {
list[i] = list[i + 1];
}
count--;
list[count] = null;
return removed;
}
#Override
public void clear() {
for (int i = 0; i < count; i++) {
list[i] = null;
}
count = 0;
}
#Override
public int getLength() {
return count;
}
#Override
public boolean isEmpty() {
return count == 0;
}
#Override
public boolean isFull() {
return count == SIZE;
}
private boolean binarySearchComparable(T element) {
boolean found = false;
int lo = 0;
int hi = count - 1;
while (lo <= hi) {
int mid = (lo + hi) / 2;
if (list[mid].compareTo(element) < 0) {
lo = mid + 1;
}
else if (list[mid].compareTo(element) > 0) {
hi = mid - 1;
}
else {
found = true;
break;
}
}
return found;
}
private boolean binarySearchComparator(T key) {
int low = 0;
int high = count - 1;
while (low <= high) {
int mid = (low + high) >>> 1;
T midVal = list[mid];
int cmp = comparator.compare(midVal, key);
if (cmp < 0)
low = mid + 1;
else if (cmp > 0)
high = mid - 1;
else
return true; // key found
}
return false; // key not found.
}
private void checkIndex(int index) {
if (index < 0) {
throw new IllegalArgumentException("Negative index.");
}
if (index >= count) {
throw new IllegalArgumentException(String.format("Supplied index %d is not less than %d", index, count));
}
}
}
Here is an example Comparator for the Name of a Student
import java.util.Comparator;
public class NameComparator implements Comparator<Student> {
#Override
public int compare(Student student1, Student student2) {
int result;
if (student1 == null) {
if (student2 == null) {
result = 0;
}
else {
result = -1;
}
}
else {
if (student2 == null) {
result = 1;
}
else {
result = student1.getName().getFullName().compareTo(student2.getName().getFullName());
}
}
return result;
}
}
So in order to search the list according to any combination of Student attributes, simply implement an appropriate Comparator and pass it to the SortedArrayList class.
EDIT 2
Following your comments from November 17, 2019.
Below is code for a "name and mobile" Comparator. As I wrote in my previous Edit, you need to write an appropriate Comparator for a given combination of Student attributes.
import java.util.Comparator;
/**
* Compares {#code Student} name and mobile phone number.
*/
public class NameAndMobileComparator implements Comparator<Student> {
#Override
public int compare(Student student1, Student student2) {
int result;
if (student1 == null) {
if (student2 == null) {
result = 0;
}
else {
result = -1;
}
}
else {
if (student2 == null) {
result = 1;
}
else {
result = student1.getName().getFullName().compareTo(student2.getName().getFullName());
if (result == 0) {
result = student1.getMobileNo().compareTo(student2.getMobileNo());
}
}
}
return result;
}
}

Sort ArrayList of objects by field in custom order

How can I achieve a custom sorting to the content of field name:
first element: P followed by numbers [1-9]{2} always on first
followed by : P followed by numbers 0[0-9]
followed by : S
followed by numbers [1-9]{2}
and then the rest in normal order i1.getName().compareToIgnoreCase(i2.getName())
private static Comparator<Item> itemComperator = new Comparator<Item>() {
#Override
public int compare(Item i1, Item i2) {
if (i1.getName().matches("P[1-9]{2}") && i2.getName().matches("P0[0-9]"))
return -1;
else if (i1.getName().matches("S[1-9]{2}"))
return -1;
else
return i1.getName().compareToIgnoreCase(i2.getName());
}
};
#Test
public void sortItem() {
Item item01 = new Item(1, "R59");
Item item02 = new Item(2, "S48");
Item item03 = new Item(3, "P01");
Item item04 = new Item(4, "P25");
Item item05 = new Item(5, "R99");
List<Item> items = Arrays.asList(item01, item02, item03, item04, item05);
System.out.println("before sorting");
long seed = System.nanoTime();
Collections.shuffle(items, new Random(seed));
for (Item i : items) {
System.out.println(i.getId() + " " + i.getName());
}
System.out.println("after sorting");
Collections.sort(items, itemComperator);
for (Item i : items) {
System.out.println(i.getId() + " " + i.getName());
}
}
public class Item {
private int id;
private String name;
public Item(int id, String name) {
this.id = id;
this.name = name;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
output expected:
after sorting
4 P25
3 P01
2 S48
1 R59
5 R99
I think that I would first map each of the inputs to a "kind" number, which is based upon the list of criteria above. For example:
int kind(String input) {
if (input.matches("P[1-9]{2}") {
return 0;
} else if (input.matches("P0[0-9]")) {
return 1;
} else if (input.matches("S.*")) {
return 2;
} else if (input.matches("[1-9]{2}")) {
return 3;
} else {
return 4;
}
}
This gives you a way to see if the two strings are of the same "kind"; if not, return the ordering based on the kind. If they are the same kind, just compare them using (case insensitive) lexicographic ordering (you don't specify, but I assume you want e.g. "P11" to come before "P22"):
public int compare(Item a, Item b) {
String nameA = a.getName();
String nameB = b.getName();
int kindA = kind(nameA);
int kindB = kind(nameB);
if (kindA != kindB) {
return Integer.compare(kindA, kindB);
} else {
return nameA.compareToIgnoreCase(nameB);
}
}

Finding same objects assigned to a string in an ArrayList

I am not sure if I expressed myself correctly with the title but I will try to be more specific here.
What I have:
An arraylist with clients/customers.
An arraylist with phone numbers assigned to the clients/customers.
My Client class:
import java.util.*;
public class Clients implements Comparable<Clients> {
private String name;
private String address;
public ArrayList<Share> shareList = new ArrayList<Share>();
private PhoneBook phoneBook = new PhoneBook();
public Clients(String name, String address) {
this.name = name;
this.address = address;
}
public void addPhoneDescription(String description) {
phoneBook.addPhoneDescription(description);
}
public void addPhoneNumber(String number) {
phoneBook.addPhoneNumber(number);
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
public PhoneBook getPhoneBook() {
return phoneBook;
}
public boolean equals(Object obj) {
Clients c = (Clients) obj;
return this.name.equals(c.name);
}
public String toString() {
String result;
result = ("\n" + "Name: " + this.getName() + "\n" + "Address: "
+ this.getAddress() + "\n" + "Phone description: " + this
.getPhoneBook());
return result;
}
public int compareTo(Clients other) {
return name.compareTo(other.name);
}
}
This is my PhoneBook class consisting of set/get methods:
import java.util.ArrayList;
public class PhoneBook {
private ArrayList<String> numbersList = new ArrayList<String>();
private ArrayList<String> phoneDescription = new ArrayList<String>();
public void addPhoneDescription(String description) {
phoneDescription.add(description);
}
public void addPhoneNumber(String number) { // Add the phone number to the numbersList
numbersList.add(number);
}
public String toString(){
return numbersList.toString() + phoneDescription.toString();
}
}
What I want to achieve: So if I create lets say 3 clients and 2 of them have the same numbers I want to print out those 2 clients with the number they share/have in common and so on. I have create a method over at my Program class:
public void findDuplicatedNumbers() {
// method that looks for duplicated numbers that clients have
ArrayList<Integer> sNumber = new ArrayList<>();
ArrayList<Integer> duplicateNumber = new ArrayList<>();
for (int i = 0; i < clientList.size(); i++) {
for (int k = 0; k < (clientList.get(i).getPhoneBook().size); k++) {
if (sNumber.contains(clientList.get(i).getPhoneBook().get(k).getNumber())) {
if (duplicateNumber.contains(clientList.get(i).getPhoneBook().get(k).getNumber())) {
} else {
// adds to duplicateNumber arrayList
duplicateNumber.add(clientList.get(i).getPhoneBook().get(k).getNumber());
}
} else {
// adds to sNumber arrayList
sNumber.add(clientList.get(i).getPhoneBook().get(k).getNumber());
}
}
}
for (int i = 0; i < duplicateNumber.size(); i++) {
System.out.println("Phone number: " + duplicateNumber.get(i) + " is share with these clients: ");
for (int k = 0; k < clientList.size(); k++) {
for (int p = 0; p < (clientList.get(p).getPhoneBook().size()); p++) {
if (duplicateNumber.get(i) == clientList.get(k).getPhoneBook().get(p).getNumber()) {
System.out.println(clientList.get(k).getName() + ", ");
}
}
}
System.out.println("\n");
}
}
Puh .. quiet a lot of code for a simple task. KISS (keep it simple):
public void findDuplicatedNumbers() {
Map<String, Set<Client> > duplicates =
new HashMap<String, Set<Client> >();
Set<String> phoneNumbers = new HashSet<String>();
for(Client client : clientList) {
PhoneBook phoneBook = client.getPhoneBook();
phoneNumbers.addAll(phoneBook.getNumberList());
}
for(String phoneNumber : phoneNumbers) {
Set<Client> clients = findClientsByPhoneNumber(phoneNumber);
if(clients.size() > 1)
duplicates.put(phoneNumber, clients);
}
for(Entry<String, Set<Client> entry : duplicates.entrySet()) {
System.out.println("phonenumber " + entry.getKey() + " is dubplicated / is share with these clients:");
for(Client client : entry.getValue()) {
System.out.println(client.getName());
}
}
}
protected Set<Client> findClientsByPhoneNumber(String phoneNumber) {
Set<Client> clients = new HashSet<Client>();
for(Client client : clientList ) {
List<String> phoneNumbers = client.getPhonebook().getNumberList();
if(phoneNumbers.contains(phoneNumber)) {
clients.add(client);
}
}
return clients;
}
This is not only cleaner structured and implements an additional interface for finding clients by number but also more performance in most cases.
Just be clean about what you want to do: If you want to store a list of unique objects, it is one of the Set - implementations. If you want to store something by a key, use a Map - implementation.
public class PhoneBook {
private ArrayList<String> numbersList = new ArrayList<String>();
private ArrayList<String> phoneDescription = new ArrayList<String>();
public void addPhoneDescription(String description) {
phoneDescription.add(description);
}
public void addPhoneNumber(String number) { // Add the phone number to the numbersList
numbersList.add(number);
}
public String toString(){
return numbersList.toString() + phoneDescription.toString();
}
public ArrayList<String> findDuplicatedNumbers() {
ArrayList<String> dupes = new ArrayList<String>();
Collections.sort(numbersList);
Iterator<String> iter = numbersList.iterator();
while(iter.hasNext()) {
String next = iter.next();
if(iter.hasNext() && next == iter.next()) {
dupes.add(next);
}
}
return dupes;
}
}

Do I have to CompareTo implementation?

I am trying to search in a list but I sort as array so that I convert my linked list to array list but when I compile it without this part below. Command prompt gives "Person is not abstract and does not override abstract method compareTo(Person) in Comparable".
How can I fix this?
public int compareTo(Person other){
if (!this.name.equalsIgnoreCase(other.name))
return this.name.compareTo(other.name);
return this.name + " "+other.name;
}
Search list and sort methods:
public void searchList(String search)
{
if(phoneList.size() == 0){
System.out.println("There is no record phone book.");
}
Node<Person> tempNode = phoneList.head;
SLinkedList<Person> tempList = new SLinkedList();
for(int i=1; i<=phoneList.size; i++)
{
if (tempNode.getElement().getName().contains(search) || tempNode.getElement().getSurname().contains(search) || tempNode.getElement().getAddress().contains(search) || tempNode.getElement().getCell().contains(search) || tempNode.getElement().getHome().contains(search) || tempNode.getElement().getWork().contains(search))
{
tempList.addLast(tempNode.getElement());
personArray = new Person[tempList.size()];
Iterator<Person> it = tempList.iterator();
while(it.hasNext()){
int x = 0;
personArray[x] = it.next();
x++;
}
bubbleSort(personArray );
for(int x = 0; x < tempList.size(); x++)
System.out.println((x+1) + ""+ personArray[x]);
}
tempNode = tempNode.getNext();
}
}
public <AnyType extends Comparable<? super AnyType>> void bubbleSort(AnyType[] a) {
int outer, inner;
for (outer = a.length - 1; outer > 0; outer--) { // counting down
for (inner = 0; inner < outer; inner++) { // bubbling up
if (a[inner].compareTo(a[inner + 1]) > 0) { // if out of order...
//then swap
swapReferences(a,inner,inner+1);
}
}
}
}
public <AnyType> void swapReferences( AnyType [ ] a, int index1, int index2 )
{
AnyType tmp = a[ index1 ];
a[ index1 ] = a[ index2 ];
a[ index2 ] = tmp;
}
Person Class:
public class Person implements Comparable<Person>
{
private String name;
private String surname;
public String address;
public String cell;
public String home;
public String work;
public Person(String name, String surname, String address, String cell, String home, String work)
{
this.name = name;
this.surname = surname;
this.address = address;
this.cell = cell;
this.home = home;
this.work = work;
}
// Accessor methods:
public String getName(){
return name;
}
public String getSurname(){
return surname;
}
public String getAddress(){
return address;
}
public String getCell(){
return cell;
}
public String getHome(){
return home;
}
public String getWork(){
return work;
}
// Modifier methods:
public void setName(String name){
this.name = name;
}
public void setSurname(String surname){
this.surname = surname;
}
public void setAddress (String address){
this.address = address;
}
public void setCell (String cell){
this.cell = cell;
}
public void setHome (String home){
this.home = home;
}
public void setWork (String work){
this.work = work;
}
public String toString(){
return name + " " + surname + " " + address + " " + cell + " " + home + " " + work;
}
public int compareTo(Person other){
if (!this.name.equalsIgnoreCase(other.name))
return this.name.compareTo(other.name);
return this.name + " "+other.name;
}
}
Your existing compareTo method has a problem, but removing it violates the implements Comparable contract, since you must provide a compareTo method.
public int compareTo(Person other) {
if (!this.name.equalsIgnoreCase(other.name))
return this.name.compareTo(other.name);
// next line returns a String, but the method needs to return an int
return this.name + " " + other.name;
}
You can instead rely more directly on the standard String compareTo:
public int compareTo(Person other) {
if ( this.name.equalsIgnoreCase( other.name ) ) { return 0 };
return this.name.compareTo( other.name );
}
If you didn't have the ignore case constraint you've coded for, this would simply be
public int compareTo(Person other) {
return this.name.compareTo( other.name );
}
As an aside, there is no reason to make address, cell, home, and work public — and that's generally bad practice.
In order to implement an interface you need to implement all the methods in that interface. You either remove implements Comparable part or add public int compareTo method to your class.
The rule of compareTo method is that :
- if this Person is greater than other , return 1
- if this Person is smaller than other , return -1
- if they are equal, return 0

Categories