比较不同对象的2个Java arraylists,并将匹配的行添加到新的List中

时间:2012-12-04 15:41:40

标签: java arraylist compare match

我们需要比较具有一些公共字段的不同对象的2个arraylists,然后将匹配的行存储到新的arraylist。我已经寻找解决方案,但无法得到我需要的东西。

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;

所以我需要检查是否name & address in the PersonNpi object in the PersonNpiList match to a Person object in the PersonList,如果是,请保存Person details + Npi to a new Arraylist<Employee>

希望我对这个问题很清楚。请让我知道如何有效地解决这个问题。

由于

哈利

修改

我需要将不匹配的行(在第一个arraylist上)保存到另一个列表中。我是否需要另外一个循环或者我可以在同一个For循环中进行吗?有人请吗?

4 个答案:

答案 0 :(得分:2)

如果您实施等于比较问题的值,则可以使用contains查看对象是否在其他列表中。

否则,您将不得不手动迭代列表,并检查每个对象。

如果您使用jdk8 Lambda,您可以执行类似的操作(编译并运行btw,使用正确的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);
    }

答案 1 :(得分:2)

由于我没有看到它们扩展的任何超类,因此您必须手动遍历列表。我假设了很多,例如你有属性的getter和setter,PersonNpi.name或多或少与Person.firstname + Person.lastname相同,你在Address中有一些函数,如{ {1}},您的boolean checkEquality(String street1, String street2, String city, String state, String zip)班级有Person方法与getName()进行比较。在这种情况下,循环遍历第一个数组,并检查每个项目是否第二个具有与之相等的任何项目。

PersonNpi

同样,我做了很多假设,也就是你有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)); } } } 构造函数的假设,它只需要EmployeePerson,并相应地获取所需的信息。 / p>

您应该详细说明,使用超类,并使用PersonNpi函数。换句话说,通过函数更轻松地比较contains()Person

修改:您的第二个问题非常重要,如果不是非常依赖于您对PersonNpiEmployeePerson的进一步实施。现在,我再次假设您有一些方法可以验证PersonNpiEmployeePerson之间的相等性。

我建议不要在一个循环中进行检查,因为你有两个PersonNpi被运行。对于第一个ArrayLists中的每个记录,都会运行PersonNpi - 列表。所以可能发生的事情是在我们检查了所有内容之后,一些List保持不匹配,并且一些Persons保持不匹配,因为我们没有标记PersonNpis和{{1}我们匹配了。

总之:为了方便起见,只需添加此部分:

Persons

此方法确实要求您为所有3个人类实现PersonNpis方法,您可以考虑将其放在像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); 这样的超类下面。在这种情况下,您可以将equals(Object)变为Human

使用一个循环(3个人类需要Object ArrayList方法)

ArrayList<Human>

解释:我们通过两个列表循环equals(Object),以便我们在迭代时从列表中删除。因此,在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); Iterators中,只有单曲保留,因为我们在personList - 列表中添加了双精度,立即将其从其他两个列表中删除。我们使用npiList方法将两个列表中的剩余单曲添加到我们的Employee列表中。

Edit2 :如果由于某种原因无法编辑这些类,请创建3 包装类,如:

nonMatchedPerson

如果您选择使用此方法,请在循环中更改此行:

addAll

到此:

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 (person.equals(personNpi)) { 方法。

另一个解决方案可能是你创建一个这样的静态方法:

if (new PersonWrapper(person).equals(new PersonNpiWrapper(personNpi))) {

现在只需致电equals(),假设您将该方法放在课程public static boolean equals(Object this, Object that) { if (this instanceof Person || this instanceof PersonNpi) //et cetera, et cetera return true; return false; } 中。

答案 2 :(得分:1)

这样的事情应该有效。它假定您可以从EmployeePerson构建PersonNpi。另外,既然你没有告诉Address的结构,我会留给你写地址匹配逻辑。

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 */;
}

这是O(n 2 )操作。通过按名称和地址对数组进行排序,可以大大提高速度。排序操作是O(n log(n)),然后可以将比较实现为O(n)操作。

答案 3 :(得分:-2)

使用HashMap存储第一个列表PersonNpiList。使用map.get(Person) == null检查此人是否在哈希映射中。