У меня есть перечисление Tags
, содержащее полный список тегов, которые можно применять к экземплярам класса Product
. В этом классе есть переменная экземпляра tags
, которая является Set
из Strings
и содержит подмножество этих тегов. Что я пытаюсь сделать, так это найти набор тегов, которые еще не были применены к определенному продукту, и вернуть его как новый Set
с помощью метода.
Set<String> suggestedTags = new HashSet<>();
Arrays.stream(Tags.values())
.forEach(tagsList -> {
if (!this.tags.contains(tagsList.getTagName())) {
suggestedTags.add(tagsList.getTagName());
}
});
return suggestedTags;
Я протестировал приведенный выше код, и он работает так, как ожидалось. Однако я хочу добиться того же результата всего одним оператором. Что-то вроде этого:
return Arrays.stream(Tags.values())
.map(tagsList -> {
// code to find missing elements goes here
})
.collect(Collectors.toSet());
Я застрял здесь, так как не уверен, какая промежуточная операция подойдет для такой задачи. Я думал об использовании map()
и filter()
, но пока безуспешно.
Перечисление Tags
выглядит следующим образом:
public enum Tags {
BIRTHDAY("birthday"),
GRADUATION("graduation"),
GET_WELL_SOON("get well soon");
final String tagName;
private Tags(String tagName) {
this.tagName = tagName;
}
public String getTagName() {
return tagName;
}
}
Как это может быть сделано?
Вы хотите отфильтровать Tags
, которого нет в Product
, и получить имя Tags
, приведенный ниже код должен работать
return Arrays.stream(Tags.values()).filter(tag -> !this.tags.contains(tag)).map(Tags::getTagName).collect(Collectors.toSet());
@CMK, когда ваш набор содержит имена тегов, проще сначала сопоставить имена, т. Е. .map(Tags::getTagName) .filter(name -> !tags.contains(name))
, потому что тогда вы не вызываете getTagName()
дважды для каждого элемента.
Вы можете сделать что-то вроде этого:
Set<String> suggestedTags = Arrays.stream(Tags.values())
.map(Tags::getTagName)
.collect(Collectors.toCollection(HashSet::new));
suggestedTags.removeAll(tags);
но это все еще два выражения. Тем не менее, все еще намного чище, чем ваша первая версия.
Если вы переключитесь с наборов String
на EnumSet
Tags
, хотя...
EnumSet<Tags> suggestedTags = EnumSet.complementOf(tags);
// Assuming EnumSet<Tags> tags = EnumSet.of(Tags.BIRTHDAY);
// suggestedTags contains GRADUATION and GET_WELL_SOON
Это также имеет приятный побочный эффект, делая наборы намного быстрее и занимая меньше памяти.
до сих пор не знал об EnumSet. Спасибо за информацию, попробую использовать.
Intellij предупреждает меня о том, что порядок фильтра и карты должен быть изменен, вызовет ли этот порядок какие-либо заметные проблемы?