Order objects in toString based on objects parameter value - java

I have this toString method set up
public String toString (){
String result;
result = "Ideal Family";
result += "\n"+person1.toString();
result += "\n"+person2.toString();
result += "\n"+person3.toString();
result += "\n"+person4.toString();
result += "\n"+pet1.toString();
result += "\n"+car1.toString();
result += "\n"+car2.toString();
result += "\n"+homeAddress.toString();
return result;
}
in which I list objects in the order I wish to output them. Is there a way to re-order the list based on values within the objects.
Specefically in the Person Class, to re-order the person objects based on an instance variable, an int.
The Person class takes these parameters
public Person (String personName,String personGender,String personSS,int personAge){
name = personName;
ss = personSS;
age = personAge;
gender = personGender;
}

First of all, you should be using a collection instead of having four variables. It would have been easier.
But for what you are looking for, create a list of Persons
List<Person> personList = Arrays.asList(person1, person2, person3, person4);
sort the list
Collections.sort(personList, Comparator<Person>() {
public int compare(Person p1, Person p2) {
return Integer.valueOf(p1.getAge()).compareTo(p2.getAge());
}
});
and iterate through the list
for(Person person : personList) {
result += "\n"+person.toString();
}

Yes, but you need a List or array first.
List<Person> family;
Or:
Person[] family;
Then you can use Collection.sort or Arrays.sort to re-order the family for printing.

Related

Creating objects dynamically using a list of Strings?

