Что было бы лучшим способом сделать это на Java?
Первая часть, которую вы описываете, - это powerset (так как я отредактировал ваш вопрос, чтобы включить на прошлой неделе). Затем вы получите пересечение для каждого набора множеств в силовом наборе.
Поскольку вы выполняете набор наборов функций, а не простой силовой набор чего-то вроде целых чисел, реализация будет немного более сложной.
Extra Credit
Я написал основную реализацию ваших требований, в качестве примера того, как вы могли бы это сделать. Все методы и типы в этом примере являются членами класса 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;
}
пересекаются() метод создания пересечения для каждого набора множеств в 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;
}
сортировки() способ сортировки наборов пересекались в результате чего по дате.
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();
}
});
}
формат) метод (форматировать список дней для каждого перекрестка.
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 на выходе.
Вы пытались использовать пару простых циклов (внешний для проверки всех возможных масок, внутренних для вычисления пересечения)? – kraskevich
Кажется, что это будет очень сложно. – Whitecat
Я так не думаю. Это буквально всего два цикла, один оператор if, чтобы проверить, установлен ли бит в маске, и метод, который находит пересечение двух наборов. – kraskevich