java - 比较两组不同类型

标签 java guava apache-commons

如果我可以说明这些元素类型之间的一对一关系,我正在寻找一种方法来判断两组不同的元素类型是否相同。是否有在 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)

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;
    }
}));

我正在寻找此任务的标准解决方案。欢迎提出任何改进此代码的建议。

最佳答案

这就是我在你的情况下会做的。你有套。集合很难比较,但最重要的是,你想比较它们的 id。

我只看到一个合适的解决方案,您必须规范化所需的值(提取它们的 ID),然后对这些 ID 进行排序,然后按顺序比较它们,因为如果您不进行排序和比较,您可以跳过传递重复项和/或值。

想一想 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()
  );
}

你提到了 Guava,如果你没有 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);

关于java - 比较两组不同类型,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/29409881/

相关文章:

java - Apache Commons ZipArchiveOutputStream 在添加带有非 ASCII 字符的文件名时中断

java - 如果 getter 使用 "is"而不是 "get",PropertyUtils 无法转换 boolean 值

java - java中 boolean 值的最佳实践

java - Apache Commons HttpClient 是否支持 GZIP?

java - 即使 jar 位于/lib 中,也会抛出 "java.lang.ClassNotFoundException: org.apache.commons.io.FileUtils"

java - Guava 相当于 Apache commons.lang3 StringEscapeUtils.escapeJava()

java - 创建自定义流式 API

java - 需要使用单元测试框架来测试 Servlet、Filters 和 JPA 等 J2EE 组件

java - 在Java中对列表进行排序的方式相同,id出现在数组中

java - 最佳实践 : how do I tell if a collection/set/let is a Guava ImmutableSet/Immutable map?