I am trying to create objects by using a list of Strings that will populate their fields. For example I have the list of strings, Note that the values repeat after every 3. i.e. id, name , address.
List<String> myList = "Id1", "name1", "address1", "Id2", "name2", "address2";
I would like to dynamically create a number of Person Objects (shown below) using this list
Person object:
public class Person {
private String id;
private String name;
private String address;
public Person() {
}
public Person(String id, String name, String address) {
this.id = id;
this.name = name;
this.address = address;
}
//standard getters and setters
}
What I want to do is have a method that will take the list of strings as an input and then create the objects dynamically. How could I best do this?
I know that I could do the following if I knew that I was definitely populating 2 objects, but the problem is that there may be more or less.
public List<Person> createObjectsFromStringList(List<String> list){
List<person> personList = new Arraylist<>();
Person person1 = new Person(list.get(0), list.get(1), list.get(2));
Person person2 = new Person(list.get(3), list.get(4), list.get(5));
personList.add(person1);
personList.add(person2);
return personList;
}
A simple for loop can do the work:
public List<Person> createObjectsFromStringList(List<String> list) {
List<person> personList = new Arraylist<>();
//We use < size-2 here because we access 2 indeces ahead of x in this loop
for(int x=0; x<list.size()-2; x+=3) {
personList.add(new Person(list.get(x), list.get(x+1), list.get(x+2));
}
return personList;
}
At first glance, I feel like having the different field values across one List is a sign of a poor code structure, but maybe you're already stuck with this List as-is.
Edit:
Now let's suppose you want a partial Person based on the number of remaining elements. Supposing they are still in the same order, you could modify this method to check the validity of the current index for each field:
public List<Person> createObjectsFromStringList(List<String> list) {
List<person> personList = new Arraylist<>();
int size = list.size();
//Now we remove the "-2" from size check because we will handle this ourselves
for(int x=0; x<size; x+=3) {
String id = list.get(x); //Obviously valid
String name = x+1 < size? list.get(x+1) : null;
String address = x+2 < size? list.get(x+2) : null;
personList.add(new Person(id, name, address);
}
return personList;
}
We're using the ternary operation ? ... : null here, so if we run out of elements we set the associated Person field to null instead of using an out-of-bounds index.
You can use recursion
public List<Person> createObjectsFromStringList(List<String> list){
List<person> personList = new Arraylist<>();
for(int i=0; i<list.size(); i++){
personList.add(new Person(list(i),list(i+1),list(i+2)));
i+=2;
}
return personList;
}
Notice that restructuring your list would me much better. make it like this:
List<String> myList = "Id1_name1_address1", "Id2_name2_address2";
Or even use different lists (it is much better). If you change your list structure as above then change the code to this :
public List<Person> createObjectsFromStringList(List<String> list){
List<person> personList = new Arraylist<>();
for(int i=0; i<list.size(); i++){
String[] info= list(i).split("_"); // this will give u a 3element array of yout info IdX nameX addressX
personList.add(new Person(info(0),info(1),info(2)));
}
return personList;
As you want to access your elements sequentially you should use java.util.LinkedList in such loop
for(true)
if(linkedList.size()>=3){
Person person= new
Person(linkedList.removeFirst(),linkedList.removeFirst(),linkedList.removeFirst());
personList.add(person);
}
else break;
But ArrayList and its get method is good for random access by index which is not your case
If you use java 8 you can try something like this:
public List<Person> createObjectsFromStringList(List<String> list) {
//partition by 3 and list.size.
Map<Integer,List<Integer>> map = IntStream
.range(0,list.size())
.boxed()
.collect(Collectors.groupingBy(e->(e)/3));
List<Person> personList = new ArrayList<>();
map.entrySet().forEach(e->{
List<String> per= e.getValue();
Person p = new Person(per.get(0),per.get(1),per.get(2));
personList.add(p);
});
return personList;
}

group (gather) items of an object

i have a List of an Object, with the following characteristics:
Class Object{
String gender;
String state;
int quantity;
int Salary;
}
List<Object> myList=new ArrayList<Object>;
As input of the List, i have the following:
and as Output, i want to keep only one occurrence of the object with the same gender and the same state, in the same time sum the quantity and the salsary correspanding, like the following:
my question is how can i loop through myList, find objects with the same gender and the same state,keep only one occurence of them, and sum the quantity and the salary correspanding ??
First off, I renamed your class to MyObject as Object is the base Java class. Now for the rest of it - You can use a pseudo-index made out of the gender and state combinations you have already found and sum up the values for the rest of the list as follows:
Class MyObject{
String gender;
String state;
int quantity;
int Salary;
}
List<MyObject> myList=new ArrayList<MyObject>();
List<String> stateAndGender = new ArrayList<String>();
List<MyObject> finalList = new ArrayList<MyObject>();
// add objects here
for(MyObject mO : myList){
String s = mO.getGender();
s+="," + mO.getState();
if(stateAndGender.indexOf(s)==-1)
{
MyObject fO = new MyObject();
fO.setGender(mO.getGender());
fO.setState(mO.getState());
stateAndGender.add(s);
int Qua = mO.getQuantity();
int Sal = mO.getSalary();
for(int i=0; i<myList.size(); i++)
{
if(String t = myList.get(i).getGender()+","+myList.get(i).getGender() == s)
Qua += myList.get(i).getQuantity();
Sal += myList.get(i).getSalary();
}
fO.setQuantity(Qua);
fO.setSalary(Sal);
finalList.add(fO);
}
}
// Then return finalList
The above code assumes you have proper getters for the fields of the class you have created and your gender and state do not contain commas, otherwise you will need to tweak the code.
UPDATE: Now you get a list of the MyObject type with the proper values as you requested! It is not the original one, though, but the one called finalList.

Sort List based on index value

This is what i have so far, i'm trying to sort a bunch of List<String>'s based on the value of an index.
LinkedHashSet<List<String>> sorted = new LinkedHashSet<List<String>>();
How do i sort the LinkedHashSet in order from Highest to Lowest index 2 value of the List's?
Example input:
List<String> data1 = Database.getData(uuid);
double price = Double.valueOf(data1.get(2))
data1.add("testval");
data1.add("testval");
data1.add("100.00");
sorted.add(data1);
and on another seperate List:
List<String> data2 = Database.getData(uuid);
double price = Double.valueOf(data2.get(2))
data2.add("anotherval");
data2.add("anotherval");
data2.add("50.00");
sorted.add(data2);
Output of the sorted LinkedHashSet in descending order.
testval testval 100.00
anotherval anotherval 50.00
Sorry if this is confusing, im not sure where to go about sorting like this.
Create a new class to represent you complex objects. There is no need to store multiple values in a list when you can do it in objects.
public class ComplexObject {
private String description1;
private String description2;
private Double value;
public ComplexObject(String description1, String description2, Double value) {
this.description1 = description1;
this.description2 = description2;
this.value = value;
}
public void setDescription1(String description1) {
this.description1 = description1;
}
public String getDescription1() {
return description1;
}
public void setDescription2(String description2) {
this.description2 = description2;
}
public String getDescription2() {
return description2;
}
public void setValue(Double value) {
this.value = value;
}
public Double getValue() {
return value;
}
}
Then add elements to the list and sort it using a new, custom, comparator:
public static void main(String[] args) {
List<ComplexObject> complexObjectList = new ArrayList<ComplexObject>();
//add elements to the list
complexObjectList.add(new ComplexObject("testval","testval",100.00d));
complexObjectList.add(new ComplexObject("anotherval","anotherval",50.00d));
//sort the list in descending order based on the value attribute of complexObject
Collections.sort(complexObjectList, new Comparator<ComplexObject>() {
public int compare(ComplexObject obj1, ComplexObject obj2) {
return obj2.getValue().compareTo(obj1.getValue()); //compares 2 Double values, -1 if less , 0 if equal, 1 if greater
}
});
//print objects from sorted list
for(ComplexObject co : complexObjectList){
System.out.println(co.getDescription1()+" "+co.getDescription2()+" "+co.getValue());
}
}
Output:
testval testval 100.0
anotherval anotherval 50.0
Firstly, you shouldn't use a LinkedHashSet but a TreeSet. LinkedHashSet will retain the insertion order without sorting.
Secondly, you need to initialize your TreeSet with a Comparator that compares based on whichever value of your List is required, that is, if you know the index of the String that will represent a double value in advance. Otherwise I would recommend using custom objects instead of List.
If you decide to use custom objects, you don't necessarily need to initialize your TreeSet with a Comparator as second argument.
Instead, you could have your custom objects implement Comparable, and implement a one-time comparation logic there.
It all depends on whether you only need to sort in a particular order.
Finally, custom objects will require you to override equals and hashCode.
First, and extracted from Oracle's Java reference:
This linked list defines the iteration ordering, which is the order in which elements were inserted into the set
So you can't sort your data just inserting it into the LinkedHashSet.
You may be confusing that set implementation with SortedSet. SortedSet allows you to pass a comparator which will determine the elements order in the data structure.
On the other hand, I don't know whether you chose you List<String> arbitrarily but it seems to me a wiser option to aggregate your the 3 strings as a class attributes. The point is that, if your elements are always going to be 3 elements, being the last one a double value: Why do you need a dynamic structure as a List?
EDIT
Here you have a possible better implementation of what you want:
public class Element
{
public Element(String a, String b, double val) {
this.a = a;
this.b = b;
this.val = val;
}
#Override
public String toString() {
return a + "\t" + b + "\t" + val;
}
public String a;
public String b;
public double val;
}
And you can use this class to store your elements. An example of use:
SortedSet<Element> sorted = new TreeSet<>(new Comparator<Element>() {
#Override
public int compare(Element o1, Element o2) {
return (new Double(o1.val)).compareTo(o2.val);
}
});
sorted.add(new Element("testval", "testval", 100.0));
sorted.add(new Element("anotherval", "anotherval", 50.0));
for(Element el: sorted)
{
System.out.println(el);
}
Note that the comparator is given as an instance of an anonympous inner class implementing Java's Comparator interface.

Compare 2 Java arraylists of different objects and add the matching rows to a new List

We need to compare 2 arraylists of different objects having some common fields, and then store the matching rows to a new arraylist. I have searched for solutions, but wasn't able to get what I need.
List<Person> personList = new ArrayList<Person>();
Person:
private String firstName;
private String lastName;
private String street1;
private String street2;
private String city;
private String stateCode;
private String zipCode;
List<PersonNpi> npiList = new ArrayList<PersonNpi>();
PersonNpi:
private String name;
private String npi;
private Address address;
So I need to check if the name & address in the PersonNpi object in the PersonNpiList match to a Person object in the PersonList, and if yes save the Person details + Npi to a new Arraylist<Employee>
Hope I'm clear on the question. Please let me know on how to solve this efficiently.
Thanks
Harry
EDIT:
I need to save the non-matching rows (on the first arraylist) as well to another list. Do I need to have another loop or can I do it on the same For loop? Anyone please?
Since I don't see any superclasses from which they extend, you have to manually iterate through your lists. I am assuming a lot, for instance that you have getters and setters for your attributes, that PersonNpi.name is more or less the same as Person.firstname + Person.lastname, that you have some function in Address like boolean checkEquality(String street1, String street2, String city, String state, String zip), that your Person class has a getName() method to compare with PersonNpis. In that case, loop through the first array, and check for every item if the second has anything equal to it.
ArrayList<Employee> employees = new ArrayList<Employee>();
for(Person person : personList) {
for(PersonNpi personNpi : npiList) {
if (person.getName().equals(personNpi.getName()) &&
person.getAddress().checkEquality(...address parts here...)) {
employees.add(new Employee(person, personNpi));
}
}
}
Again, I made a lot of assumptions, also the one that you have an Employee constructor which just requires the Person and the PersonNpi, and gets the required information accordingly.
You should elaborate more, use superclasses, and use the contains() function. In other words, make comparing the Person and the PersonNpi easier through a function.
Edit: your second question is highly, if not extremely dependant on your further implementation of Employee, Person and PersonNpi. For now, I'll yet again assume you have some methods that verify equality between Employee, Person and PersonNpi.
I'd suggest to not do the checking in one loop, since you have two ArrayLists which are ran through. The PersonNpi-list is ran through for every record in the first List. So what might happen is after we checked everything, a few Persons are left unmatched, and a few PersonNpis are left unmatched, since we don't flag which Persons and PersonNpis we've matched.
In conclusion: for easiness' sake, just add this part:
ArrayList<Object> nonMatchedPersons = new ArrayList<Object>();
for (Person person : personList)
if (!employees.contains(person))
nonMatchedPersons.add(person);
for (PersonNpi personNpi : npiList)
if (!employees.contains(personNpi))
nonMatchedPersons.add(personNpi);
This method does require you to implement the equals(Object) method for all 3 person classes, which you might consider putting beneath a superclass like Human. In that case, you can make the Object ArrayList into a ArrayList<Human>
With one loop (requires equals(Object) method for the 3 person classes):
List<Employee> employees = new ArrayList<Employee>();
ArrayList<Object> nonMatchedPersons = new ArrayList<Object>();
Iterator<Person> personIterator = personList.iterator();
while (personIterator.hasNext()) {
Iterator<PersonNpi> npiIterator = npiList.iterator();
while(npiIterator.hasNext()) {
Person person = personIterator.next();
PersonNpi personNpi = npiIterator.next();
if (person.equals(personNpi)) {
employees.add(new Employee(person, personNpi));
personIterator.remove();
npiIterator.remove();
}
}
}
nonMatchedPersons.addAll(personList);
nonMatchedPersons.addAll(npiList);
Explanation: we loop with Iterators through both lists, to enable us to remove from the list while iterating. So in the personList and the npiList, only the singles remain, as we add doubles to the Employee-list, instantly removing them from the other two lists. We add the remaining singles in the two lists to our nonMatchedPerson-list with the addAll method.
Edit2: If you can't edit those classes for whatever reason, make 3 wrapper classes, something like:
public class PersonWrapper {
private Person person;
public PersonWrapper(Person person) {
this.person = person;
}
#override
public boolean equals(Object other) {
if (other == null)
return false;
if (other instanceof PersonWrapper) {
//etc etc, check for equality with other wrappers.
...
}
}
}
If you choose to use this approach, change this line in the loop:
if (person.equals(personNpi)) {
to this:
if (new PersonWrapper(person).equals(new PersonNpiWrapper(personNpi))) {
Using this, you can still implement your own equals() method.
Another solution could be that you make a static method like this:
public static boolean equals(Object this, Object that) {
if (this instanceof Person || this instanceof PersonNpi) //et cetera, et cetera
return true;
return false;
}
Now just call Person.equals(person, personNpi), assuming you put the method in the class Person.
If you implement equals to compare the values under question, you can then use contains to see if object is in other list.
Otherwise you'll have to manually iterate though lists, and check each object.
And if you using jdk8 Lambda, you could do something like this (compiles and runs btw, with correct jdk) :
public static void main(String args[]) throws ParseException {
TransformService transformService = (inputs1, inputs2) -> {
Collection<String> results = new ArrayList<>();
for (String str : inputs1) {
if (inputs2.contains(str)) {
results.add(str);
}
}
return results;
};
Collection<String> inputs1 = new ArrayList<String>(3) {{
add("lemon");
add("cheese");
add("orange");
}};
Collection<String> inputs2 = new
ArrayList<String>(3) {{
add("apple");
add("random");
add("cheese");
}};
Collection<String> results = transformService.transform(inputs1, inputs2);
for (String result : results) {
System.out.println(result);
}
}
public interface TransformService {
Collection<String> transform(Collection<String> inputs1, Collection<String> inputs2);
}
Something like this should work. It assumes that you have a way of constructing an Employee from a Person and a PersonNpi. Also, since you don't tell the structure of an Address, I'll leave it to you to write the address matching logic.
public List<Employee> findCommonElements(List<Person> list1,
List<PersonNpi> list2)
{
List<Employee> common = new ArrayList<Employee>();
for (Person p1 : list1) {
PersonNpi p2 = find(list2, p1);
if (p2 != null) {
common.add(new Employee(p1, p2));
}
}
}
private PersonNpi find(List<PersonNpi> list, Person p) {
for (PersonNpi p2 : list) {
if (matches(p, p2)) {
return p2;
}
}
return null;
}
private boolean matches(Person p1, PersonNpi p2) {
return /* logic for comparing name and address info */;
}
This is an O(n2) operation. You could speed this up considerably by sorting both arrays by name and address. The sorting operation is O(n log(n)) and the comparison could then be implemented as an O(n) operation.
Use HashMap to store the first list PersonNpiList. Use map.get(Person) == null to check whether the person is in the hash map.

not sure if I should search or sort my hashmap

Hi I have a list of people with their ages, I need to find those who are more than 30 years old,
is there any possibility to search in a hashmap ? (please note that I may need to look for those in other age ranges as well so I prefer not to use two different lists for the sake of simplicity of code)
In short: My goal is to find a way to search for elements with specific values in HashMap
Sample list is
element1 40
element2 4
element3 66
element4 5
I want to find those with values more than 40 and those with values more than or equal to 66.
I'd suggest you to use NavigableMap (Implemented as TreeSet).
This implementation is a quite fast - O(log(N)), versus O(N) if you implement index based on lists.
Edit. Example:
class PersonsAgeIndex {
private NavigableMap<Integer, List<Person>> ageToPersons =
new TreeMap<Integer, List<Person>>();
public void addPerson( Person p ) {
List<Person> personsWithSameAge = this.ageToPersons.get( p.age );
if ( personsWithSameAge == null ) {
personsWithSameAge = new LinkedList<Person>();
this.ageToPersons.put( p.age, personsWithSameAge );
}
personsWithSameAge.add( p );
}
public List<Person> personsWithAgeLessThan( int age ) {
List<Person> persons = new LinkedList<Person>();
// persons with less age
for (List<Person> tmp : this.ageToPersons.headMap( age ).values()) {
persons.addAll( tmp );
}
return persons;
}
public List<Person> personsWithAgeInInterval( int minAge, int maxAge ) {
List<Person> persons = new LinkedList<Person>();
// persons with age, which: (minAge <= age <= maxAge)
for (List<Person> tmp : this.ageToPersons.subMap( minAge, true, maxAge, true ).values()) {
persons.addAll( tmp );
}
return persons;
}
}
class Person {
public final int age;
public Person(int age) {
this.age = age;
}
}
Try this:
private List<Person> getPeople(Map<?, Person> peopleMap, int filterAge) {
List<Person> returnList = new ArrayList<Person>(peopleMap.values().size());
for (Person p : peopleMap.values()) {
if (p.getAge() > filterAge)
returnList.add(p);
}
return returnList;
}
HashMapiteration order is 'not predictable' (that's to say that if you sort, and than insert keys, in a determinate order when you later try to iterate the keys the order is not the same).
Use a LinkedHashMap instead.
Good question... unfortunately, a Map needs a very specific key. Your solution above is the only real way to do it.
Alternatively you could maintain two lists, and store those that older than 30 to the 2nd list.
You cannot sort a HashMap, it has no order. If you want an ordered HashMap, use LinkedHashMap.
HashMap<String,String> hmap = new HashMap<String,String>();
SortedSet<String> keys = new TreeSet<String>(hmap.keySet());
This will give you a sorted set which you could make a subset of.
keys.subSet(from,to) e.g keys.subSet(30,100)
and you will have a set with all required elemets.

Categories