比较两组不同类型
Compare two sets of different types
我正在寻找一种方法来判断两组不同的元素类型是否相同,前提是我可以说明这些元素类型之间的一对一关系。在 java 或 guava 或 apache commons 中是否有执行此操作的标准方法?
这是我自己实现的这个任务。例如,我有两个元素 类 我知道如何比较。为了简单起见,我按id字段比较:
class ValueObject {
public int id;
public ValueObject(int id) { this.id=id; }
public static ValueObject of(int id) { return new ValueObject(id); }
}
class DTO {
public int id;
public DTO(int id) { this.id=id; }
public static DTO of(int id) { return new DTO(id); }
}
然后我定义一个接口来做比较
interface TwoTypesComparator<L,R> {
boolean areIdentical(L left, R right);
}
比较集合的实际方法如下所示
public static <L,R> boolean areIdentical(Set<L> left, Set<R> right, TwoTypesComparator<L,R> comparator) {
if (left.size() != right.size()) return false;
boolean found;
for (L l : left) {
found = false;
for (R r : right) {
if (comparator.areIdentical(l, r)) {
found = true; break;
}
}
if (!found) return false;
}
return true;
}
客户代码示例
HashSet<ValueObject> valueObjects = new HashSet<ValueObject>();
valueObjects.add(ValueObject.of(1));
valueObjects.add(ValueObject.of(2));
valueObjects.add(ValueObject.of(3));
HashSet<DTO> dtos = new HashSet<DTO>();
dtos.add(DTO.of(1));
dtos.add(DTO.of(2));
dtos.add(DTO.of(34));
System.out.println(areIdentical(valueObjects, dtos, new TwoTypesComparator<ValueObject, DTO>() {
@Override
public boolean areIdentical(ValueObject left, DTO right) {
return left.id == right.id;
}
}));
我正在寻找此任务的标准解决方案。欢迎提出任何改进此代码的建议。
您可以覆盖 dto/value 对象上的 equals 和哈希码,然后执行:leftSet.containsAll(rightSet) && leftSet.size().equals(rightSet.size())
如果您无法更改元素 类,请创建一个装饰器并将集合设置为装饰器类型。
另一种解决方案是使用 List 而不是 Set(如果允许的话)。 List 有一个名为 get(int index) 的方法,可以检索指定索引处的元素,当两个列表的大小相同时,您可以将它们一一比较。有关列表的更多信息:http://docs.oracle.com/javase/7/docs/api/java/util/List.html
此外,避免在 类 中使用 public 变量。一个好的做法是将变量设为私有并使用 getter 和 setter 方法。
实例化列表并添加值
List<ValueObject> list = new ArrayList<>();
List<DTO> list2 = new ArrayList<>();
list.add(ValueObject.of(1));
list.add(ValueObject.of(2));
list.add(ValueObject.of(3));
list2.add(DTO.of(1));
list2.add(DTO.of(2));
list2.add(DTO.of(34));
比较列表的方法
public boolean compareLists(List<ValueObject> list, List<DTO> list2) {
if(list.size() != list2.size()) {
return false;
}
for(int i = 0; i < list.size(); i++) {
if(list.get(i).id == list2.get(i).id) {
continue;
} else {
return false;
}
}
return true;
}
这就是我对你的情况所做的。你有套。集合很难比较,但最重要的是,您想比较它们的 id。
我只看到一个合适的解决方案,您必须规范化所需的值(提取它们的 ID)然后对这些 ID 进行排序,然后按顺序比较它们,因为如果您不这样做如果不进行排序和比较,您可以跳过重复的 and/or 个值。
想一想 Java 8 允许您懒惰地玩流。所以不要急着过来认为提取,然后排序然后复制很长。与迭代解决方案相比,惰性使其变得相当快。
HashSet<ValueObject> valueObjects = new HashSet<>();
valueObjects.add(ValueObject.of(1));
valueObjects.add(ValueObject.of(2));
valueObjects.add(ValueObject.of(3));
HashSet<DTO> dtos = new HashSet<>();
dtos.add(DTO.of(1));
dtos.add(DTO.of(2));
dtos.add(DTO.of(34));
boolean areIdentical = Arrays.equals(
valueObjects.stream()
.mapToInt((v) -> v.id)
.sorted()
.toArray(),
dtos.stream()
.mapToInt((d) -> d.id)
.sorted()
.toArray()
);
您想推广解决方案吗?没问题。
public static <T extends Comparable<?>> boolean areIdentical(Collection<ValueObject> vos, Function<ValueObject, T> voKeyExtractor, Collection<DTO> dtos, Function<DTO, T> dtoKeyExtractor) {
return Arrays.equals(
vos.stream()
.map(voKeyExtractor)
.sorted()
.toArray(),
dtos.stream()
.map(dtoKeyExtractor)
.sorted()
.toArray()
);
}
对于无法比较的 T
:
public static <T> boolean areIdentical(Collection<ValueObject> vos, Function<ValueObject, T> voKeyExtractor, Collection<DTO> dtos, Function<DTO, T> dtoKeyExtractor, Comparator<T> comparator) {
return Arrays.equals(
vos.stream()
.map(voKeyExtractor)
.sorted(comparator)
.toArray(),
dtos.stream()
.map(dtoKeyExtractor)
.sorted(comparator)
.toArray()
);
}
你提到番石榴,如果你没有 Java 8,你可以使用相同的算法执行以下操作:
List<Integer> voIds = FluentIterables.from(valueObjects)
.transform(valueObjectIdGetter())
.toSortedList(intComparator());
List<Integer> dtoIds = FluentIterables.from(dtos)
.transform(dtoIdGetter())
.toSortedList(intComparator());
return voIds.equals(dtoIds);
您当前的方法不正确,或者至少对于一般集合而言是不一致的。
想象一下:
L
包含对 (1,1)、(1,2)、(2,1)。
R
包含对 (1,1), (2,1), (2,2).
现在,如果您的 id 是第一个值,您的比较将 return 为真,但这些集合真的相等吗?问题是你不能保证集合中最多有一个具有相同 id 的元素,因为你不知道 L
和 R
是如何实现相等的,所以我的建议是不要比较不同类型的集合。
如果你真的需要按照你描述的方式比较两个集合,我会把所有元素从 L
复制到一个列表,然后遍历 R
,每次你在L
从 List
中删除它。只要确保您使用 LinkedList
而不是 ArrayList
.
我正在寻找一种方法来判断两组不同的元素类型是否相同,前提是我可以说明这些元素类型之间的一对一关系。在 java 或 guava 或 apache commons 中是否有执行此操作的标准方法?
这是我自己实现的这个任务。例如,我有两个元素 类 我知道如何比较。为了简单起见,我按id字段比较:
class ValueObject {
public int id;
public ValueObject(int id) { this.id=id; }
public static ValueObject of(int id) { return new ValueObject(id); }
}
class DTO {
public int id;
public DTO(int id) { this.id=id; }
public static DTO of(int id) { return new DTO(id); }
}
然后我定义一个接口来做比较
interface TwoTypesComparator<L,R> {
boolean areIdentical(L left, R right);
}
比较集合的实际方法如下所示
public static <L,R> boolean areIdentical(Set<L> left, Set<R> right, TwoTypesComparator<L,R> comparator) {
if (left.size() != right.size()) return false;
boolean found;
for (L l : left) {
found = false;
for (R r : right) {
if (comparator.areIdentical(l, r)) {
found = true; break;
}
}
if (!found) return false;
}
return true;
}
客户代码示例
HashSet<ValueObject> valueObjects = new HashSet<ValueObject>();
valueObjects.add(ValueObject.of(1));
valueObjects.add(ValueObject.of(2));
valueObjects.add(ValueObject.of(3));
HashSet<DTO> dtos = new HashSet<DTO>();
dtos.add(DTO.of(1));
dtos.add(DTO.of(2));
dtos.add(DTO.of(34));
System.out.println(areIdentical(valueObjects, dtos, new TwoTypesComparator<ValueObject, DTO>() {
@Override
public boolean areIdentical(ValueObject left, DTO right) {
return left.id == right.id;
}
}));
我正在寻找此任务的标准解决方案。欢迎提出任何改进此代码的建议。
您可以覆盖 dto/value 对象上的 equals 和哈希码,然后执行:leftSet.containsAll(rightSet) && leftSet.size().equals(rightSet.size())
如果您无法更改元素 类,请创建一个装饰器并将集合设置为装饰器类型。
另一种解决方案是使用 List 而不是 Set(如果允许的话)。 List 有一个名为 get(int index) 的方法,可以检索指定索引处的元素,当两个列表的大小相同时,您可以将它们一一比较。有关列表的更多信息:http://docs.oracle.com/javase/7/docs/api/java/util/List.html
此外,避免在 类 中使用 public 变量。一个好的做法是将变量设为私有并使用 getter 和 setter 方法。
实例化列表并添加值
List<ValueObject> list = new ArrayList<>();
List<DTO> list2 = new ArrayList<>();
list.add(ValueObject.of(1));
list.add(ValueObject.of(2));
list.add(ValueObject.of(3));
list2.add(DTO.of(1));
list2.add(DTO.of(2));
list2.add(DTO.of(34));
比较列表的方法
public boolean compareLists(List<ValueObject> list, List<DTO> list2) {
if(list.size() != list2.size()) {
return false;
}
for(int i = 0; i < list.size(); i++) {
if(list.get(i).id == list2.get(i).id) {
continue;
} else {
return false;
}
}
return true;
}
这就是我对你的情况所做的。你有套。集合很难比较,但最重要的是,您想比较它们的 id。
我只看到一个合适的解决方案,您必须规范化所需的值(提取它们的 ID)然后对这些 ID 进行排序,然后按顺序比较它们,因为如果您不这样做如果不进行排序和比较,您可以跳过重复的 and/or 个值。
想一想 Java 8 允许您懒惰地玩流。所以不要急着过来认为提取,然后排序然后复制很长。与迭代解决方案相比,惰性使其变得相当快。
HashSet<ValueObject> valueObjects = new HashSet<>();
valueObjects.add(ValueObject.of(1));
valueObjects.add(ValueObject.of(2));
valueObjects.add(ValueObject.of(3));
HashSet<DTO> dtos = new HashSet<>();
dtos.add(DTO.of(1));
dtos.add(DTO.of(2));
dtos.add(DTO.of(34));
boolean areIdentical = Arrays.equals(
valueObjects.stream()
.mapToInt((v) -> v.id)
.sorted()
.toArray(),
dtos.stream()
.mapToInt((d) -> d.id)
.sorted()
.toArray()
);
您想推广解决方案吗?没问题。
public static <T extends Comparable<?>> boolean areIdentical(Collection<ValueObject> vos, Function<ValueObject, T> voKeyExtractor, Collection<DTO> dtos, Function<DTO, T> dtoKeyExtractor) {
return Arrays.equals(
vos.stream()
.map(voKeyExtractor)
.sorted()
.toArray(),
dtos.stream()
.map(dtoKeyExtractor)
.sorted()
.toArray()
);
}
对于无法比较的 T
:
public static <T> boolean areIdentical(Collection<ValueObject> vos, Function<ValueObject, T> voKeyExtractor, Collection<DTO> dtos, Function<DTO, T> dtoKeyExtractor, Comparator<T> comparator) {
return Arrays.equals(
vos.stream()
.map(voKeyExtractor)
.sorted(comparator)
.toArray(),
dtos.stream()
.map(dtoKeyExtractor)
.sorted(comparator)
.toArray()
);
}
你提到番石榴,如果你没有 Java 8,你可以使用相同的算法执行以下操作:
List<Integer> voIds = FluentIterables.from(valueObjects)
.transform(valueObjectIdGetter())
.toSortedList(intComparator());
List<Integer> dtoIds = FluentIterables.from(dtos)
.transform(dtoIdGetter())
.toSortedList(intComparator());
return voIds.equals(dtoIds);
您当前的方法不正确,或者至少对于一般集合而言是不一致的。
想象一下:
L
包含对 (1,1)、(1,2)、(2,1)。
R
包含对 (1,1), (2,1), (2,2).
现在,如果您的 id 是第一个值,您的比较将 return 为真,但这些集合真的相等吗?问题是你不能保证集合中最多有一个具有相同 id 的元素,因为你不知道 L
和 R
是如何实现相等的,所以我的建议是不要比较不同类型的集合。
如果你真的需要按照你描述的方式比较两个集合,我会把所有元素从 L
复制到一个列表,然后遍历 R
,每次你在L
从 List
中删除它。只要确保您使用 LinkedList
而不是 ArrayList
.