我有一个集合列表:
setlist = [s1,s2,s3...sn]
我想要集合的所有方式比较,这是2 ^ n个集合:
setIntersection = [s1 ∩ s2, s1 ∩ s2 ∩ s3, ....., s2 ∩ s3 ∩ s4, ...., sn-1 ∩ sn]
在Java中执行此操作的最佳方法是什么?
例如,如果我只使用5套。我希望能够填充5 circle venn diagram.
的所有重叠我正在尝试使用集合列表执行此操作:
List<Set<People>> lListSets = new ArrayList<Set<People>>();
for (DaysObject day : listOfDaysInJanuary) {
lListSets.add(day.peopleOneInternet());
}
findPowerSetsAndCompare(lListSets, listOfDaysInJanuary);
我想找到一些结果:
January 1 (Bob, Sally, Tommy)
January 1, January 2 (Sally, Tommy)
...
so on for all possible combination of days.
基本上我要问的是如何将powerset algorithm与set union结合使用。
答案 0 :(得分:4)
在Java中执行此操作的最佳方法是什么?
您要描述的第一部分是powerset(因为我上周编辑了您的问题)。然后,您将获得powerset中每组集合的交集。
因为你正在做一组集合,而不是像整数这样的简单的幂集,所以实现的内容会更复杂。
额外学分
我写了一个基本的需求实现,作为如何实现它的一个例子。此示例中的所有方法和类型都是Example
类的成员。
示例类,其中只有main
方法,用于演示工作代码。我相信你会原谅我使用已弃用的Date
构造函数进行演示。
import java.text.*;
import java.util.*;
public class Example
{
public static void main(String[] args) {
// create simple test harness
Set<PeopleByDays> peepsByDay = new HashSet<PeopleByDays>();
peepsByDay.add(new PeopleByDays(new Date(2015 - 1900, Calendar.JANUARY, 1),
Person.BOB, Person.FRANK, Person.JIM, Person.JUDY, Person.SALLY));
peepsByDay.add(new PeopleByDays(new Date(2015 - 1900, Calendar.JANUARY, 2),
Person.BOB, Person.FRANK, Person.JIM, Person.JUDY, Person.TOMMY));
peepsByDay.add(new PeopleByDays(new Date(2015 - 1900, Calendar.JANUARY, 3),
Person.BOB, Person.FRANK, Person.JIM, Person.SALLY, Person.TOMMY));
peepsByDay.add(new PeopleByDays(new Date(2015 - 1900, Calendar.JANUARY, 4),
Person.BOB, Person.FRANK, Person.JUDY, Person.SALLY, Person.TOMMY));
peepsByDay.add(new PeopleByDays(new Date(2015 - 1900, Calendar.JANUARY, 5),
Person.BOB, Person.JIM, Person.JUDY, Person.SALLY, Person.TOMMY));
// make powerSet, then intersect, then sort
Set<Set<PeopleByDays>> powerPeeps = powerSet(peepsByDay);
List<PeopleByDays> powerPeepsIntersected = intersect(powerPeeps);
sort(powerPeepsIntersected);
// print out results
for (PeopleByDays peeps: powerPeepsIntersected) {
String daysFormatted = format(peeps.getDays());
System.out.print(daysFormatted);
System.out.println(peeps);
}
}
// all other Example members as defined in this answer
}
人是人名的简单enum
类型。在此处使用枚举的好处是,它会针对所需的equals()
行为执行适当的hashCode()
和HashSet
实现。
static enum Person {
BOB, FRANK, JIM, JUDY, SALLY, TOMMY;
}
PeopleByDays 扩展HashSet<Person>
以收集另外一组Date
个对象来表示日期。覆盖retainAll()
(相交)以结合日期;覆盖equals()
和hashSet()
以获取外部集合中的正确行为。
static class PeopleByDays extends HashSet<Person> {
private final Set<Date> days = new HashSet<Date>();
public PeopleByDays() {
super();
}
public PeopleByDays(Date day, Person... people) {
super(Arrays.asList(people));
this.days.add(day);
}
public PeopleByDays(PeopleByDays other) {
super(other);
this.days.addAll(other.days);
}
public List<Date> getDays() {
return new ArrayList<Date>(this.days);
}
@Override
public boolean retainAll(Collection<?> c) {
if (c instanceof PeopleByDays) {
this.days.addAll(((PeopleByDays)c).days);
}
return super.retainAll(c);
}
@Override
public boolean equals(Object o) {
return super.equals(o) && this.days.equals(((PeopleByDays) o).days);
}
@Override
public int hashCode() {
return super.hashCode() + this.days.hashCode();
}
}
powerSet()方法,从this answer逐字记录。
public static <T> Set<Set<T>> powerSet(Set<T> originalSet) {
Set<Set<T>> sets = new HashSet<Set<T>>();
if (originalSet.isEmpty()) {
sets.add(new HashSet<T>());
return sets;
}
List<T> list = new ArrayList<T>(originalSet);
T head = list.get(0);
Set<T> rest = new HashSet<T>(list.subList(1, list.size()));
for (Set<T> set: powerSet(rest)) {
Set<T> newSet = new HashSet<T>();
newSet.add(head);
newSet.addAll(set);
sets.add(newSet);
sets.add(set);
}
return sets;
}
intersect()方法为powerset中的每组设置创建交集。
static List<PeopleByDays> intersect(Set<Set<PeopleByDays>> powerSet) {
List<PeopleByDays> intersected = new ArrayList<PeopleByDays>();
for (Set<PeopleByDays> powerElement: powerSet) {
PeopleByDays intersection = null;
if (powerElement.isEmpty()) {
intersection = new PeopleByDays();
} else for (PeopleByDays peeps: powerElement) {
if (intersection == null) {
intersection = new PeopleByDays(peeps);
} else {
intersection.retainAll(peeps);
}
}
intersected.add(intersection);
}
return intersected;
}
sort()方法,按日期对生成的相交集进行排序。
static void sort(List<PeopleByDays> peeps) {
Collections.sort(peeps, new Comparator<PeopleByDays>() {
@Override
public int compare(PeopleByDays p1, PeopleByDays p2) {
List<Date> days1 = p1.getDays();
List<Date> days2 = p2.getDays();
Collections.sort(days1);
Collections.sort(days2);
for (int i = 0; i < days1.size() && i < days2.size(); i++) {
int compare = days1.get(i).compareTo(days2.get(i));
if (compare != 0) {
return compare;
}
}
return days1.size() - days2.size();
}
});
}
format()格式化每个交叉点的天数列表的方法。
static String format(List<Date> days) {
if (days.isEmpty()) {
return "";
}
StringBuilder sb = new StringBuilder();
DateFormat format = new SimpleDateFormat("MMM d");
Collections.sort(days);
String separator = "";
for (Date day: days) {
sb.append(separator);
sb.append(format.format(day));
separator = ", ";
}
sb.append(" ");
return sb.toString();
}
最后,输出。
[]
Jan 1 [BOB, JUDY, FRANK, JIM, SALLY]
Jan 1, Jan 2 [BOB, JUDY, FRANK, JIM]
Jan 1, Jan 2, Jan 3 [BOB, FRANK, JIM]
Jan 1, Jan 2, Jan 3, Jan 4 [BOB, FRANK]
Jan 1, Jan 2, Jan 3, Jan 4, Jan 5 [BOB]
Jan 1, Jan 2, Jan 3, Jan 5 [BOB, JIM]
Jan 1, Jan 2, Jan 4 [BOB, JUDY, FRANK]
Jan 1, Jan 2, Jan 4, Jan 5 [BOB, JUDY]
Jan 1, Jan 2, Jan 5 [BOB, JUDY, JIM]
Jan 1, Jan 3 [BOB, FRANK, JIM, SALLY]
Jan 1, Jan 3, Jan 4 [BOB, FRANK, SALLY]
Jan 1, Jan 3, Jan 4, Jan 5 [BOB, SALLY]
Jan 1, Jan 3, Jan 5 [BOB, JIM, SALLY]
Jan 1, Jan 4 [BOB, JUDY, FRANK, SALLY]
Jan 1, Jan 4, Jan 5 [BOB, JUDY, SALLY]
Jan 1, Jan 5 [BOB, JUDY, JIM, SALLY]
Jan 2 [BOB, JUDY, TOMMY, FRANK, JIM]
Jan 2, Jan 3 [BOB, TOMMY, FRANK, JIM]
Jan 2, Jan 3, Jan 4 [BOB, TOMMY, FRANK]
Jan 2, Jan 3, Jan 4, Jan 5 [BOB, TOMMY]
Jan 2, Jan 3, Jan 5 [BOB, TOMMY, JIM]
Jan 2, Jan 4 [BOB, JUDY, TOMMY, FRANK]
Jan 2, Jan 4, Jan 5 [BOB, JUDY, TOMMY]
Jan 2, Jan 5 [BOB, JUDY, TOMMY, JIM]
Jan 3 [BOB, TOMMY, FRANK, JIM, SALLY]
Jan 3, Jan 4 [BOB, TOMMY, FRANK, SALLY]
Jan 3, Jan 4, Jan 5 [BOB, TOMMY, SALLY]
Jan 3, Jan 5 [BOB, TOMMY, JIM, SALLY]
Jan 4 [BOB, JUDY, TOMMY, FRANK, SALLY]
Jan 4, Jan 5 [BOB, JUDY, TOMMY, SALLY]
Jan 5 [BOB, JUDY, TOMMY, JIM, SALLY]
希望有所帮助。我用它修改了比我想要的更长的时间;)但是仍然没有在输出中对Person名称进行排序。