public record ValueHolder(int val1, int val2) {} // equals/hashCode, constructor and getters provided by the compiler
类 A 和 B
public class A {
private int val1;
private int val2;
// constructor and getters
}
public class B {
private int val1;
private int val2;
// constructor and getters
}
public Optional<A> getMatchingItem(List<A> listA, List<B> listB) {
Map<ValueHolder, A> aByValue = listA.stream()
.collect(Collectors.toMap(a -> new ValueHolder(a.getVal1(), a.getVal2()),
Function.identity()));
Map<ValueHolder, B> bByValue = listB.stream()
.collect(Collectors.toMap(b -> new ValueHolder(b.getVal1(), b.getVal2()),
Function.identity()));
return aByValue.keySet().stream()
.filter(bByValue::containsKey)
.findFirst()
.map(aByValue::get);
}
It doesn't clear how uniqueIdentificationNumber of the Person and Company are related. It's worth to refine these classes to represent the relationship between them in a better way (maybe a company can hold a reference to a list of customers). And don't overuse setters, if id is unique there's no need to allow it to be changed.
Although it's not clear how these values are connected because of the drawbacks of your class design technically it's doable.
return the customer object which is matching with Id
For that, you need to create two maps that will associate these identifiers with companies and persons. Then create a stream over the keys of one of these maps and check for every key whether if contained in another map. And then retrieve the Person objects for filtered keys and collect the result into a list.
Map<Integer, Person> personById =
persons.stream()
.collect(Collectors.toMap(Person::getUniqueIdentificationNumber,
Function.identity()));
Map<Integer, Company> companyById =
companies.stream()
.collect(Collectors.toMap(Company::getUniqueIdentificationNumber,
Function.identity()));
List<Person> customers =
personById.keySet().stream()
.filter(companyById::containsKey) // checking whether id is present in the company map
.map(personById::get) // retrieving customers
.collect(Collectors.toList());
Update
Let me rephrase the description of the problem.
There are two unrelated classes A and B. Both classes have two fields of type int, let's say val1 and val2 (and maybe a few more fields but we are not interested in them).
We have a list of objects A and a list of objects B. The goal is to find a single object A for which exists an object B with the same values for both val1 and val2 (in order to keep things simple I propose to stick with this example).
There are two approaches that could be used for that purpose:
create an auxiliary class with two fields val1 and val2, and associate every instance of A and B with instances of this class;
create a nested map Map<Integer, Map<Integer, *targetClass*>>, this solution is more complicated and less flexible, if you'll need to compare objects by three, four, etc. fields the code will quickly become incomprehensible.
So I'll stick with the first approach. We need to declare the ValueHolder class with two fields and implement the equals/hashCode contract based on these fields. For Java 16 and above we can utilize a record for that purpose and make use of equals(), hashCode, getters provided by the compiler. The option with the record will look like this:
public record ValueHolder(int val1, int val2) {} // equals/hashCode, constructor and getters provided by the compiler
Classes A and B
public class A {
private int val1;
private int val2;
// constructor and getters
}
public class B {
private int val1;
private int val2;
// constructor and getters
}
And a method that accepts two lists: List<A> and List<B>, and return a result as Optional<A>. Because the matching element may or may not be present and it's a good practice to return an optional object in such cases instead of returning null in case the result was not found. It provides more flexibility and that's precisely the case for which the optional was designed.
public Optional<A> getMatchingItem(List<A> listA, List<B> listB) {
Map<ValueHolder, A> aByValue = listA.stream()
.collect(Collectors.toMap(a -> new ValueHolder(a.getVal1(), a.getVal2()),
Function.identity()));
Map<ValueHolder, B> bByValue = listB.stream()
.collect(Collectors.toMap(b -> new ValueHolder(b.getVal1(), b.getVal2()),
Function.identity()));
return aByValue.keySet().stream()
.filter(bByValue::containsKey)
.findFirst()
.map(aByValue::get);
}
发布评论
评论(1)
目前尚不清楚
Person
和Company
的uniqueIdentificationNumber
是如何关联的。值得细化这些类以更好的方式表示它们之间的关系(也许公司可以保存对客户列表的引用)。并且不要过度使用 setter,如果 id 是唯一的,则无需允许更改它。尽管由于类设计的缺陷,技术上尚不清楚这些值是如何连接的,但它是可行的。
为此,您需要创建两个映射,将这些标识符与公司和关联起来人。然后在其中一个映射的键上创建一个流,并检查每个键是否包含在另一个映射中>。然后检索
Person
对象以查找已过滤的键,并将结果收集到列表中。更新
让我重新表述一下问题的描述。
有两个不相关的类
A
和B
。这两个类都有 两个int
类型的字段,比方说val1
和val2
(也许还有更多字段,但我们对它们不感兴趣)。我们有一个对象列表
A
和一个对象列表B
。目标是找到一个对象A
,该对象存在一个对象B
,并且val1
和val2
具有相同的值code> (为了让事情简单,我建议坚持使用这个例子)。有两种方法可用于此目的:
val1
和val2
的辅助类,并关联A
的每个实例和B
以及此类的实例;Map>
,如果您需要将对象进行三倍、四倍等比较,此解决方案会更复杂且不太灵活. 字段的代码很快就会变得难以理解。所以我会坚持第一种方法。我们需要声明具有两个字段的
ValueHolder
类,并基于这些字段实现equals/hashCode
合约。对于Java 16及更高版本,我们可以利用记录来实现此目的,并使用equals()
、hashCode
,由编译器提供的 getter。带有记录的选项将如下所示:类
A
和B
以及接受两个列表的方法:
List
和>列出
,并将结果作为Optional
返回。因为匹配元素可能存在也可能不存在,并且在这种情况下返回可选对象是一个好习惯,而不是在未找到结果时返回
null
。它提供了更大的灵活性,而这正是该选项设计的目的。It doesn't clear how
uniqueIdentificationNumber
of thePerson
andCompany
are related. It's worth to refine these classes to represent the relationship between them in a better way (maybe a company can hold a reference to a list of customers). And don't overuse setters, if id is unique there's no need to allow it to be changed.Although it's not clear how these values are connected because of the drawbacks of your class design technically it's doable.
For that, you need to create two maps that will associate these identifiers with companies and persons. Then create a stream over the keys of one of these maps and check for every key whether if contained in another map. And then retrieve the
Person
objects for filtered keys and collect the result into a list.Update
Let me rephrase the description of the problem.
There are two unrelated classes
A
andB
. Both classes have two fields of typeint
, let's sayval1
andval2
(and maybe a few more fields but we are not interested in them).We have a list of objects
A
and a list of objectsB
. The goal is to find a single objectA
for which exists an objectB
with the same values for bothval1
andval2
(in order to keep things simple I propose to stick with this example).There are two approaches that could be used for that purpose:
val1
andval2
, and associate every instance ofA
andB
with instances of this class;Map<Integer, Map<Integer, *targetClass*>>
, this solution is more complicated and less flexible, if you'll need to compare objects by three, four, etc. fields the code will quickly become incomprehensible.So I'll stick with the first approach. We need to declare the
ValueHolder
class with two fields and implement theequals/hashCode
contract based on these fields. For Java 16 and above we can utilize a record for that purpose and make use ofequals()
,hashCode
, getters provided by the compiler. The option with the record will look like this:Classes
A
andB
And a method that accepts two lists:
List<A>
andList<B>
, and return a result asOptional<A>
. Because the matching element may or may not be present and it's a good practice to return an optional object in such cases instead of returningnull
in case the result was not found. It provides more flexibility and that's precisely the case for which the optional was designed.