split List of values based on value - java

I have a list of objects(Person in this case) and I want to split them into a list of list Person objects based on value. In the example given below, I have a Person object with name, id and Address object. The address object has a house number, Street Id. Now I want to split them based on Street Id in address object using collections API. I tried grouping by, partitioning in collections, but couldn't get it work. I want to use only Java 8. No third party.
Expected result :
[ [person1, person2, person3] , [person4, person5], [person6] ]
Thanks.
package testapplication2;
import java.util.ArrayList;
import java.util.List;
/**
*
*
*/
public class JavaCollections {
public static void main(String[] args) {
JavaCollections c = new JavaCollections();
c.test1();
}
public void test1() {
List<Person> persons = new ArrayList<>();
Address address1 = new Address(1, "X Street", 100);
Address address2 = new Address(2, "X Street", 100);
Address address3 = new Address(3, "X Street", 100);
Address address4 = new Address(4, "Y Street", 101);
Address address5 = new Address(5, "Y Street", 101);
Address address6 = new Address(6, "Z Street", 102);
persons.add(new Person(1, "P1", address1));
persons.add(new Person(2, "P2", address2));
persons.add(new Person(3, "P3", address3));
persons.add(new Person(4, "P4", address4));
persons.add(new Person(5, "P5", address5));
persons.add(new Person(6, "P6", address6));
}
public class Person {
public int personId;
private String name;
private Address address;
public Person() {
}
public Person(int personId, String name, Address address) {
super();
this.personId = personId;
this.name = name;
this.address = address;
}
public int getPersonId() {
return personId;
}
public void setPersonId(int personId) {
this.personId = personId;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Address getAddress() {
return address;
}
public void setAddress(Address address) {
this.address = address;
}
#Override
public String toString() {
return "Person{" + "personId=" + personId + ", name=" + name + ", address=" + address + '}';
}
}
public class Address {
public Address() {
}
public Address(int houseNumber, String streetName, int streetId) {
this.houseNumber = houseNumber;
this.streetId = streetId;
this.streetName = streetName;
}
private int houseNumber;
private String streetName;
private int streetId;
public int getHouseNumber() {
return houseNumber;
}
public void setHouseNumber(int houseNumber) {
this.houseNumber = houseNumber;
}
public String getStreetName() {
return streetName;
}
public void setStreetName(String streetName) {
this.streetName = streetName;
}
public int getStreetId() {
return streetId;
}
public void setStreetId(int streetId) {
this.streetId = streetId;
}
#Override
public String toString() {
return "Address{" + "houseNumber=" + houseNumber + ", streetName=" + streetName + ", streetId=" + streetId + '}';
}
}
}

This should do it:
List< List<Person> > groups = new ArrayList<>( persons.stream().collect(
Collectors.groupingBy( p -> p.getAddress().getStreetId() ) ).values() );
Alternatively by #shmosel:
List< List<Person> > groups = persons.stream().collect( Collectors.collectingAndThen(
Collectors.groupingBy( p -> p.getAddress().getStreetId() ),
m -> new ArrayList<>( m.values() ) ) );

The solution for your requirement is the usage of stream().collect() with a groupingBy call on the person.address.streetId field as a key.
This code should do it:
final List<List<Person>> groupedPersons = persons.stream()
.collect(Collectors.groupingBy(o -> o.address.streetId))
.entrySet().stream()
.map(Map.Entry::getValue).collect(Collectors.toList());
// Code for printing out
groupedPersons.forEach(people -> {
System.out.print("[");
System.out.print(people.stream().map(person -> String.format("person%d", person.personId)).collect(Collectors.joining(",")));
System.out.print("]");
});
Here is a full example which you can run:
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
public class Partitions {
public static void main(String[] args) {
List<Person> persons = new ArrayList<>();
Address address1 = new Address(1, "X Street", 100);
Address address2 = new Address(2, "X Street", 100);
Address address3 = new Address(3, "X Street", 100);
Address address4 = new Address(4, "Y Street", 101);
Address address5 = new Address(5, "Y Street", 101);
Address address6 = new Address(6, "Z Street", 102);
persons.add(new Person(1, "P1", address1));
persons.add(new Person(2, "P2", address2));
persons.add(new Person(3, "P3", address3));
persons.add(new Person(4, "P4", address4));
persons.add(new Person(5, "P5", address5));
persons.add(new Person(6, "P6", address6));
final List<List<Person>> groupedPersons = persons.stream()
.collect(Collectors.groupingBy(o -> o.address.streetName))
.entrySet().stream()
.map(Map.Entry::getValue).collect(Collectors.toList());
groupedPersons.forEach(people -> {
System.out.print("[");
System.out.print(people.stream().map(person -> String.format("person%d", person.personId)).collect(Collectors.joining(",")));
System.out.print("]");
});
}
public static class Person {
public int personId;
private String name;
private Address address;
public Person() {
}
public Person(int personId, String name, Address address) {
super();
this.personId = personId;
this.name = name;
this.address = address;
}
public int getPersonId() {
return personId;
}
public void setPersonId(int personId) {
this.personId = personId;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Address getAddress() {
return address;
}
public void setAddress(Address address) {
this.address = address;
}
#Override
public String toString() {
return "Person{" + "personId=" + personId + ", name=" + name + ", address=" + address + '}';
}
}
public static class Address {
private int houseNumber;
private String streetName;
private int streetId;
public Address() {
}
public Address(int houseNumber, String streetName, int streetId) {
this.houseNumber = houseNumber;
this.streetId = streetId;
this.streetName = streetName;
}
public int getHouseNumber() {
return houseNumber;
}
public void setHouseNumber(int houseNumber) {
this.houseNumber = houseNumber;
}
public String getStreetName() {
return streetName;
}
public void setStreetName(String streetName) {
this.streetName = streetName;
}
public int getStreetId() {
return streetId;
}
public void setStreetId(int streetId) {
this.streetId = streetId;
}
#Override
public String toString() {
return "Address{" + "houseNumber=" + houseNumber + ", streetName=" + streetName + ", streetId=" + streetId + '}';
}
}
}
This will print out:
[person4,person5][person6][person1,person2,person3]
Update:
If you want to preserve the order in which it was added to the initial list, you can provide a collector which supplies a java.util.LinkedHashSet - a data structure which preserves uniqueness and the original order of insertion.
The grouping code would look like this:
final List<Set<Person>> groupedPersons = persons.stream()
.collect(Collectors.groupingBy(o -> o.address.streetId,
Collector.of(() -> new LinkedHashSet<Person>(), HashSet::add, (s1, s2) -> {
s1.addAll(s2);
return s1;
})))
.entrySet().stream()
.map(Map.Entry::getValue).collect(Collectors.toList());
If you use this code in the example above it will print out:
[person1,person2,person3][person4,person5][person6]

To achieve this, you need to
use a Stream of your list,
then groupBy the id of the Address, all the Person with the same adressId will be together in a Map<Integer,List<Person>>
then you get the values (all the List<Person> and collecth them together)
public static void main(String[] args) {
JavaCollections c = new JavaCollections();
List<Person> persons = c.test1();
List<List<Person>> res = new ArrayList<>(persons .stream()
.collect(Collectors.groupingBy(o -> o.getAddress().getStreetId())).values());
System.out.println(test);
}
And change test1() to
public static List<Person> test1() {
...;
return persons;
}
to return the list

Related

Iterate List based on condition Set Values to another object

Iterate List based on condition Set Values to another object using Java 8?
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
public class Demo {
public static void main(String[] args) {
// TODO: Condition is => Only if id = 100, then assign internalMarks to (externalMarks + internalMarks); to 103
// So internalMarks = 0 and externalMarks = 500+250=750
List<Employee> employees = Arrays.asList(
new Employee(100, 500, "John", 250),
new Employee(101, 500, "Jane", 250),
new Employee(102, 500, "Jack", 250),
new Employee(103, 500, "Mike", 250)
);
List<Employee> newList = new ArrayList<>();
employees.stream().forEach(e -> {
if(e.getId() == 100 && e.getId() > 0) {
e.setExternalMark(0);
newList.add(e);
}else {
newList.add(e);
}
});
System.out.println(newList);
}
static class Employee {
private int id;
private int internalMark;
private String name;
private int externalMark;
public Employee() {
}
public Employee(int id, int internalMark, String name, int externalMark) {
super();
this.id = id;
this.internalMark = internalMark;
this.name = name;
this.externalMark = externalMark;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public int getInternalMark() {
return internalMark;
}
public void setInternalMark(int internalMark) {
this.internalMark = internalMark;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getExternalMark() {
return externalMark;
}
public void setExternalMark(int externalMark) {
this.externalMark = externalMark;
}
#Override
public String toString() {
return "Employee [id=" + id + ", internalMark=" + internalMark + ", name=" + name + ", externalMark="
+ externalMark + "]";
}
}
}
//Condition is => Only if id = 100, then assign internalMarks to (externalMarks + internalMarks); to 103
// So internalMarks = 0 and externalMarks = 500+250=750
From your condition, as its slighlty unclear that externalMarks should be changes for Id=100 or Ids 100 to 103, means for all Employees
Take one scenario, where externalMarks should be changes for id = 100, then solution can be
List<Employee> newList1 = employees.stream()
.map(e-> {
if(e.getId() == 100) {
e.setExternalMark(e.getInternalMark()+e.getExternalMark());
e.setInternalMark(0);
}
return e;
})
.collect(Collectors.toList());
For other scenario, where externalMarks should be changes for id = 100 to 103, then solution can be
List<Employee> newList1 = employees.stream()
.map(e-> {
e.setExternalMark(e.getInternalMark()+e.getExternalMark());
e.setInternalMark(0);
return e;
})
.collect(Collectors.toList());

Convert POJO to POJO with custom converter using json configuration

We have two Pojo files.
Person {
String name;
int age;
String address;
String phoneNo;
boolean isMarried;
}
and
OtherPerson {
//mandatory fields are name and age
String name_other;
int age_other;
//other fields
Map<String, Object> otherFields;
}
and a json file which defines the mapping between the fields using name
mappingJson {
"name":"name_other",
"age":"age_other",
"address":"address_other",
"phoneNo":"phoneno_other",
"isMarried":"ismarried_other"
}
Please let me know the best approach to convert Person to OtherPerson. So that the mandatory fields map to name_other and age_other while the other fields should be added to the map(otherFields)
It may be
Person->Person(json)->OtherPerson
Or Person->OtherPerson.
EDIT:
"Use case: We have an API which used to accepts a POJO 'A' but now it needs to accept POJO 'B' as an input argument. This POJO needs to get converted into POJO 'A' which can then be used for persisting into the database. Also POJO 'B' is not under our control"
That's a perfect fit for Jackson Converter! :)
It could work like this:
class OtherPerson {
#JsonProperty("name")
public String name_other;
#JsonProperty("age")
public int age_other;
Map<String, Object> otherFields = new LinkedHashMap<>();;
#JsonAnySetter
public void add(String key, Object value) {
otherFields.put(key, value);
}
}
// ...
Person person = new Person();
person.name = "Avinash";
person.age = 25;
person.address = "Mumbai";
person.phoneNo = "910731";
person.isMarried = true; // :( sorry ladies!
// ...
ObjectMapper mapper = new ObjectMapper();
// If we cannot put #JsonAutoDetect on top of Person.class,
// we need to add handling of non-public fields
// since Person seems to neither have public fields nor setters
mapper.configOverride(Person.class)
.setVisibility(JsonAutoDetect.Value.defaultVisibility()
.withFieldVisibility(JsonAutoDetect.Visibility.NON_PRIVATE));
OtherPerson other = mapper.convertValue(person, OtherPerson.class);
VoilĂ !
I personally would do this without JSON. It's my understanding that some fields in the Map are optional while name and age are mandatory. In the case of the optional content, I would use the Ternary operator to create the person object. This allows you to add some default value if the optional field is not available.
Main
import java.util.HashMap;
import java.util.Map;
/**
*
* #author blj0011
*/
public class JavaApplication30 {
/**
* #param args the command line arguments
*/
public static void main(String[] args) {
// TODO code application logic here
Map<String, Object> map1 = new HashMap();
map1.put("address", "123 Hello Street");
map1.put("phoneNo", "555-555-5555");
map1.put("isMarried", true);
OtherPerson otherPerson = new OtherPerson("John Doe", 22, map1);
Map<String, Object> map2 = new HashMap();
map2.put("address", "4456 Bye Road");
map2.put("isMarried", false);
OtherPerson otherPerson2 = new OtherPerson("Jane Doe", 21, map2);
Person person1 = new Person(otherPerson.getName_other(), otherPerson.getAge_other(),
otherPerson.getOtherFields().containsKey("address") ? otherPerson.getOtherFields().get("address").toString(): "",
otherPerson.getOtherFields().containsKey("phoneNo") ? otherPerson.getOtherFields().get("phoneNo").toString(): "",
otherPerson.getOtherFields().containsKey("isMarried") ? Boolean.valueOf(otherPerson.getOtherFields().get("isMarried").toString()): false);
System.out.println(person1);
Person person2 = new Person(otherPerson2.getName_other(), otherPerson2.getAge_other(),
otherPerson2.getOtherFields().containsKey("address") ? otherPerson2.getOtherFields().get("address").toString(): "",
otherPerson2.getOtherFields().containsKey("phoneNo") ? otherPerson2.getOtherFields().get("phoneNo").toString(): "",
otherPerson2.getOtherFields().containsKey("isMarried") ? Boolean.valueOf(otherPerson2.getOtherFields().get("isMarried").toString()): false);
System.out.println(person2);
}
}
Person
/**
*
* #author blj0011
*/
public class Person {
private String name;
private int age;
private String address;
private String phoneNo;
private boolean isMarried;
public Person(String name, int age, String address, String phoneNo, boolean isMarried) {
this.name = name;
this.age = age;
this.address = address;
this.phoneNo = phoneNo;
this.isMarried = isMarried;
}
public boolean isIsMarried() {
return isMarried;
}
public void setIsMarried(boolean isMarried) {
this.isMarried = isMarried;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
public String getPhoneNo() {
return phoneNo;
}
public void setPhoneNo(String phoneNo) {
this.phoneNo = phoneNo;
}
#Override
public String toString() {
return "Person{" + "name=" + name + ", age=" + age + ", address=" + address + ", phoneNo=" + phoneNo + ", isMarried=" + isMarried + '}';
}
}
OtherPerson
/**
*
* #author blj0011
*/
public class OtherPerson {
//mandatory fields are name and age
private String name_other;
private int age_other;
//other fields
private Map<String, Object> otherFields;
public OtherPerson(String name_other, int age_other, Map<String, Object> otherFields) {
this.name_other = name_other;
this.age_other = age_other;
this.otherFields = otherFields;
}
public Map<String, Object> getOtherFields() {
return otherFields;
}
public void setOtherFields(Map<String, Object> otherFields) {
this.otherFields = otherFields;
}
public String getName_other() {
return name_other;
}
public void setName_other(String name_other) {
this.name_other = name_other;
}
public int getAge_other() {
return age_other;
}
public void setAge_other(int age_other) {
this.age_other = age_other;
}
}
Output
Person{name=John Doe, age=22, address=123 Hello Street, phoneNo=555-555-5555, isMarried=true}
Person{name=Jane Doe, age=21, address=4456 Bye Road, phoneNo=, isMarried=false}
As you can see in the output OtherPerson2 did not have a phone number. Empty string was use as the default value.

Filter an ArrayList via Optional in Java 8

I am getting an exception while trying to filter and iterate over a Optional using Java 8. I have an object Subject which is being added in an array list and a value of null also.
Problem Statement: I have an ArrayList, I want to iterate it, filter it and then based on that, only print that record which fulfills the condition.
package com.example.app;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
public class OptionalTest {
public static void main(String[] args) {
System.out.println("getSubject: " + getSubjects());
// print the Subject with the name "Math"
System.out.println("getSubject " + getSubjects().filter((Subject s) -> s.getName().equalsIgnoreCase("Math")));
}
private static Optional getSubjects() {
Subject subject1 = new Subject(1, "Math", (short)2, "");
Subject subject2 = new Subject(2, "Social Science", (short)4, "Social Science");
Subject subject3 = new Subject(3, "English", (short)6, "Literature");
List<Subject> subjects = new ArrayList<>();
Optional<List<Subject>> optional = Optional.of(subjects);
subjects.add(subject1);
subjects.add(subject2);
subjects.add(null);
subjects.add(subject3);
return optional;
}
}
class Subject {
int id;
String name;
short type;
String description;
public Subject(int id, String name, short type, String description) {
this.id = id;
this.name = name;
this.type = type;
this.description = description;
}
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;
}
public short getType() {
return type;
}
public void setType(short type) {
this.type = type;
}
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
#Override
public String toString() {
return "\nSubject{" + "id=" + id + ", name=" + name + ", type=" + type + ", description=" + description + '}'+"\n";
}
}
Using Optional.filter would be used to filter List instances as per your code snippet. This is not what you want:
Optional.of(getSubjects()).filter(predicate) //filters lists, not subjects in lists
Your intention is probably to use the a list of Subject objects, then filter. It's the filter method of the Stream interface that returns an Optional instance:
I'd change this method:
private static List<Subject> getSubjects(){
Subject subject1 = new Subject(1, "Math", (short)2, "");
Subject subject2 = new Subject(2, "Social Science", (short)4, "Social Science");
Subject subject3 = new Subject(3, "English", (short)6, "Literature");
List<Subject> subjects = new ArrayList<>();
subjects.add(subject1);
subjects.add(subject2);
subjects.add(null);
subjects.add(subject3);
return subjects;
}
And then use it as follows:
Optional<Subject> filtered = getSubjects()
.stream().filter(s -> s.getName().equalsIgnoreCase("Math"))
//Find first is just one of the many Stream methods
//returning an optional
//It's correct to use it in this case because you know
//only one value is expected to match the filter predicate.
.findFirst();
In fact, if you expect more than one subject to match your filter, you should collect, instead, instead of picking one. In this case, you don't need an optional:
List<Subject> mathSubjects = getSubjects()
.stream().filter((s -> s.getName().equalsIgnoreCase("Math")))
.collect(Collectors.toList());
You can do it very simply using lambda expression, I am providing you a sample so that you can modify according to your need.
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
public class Java8Optional {
public static void main(String[] args) {
List<Employee> employeeList = new ArrayList<>();
employeeList.add(new Employee(1, "syed"));
employeeList.add(new Employee(2, "az"));
employeeList.add(null);
employeeList.add(new Employee(4, "Rof"));
employeeList.forEach(n -> Optional.ofNullable(n).ifPresent(e -> System.out.println("Employee ID="+e.employeeId+"\tEmployee Name="+e.employeeName)));
}
static class Employee {
Integer employeeId;
String employeeName;
public Integer getEmployeeId() {
return employeeId;
}
public void setEmployeeId(Integer employeeId) {
this.employeeId = employeeId;
}
public String getEmployeeName() {
return employeeName;
}
public void setEmployeeName(String employeeName) {
this.employeeName = employeeName;
}
public Employee(Integer employeeId, String employeeName) {
super();
this.employeeId = employeeId;
this.employeeName = employeeName;
}
}
}

Grouping by fields of inner object

I have following two classes:
class Man {
private int id;
private String firstName;
private String lastName;
private int age;
private int countOfChildren;
private Address address;
}
class Address {
private Country country;
private City city;
private String street;
private long quantityOfPeople;
}
I have no idea how to group List<Man> by street and city fields of Address class. How can I do it?
Collectors class provides Collectors.groupingBy(keyProvider, downstream) you can use to group by a pair of values. To pair two values you can either use AbstractMap.SimpleEntry or you can implement your own Pair<T,K> class that represents a pair of two values (it's worth mentioning that you will have to implement hashCode() and equals(object) methods in your Pair class if you want to use it as a key in a hash map). Also two values you want to pair in a key have to implement hashCode() and equals(object) methods - it's worth using immutable classes in this case.
The whole grouping part can be done by:
final Map<Map.Entry<City, String>, List<Man>> groupedByCityAndStreet = people.stream()
.collect(Collectors.groupingBy(
man -> new AbstractMap.SimpleEntry<>(man.getAddress().getCity(), man.getAddress().getStreet()),
Collectors.toList()
));
In this example I have used AbstractMap.SimpleEntry to represent a pair of Country and street. It creates a map where for each key it groups a list of Man object based of country and street. Below you can find a full example:
import java.util.AbstractMap;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.stream.Collectors;
public class GroupByTest {
public static void main(String[] args) {
final List<Man> people = Arrays.asList(
new Man(1, "John", "Doe", 20, 0, new Address(new Country("England"), new City("London"), "Test Street 2", 10000)),
new Man(2, "Mary", "Smith", 54, 4, new Address(new Country("Germany"), new City("Berlin"), "Maine Strasse 32", 10000)),
new Man(3, "James", "Rose", 13, 0, new Address(new Country("England"), new City("London"), "Test Street 2", 10000)),
new Man(4, "Vincent", "Dog", 43, 2, new Address(new Country("Germany"), new City("Berlin"), "Volkswagen Platz 31", 10000)),
new Man(5, "Arnold", "Smoke", 72, 3, new Address(new Country("Italy"), new City("Rome"), "Pepperoni 31", 10000)),
new Man(6, "Katy", "Puppet", 33, 3, new Address(new Country("England"), new City("London"), "Test Street 3", 10000))
);
final Map<Map.Entry<City, String>, List<Man>> groupedByCityAndStreet = people.stream()
.collect(Collectors.groupingBy(
man -> new AbstractMap.SimpleEntry<>(man.getAddress().getCity(), man.getAddress().getStreet()),
Collectors.toList()
));
// Print people associated with given city and street to console
groupedByCityAndStreet.forEach((k, v) -> {
System.out.println("People associated with " + k.getKey().name + ", " + k.getValue() + ":");
v.forEach(man -> {
System.out.println(man);
});
});
}
static final class Man {
private final int id;
private final String firstName;
private final String lastName;
private final int age;
private final int countOfChildren;
private final Address address;
public Man(int id, String firstName, String lastName, int age, int countOfChildren, Address address) {
this.id = id;
this.firstName = firstName;
this.lastName = lastName;
this.age = age;
this.countOfChildren = countOfChildren;
this.address = address;
}
public int getId() {
return id;
}
public String getFirstName() {
return firstName;
}
public String getLastName() {
return lastName;
}
public int getAge() {
return age;
}
public int getCountOfChildren() {
return countOfChildren;
}
public Address getAddress() {
return address;
}
#Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Man man = (Man) o;
return id == man.id &&
age == man.age &&
countOfChildren == man.countOfChildren &&
Objects.equals(firstName, man.firstName) &&
Objects.equals(lastName, man.lastName) &&
Objects.equals(address, man.address);
}
#Override
public int hashCode() {
return Objects.hash(id, firstName, lastName, age, countOfChildren, address);
}
#Override
public String toString() {
return "Man{" +
"id=" + id +
", firstName='" + firstName + '\'' +
", lastName='" + lastName + '\'' +
", age=" + age +
", countOfChildren=" + countOfChildren +
", address=" + address +
'}';
}
}
static class Address {
private final Country country;
private final City city;
private final String street;
private final long quantityOfPeople;
public Address(Country country, City city, String street, long quantityOfPeople) {
this.country = country;
this.city = city;
this.street = street;
this.quantityOfPeople = quantityOfPeople;
}
public Country getCountry() {
return country;
}
public City getCity() {
return city;
}
public String getStreet() {
return street;
}
public long getQuantityOfPeople() {
return quantityOfPeople;
}
#Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Address address = (Address) o;
return quantityOfPeople == address.quantityOfPeople &&
Objects.equals(country, address.country) &&
Objects.equals(city, address.city) &&
Objects.equals(street, address.street);
}
#Override
public int hashCode() {
return Objects.hash(country, city, street, quantityOfPeople);
}
#Override
public String toString() {
return "Address{" +
"country=" + country +
", city=" + city +
", street='" + street + '\'' +
", quantityOfPeople=" + quantityOfPeople +
'}';
}
}
static class City {
private final String name;
public City(String name) {
this.name = name;
}
public String getName() {
return name;
}
#Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
City city = (City) o;
return Objects.equals(name, city.name);
}
#Override
public int hashCode() {
return Objects.hash(name);
}
#Override
public String toString() {
return "City{" +
"name='" + name + '\'' +
'}';
}
}
static class Country {
private final String name;
public Country(String name) {
this.name = name;
}
public String getName() {
return name;
}
#Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Country country = (Country) o;
return Objects.equals(name, country.name);
}
#Override
public int hashCode() {
return Objects.hash(name);
}
#Override
public String toString() {
return "Country{" +
"name='" + name + '\'' +
'}';
}
}
}
When you run this example you will something like this in the console:
People associated with Rome, Pepperoni 31:
Man{id=5, firstName='Arnold', lastName='Smoke', age=72, countOfChildren=3, address=Address{country=Country{name='Italy'}, city=City{name='Rome'}, street='Pepperoni 31', quantityOfPeople=10000}}
People associated with London, Test Street 3:
Man{id=6, firstName='Katy', lastName='Puppet', age=33, countOfChildren=3, address=Address{country=Country{name='England'}, city=City{name='London'}, street='Test Street 3', quantityOfPeople=10000}}
People associated with Berlin, Volkswagen Platz 31:
Man{id=4, firstName='Vincent', lastName='Dog', age=43, countOfChildren=2, address=Address{country=Country{name='Germany'}, city=City{name='Berlin'}, street='Volkswagen Platz 31', quantityOfPeople=10000}}
People associated with Berlin, Maine Strasse 32:
Man{id=2, firstName='Mary', lastName='Smith', age=54, countOfChildren=4, address=Address{country=Country{name='Germany'}, city=City{name='Berlin'}, street='Maine Strasse 32', quantityOfPeople=10000}}
People associated with London, Test Street 2:
Man{id=1, firstName='John', lastName='Doe', age=20, countOfChildren=0, address=Address{country=Country{name='England'}, city=City{name='London'}, street='Test Street 2', quantityOfPeople=10000}}
Man{id=3, firstName='James', lastName='Rose', age=13, countOfChildren=0, address=Address{country=Country{name='England'}, city=City{name='London'}, street='Test Street 2', quantityOfPeople=10000}}
Hope it helps.

How to sort by more than one property of an object - linq4j

I am using linq4j. I am only sorting by one property and would like to sort by multiple property. If is is not supported in linq4j than what other method I can use. Following is my code snippet,
import java.util.Arrays;
import java.util.List;
import net.hydromatic.linq4j.Linq4j;
import net.hydromatic.linq4j.function.*;
public class Linq4jExample {
public static class Employee {
public final int empno;
public final String name;
public final int deptno;
public Employee(int empno, String name, int deptno) {
this.empno = empno;
this.name = name;
this.deptno = deptno;
}
public String toString() {
return "Employee(empno: " + empno +",name: " + name + ", deptno:" + deptno + ")";
}
}
public static final Employee[] emps = {
new Employee(100, "Fred", 10),
new Employee(110, "Bill", 30),
new Employee(120, "Bill", 10),
new Employee(120, "Eric", 12),
new Employee(130, "Janet", 13),
};
public static final Function1<Employee, Integer> EMP_DEPTNO_SELECTOR =
new Function1<Employee, Integer>() {
public Integer apply(Employee employee) {
return employee.deptno;
}
};
public static void main(String[] args) {
List<Employee> filter=Linq4j.asEnumerable(Arrays.asList(emps))
.orderBy(new Function1<Employee,String>()
{
public String apply(Employee arg0)
{
return arg0.name;
}
}).toList();
}
}
A potential use case could be sorting by department number and then by name
You can have multiple order by in linq4j. Check the following example
package maven_lab;
import java.util.Arrays;
import java.util.List;
import org.apache.calcite.linq4j.Linq4j;
import org.apache.calcite.linq4j.function.Function1;
public class Linq4jExample {
public static final Employee[] emps = {
new Employee(100, "Fred", 10),
new Employee(110, "Bill", 30),
new Employee(120, "Bill", 10),
new Employee(120, "henry", 10),
new Employee(120, "Adam", 10),
new Employee(120, "Eric", 12),
new Employee(130, "Janet", 13),
};
public static final Function1<Employee, Integer> EMP_DEPTNO_SELECTOR =
new Function1<Employee, Integer>() {
public Integer apply(Employee employee) {
return employee.deptno;
}
};
public static void main(String[] args) {
List<Employee> filter = Linq4j.asEnumerable(Arrays.asList(emps)).orderBy(e -> e.deptno)
.orderBy(e -> e.name).toList();
System.out.println(filter);
}
public static class Employee {
public final int empno;
public final String name;
public final int deptno;
public Employee(int empno, String name, int deptno) {
this.empno = empno;
this.name = name;
this.deptno = deptno;
}
public String toString() {
return "Employee(empno: " + empno + ",name: " + name + ", deptno:" + deptno + ")";
}
}
}
Notice that I am ordering by department first and then the name. You should also use jdk8 lambda instead of anonymous classes.
Pre JDK8 you can do this like following,
List<Employee> filter = Linq4j.asEnumerable(Arrays.asList(emps)).orderBy(new Function1<Employee, Integer>() {
public Integer apply(Employee arg0) {
return arg0.deptno;
}
}).orderBy(new Function1<Employee, String>() {
public String apply(Employee arg0) {
return arg0.name;
}
}).toList();

Categories