比较不同对象的 2 个 Java 数组列表并将匹配的行添加到新列表中
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/13706524/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Compare 2 Java arraylists of different objects and add the matching rows to a new List
提问by Harry
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.
我们需要比较具有一些公共字段的不同对象的 2 个数组列表,然后将匹配的行存储到一个新的数组列表中。我已经搜索了解决方案,但无法获得我需要的东西。
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>
所以我需要检查是否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>
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?
我需要将不匹配的行(在第一个数组列表上)保存到另一个列表中。我需要有另一个循环还是可以在同一个 For 循环上执行?请问有人吗?
回答by NimChimpsky
If you implement equals to compare the values under question, you can then use contains
to see if object is in other list.
如果您实现 equals 来比较有问题的值,则可以使用它contains
来查看对象是否在其他列表中。
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) :
如果你使用 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);
}
回答by Ted Hopp
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.
像这样的事情应该有效。它假设您有一种Employee
从 aPerson
和 a构造 a 的方法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 */;
}
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.
这是一个 O(n 2) 操作。您可以通过按名称和地址对两个数组进行排序来大大加快速度。排序操作是 O(n log(n)),然后可以将比较实现为 O(n) 操作。
回答by stealthjong
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 PersonNpi
s. In that case, loop through the first array, and check for every item if the second has anything equal to it.
由于我没有看到它们扩展的任何超类,因此您必须手动遍历您的列表。我假设了很多,例如,您的属性有 getter 和 setter,这PersonNpi.name
或多或少与 相同Person.firstname + Person.lastname
,您在Address
like 中有一些函数boolean checkEquality(String street1, String street2, String city, String state, String zip)
,您的Person
类有一个getName()
方法可以与PersonNpi
s进行比较。在这种情况下,循环遍历第一个数组,并检查每个项目是否有任何与它相等的项目。
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.
同样,我做了很多假设,还有一个假设,即您有一个Employee
只需要Person
和 的构造函数PersonNpi
,并相应地获取所需的信息。
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.
您应该详细说明,使用超类,并使用contains()
函数。换句话说,通过函数使比较Person
和PersonNpi
更容易。
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
.
编辑:您的第二个问题非常依赖于您对Employee
,Person
和 的进一步实施PersonNpi
。现在,我将再次假设您有一些方法可以验证Employee
,Person
和之间的相等性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.
我建议不要在一个循环中进行检查,因为您有两个循环ArrayLists
通过。该PersonNpi
-list是通过在第一每条记录跑去List
。所以可能会发生的情况是,在我们检查完所有内容之后,有一些Persons
是不匹配的,还有一些PersonNpis
是不匹配的,因为我们没有标记哪个Persons
并且PersonNpis
我们已经匹配了。
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>
此方法确实需要您equals(Object)
为所有 3 人类实现该方法,您可能会考虑将其放在像Human
. 在这种情况下,可以使Object ArrayList
成ArrayList<Human>
With one loop (requires equals(Object)
method for the 3 person classes):
使用一个循环(需要equals(Object)
3 人课程的方法):
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.
说明:我们Iterators
遍历两个列表,使我们能够在迭代时从列表中删除。所以在 thepersonList
和 the 中npiList
,只剩下单打,因为我们将双打添加到Employee
-list,立即将它们从其他两个列表中删除。我们nonMatchedPerson
使用addAll
方法将两个列表中剩余的单曲添加到我们的-list 中。
Edit2: If you can't edit those classes for whatever reason, make 3 wrapperclasses, something like:
Edit2:如果由于某种原因您无法编辑这些类,请制作 3 个包装类,例如:
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.
使用它,您仍然可以实现自己的equals()
方法。
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
.
现在只需调用Person.equals(person, personNpi)
,假设您将方法放在类中Person
。
回答by David Ruan
Use HashMap
to store the first list PersonNpiList
. Use map.get(Person) == null
to check whether the person is in the hash map.
使用HashMap
存储第一个列表PersonNpiList
。使用map.get(Person) == null
来检查的人是否是在散列图。