筛选仅具有相交数据的ArrayList



我有以下类:

public class School{
    List<ClassRoom> classRooms;
}
public class ClassRoom{
    List<Student> students;
}
public class Student{
    String name;
    List<Long> typeIdList;
}

我只需要得到typeId,这是给定教室S内所有学生的共同因素。

为了能够让所有学生都在指定的ID=123的教室S内,我做了以下操作:

final long typeIdToSearchFor = ...;
Collection<Student> filtered = Collections2.filter(students,
    new Predicate<Student>() {
        @Override
        public boolean apply(Student s) {
            return s.typeId == typeIdToSearchFor;
        }
    }
);

只是想知道番石榴能不能处理这样的事情?交叉点的意思是,它必须出现在所有实例中才能考虑这种类型。

我知道for循环会更可读,但我只是发现了Guava的功能。

您可以使用Multiset来计数出现次数:

ClassRoom classRoom = /* comes from somewhere */;
List<Student> students = classRoom.getStudents();
// Aggregate all the typeIds.
Multiset<Long> typeIds = HashMultiset.create();
for (Student student : students) {
    // Assuming a student doesn't have duplicated typeIds:
    typeIds.addAll(student.getTypeIds());
}
// Find which typeIds are present for all the students.
for (Multiset.Entry<Long> entry : typeIds.entrySet()) {
    if (entry.getCount() == students.size()) {
        System.out.println(entry.getElement());
    }
}

如果要检查所有Student是否都有特定的typeId,请将Iterables.all与现有谓词一起使用。

您还可以使用Multimaps.index():创建由typeId索引的StudentMultimap

Multimap<Long, Student> studentsByTypeId = Multimaps.index(students, new Function<Student, Long>() {
  public Long apply(Student s) {
    return s.typeId;
  }
};

然后使用studentsByTypeId.keySet()可以获得唯一的typeIds。

您可以使用studentsByTypeId.keySet().size() == 1检查它们是否都共享相同的typeId

如果你想要相交的,你不应该与特定的进行比较,你至少应该检查它是否包含在另一个集合的id中。像这样:

new Predicate<Student>() {
    @Override
    public boolean apply(Student s) {
        return otherIds.contains(s.typeId);
    }
}

但我仍然认为,如果你对这两个集合进行二进制搜索(排序后(,你可以更快地得到答案。像这样的

Collections.sort(list1);
Collections.sort(list2);
List<E> intersected = new ArrayList<E>();
for(E element : list1){
    if(Collections.binarySearch(list2, element) >= 0){
        intersected.add(element);
    }
}

你甚至可以找到一种方法来完成最小的列表。它可以帮助它获得一些性能。

最新更新