Dragon Dragon - 2 months ago 12
Java Question

Java: Filter collection and retrieve data by multiple fields

I have a class:

public class Address {
private String country;
private String state;
private String city;
}


And there are a list of Person objects. Person class looks like:

public class Person {
private String country;
private String state;
private String city;
//other fields
}


I need to filter
Person
objects and get the most suitable one.
Address
object can have at least one not null field.
Person
object can have none, partially or all mentioned fields initialized.

Here is one of the possible input examples:

Three Person objects:
a. PersonA: country = 'A'
b. PersonB: country = 'A', state = 'B'
c. PersonC: country = 'A', state = 'B', city = 'C'

Address object:
a. Address: country = 'A', state = 'B'


Expected result after filtering is PersonB. And in case when there're only PersonA and PersonC objects, then PersonA is more preferable.

I'd like to show how I tried to do this, but in fact it is pure brute force algorithm and I dislike it. Algorithm complexity increases with newly added field. I also thought about using guava filter by predicate, but had no idea what predicate should be.

What is preferable algorithm for such filtering if there's any besides brute force?

Answer

As I understand, by brute-force you mean checking all fields of all entities. Well, if you won't refactor your classes, it's not possible, but there is a simple trick which will help. It uses state pattern.

You can add flag notNulls to both classes:

public class Address {
    private int notNulls = 0;
    private String country;
    private String state;
    private String city;
}

public class Person {
    private int notNulls = 0;
    private String country;
    private String state;
    private String city;
    //other fields
}

I'll show you possible implementation of a one setter as the rest is similar:

public void setCountry(String s) {
    if (country == null {
        if (s != null) {
            country = s;
            notNulls++;
        }
    } else {
        if (s == null) {
            country == null;
            notNulls--;
        } else {
            country = s;
        }
    }
}

public boolean isValid() {
    return notNulls != 0;
}

Now you can simply loop through the objects.

Comments